E-signature API pricing and credits
The API has no plan or monthly fee of its own. It uses the same pay-per-document credits as the SignWith dashboard, and your code can check the balance and buy more.
When a credit is used
One credit covers one signed document, however many people sign it. Credits are used when a document is signed, not when it's sent.
In the API, a document is a template:
- A template uses one credit the first time it's signed.
- Sending the same template again, to anyone, doesn't use another credit.
- Lifetime plans never run out: their balance shows
unlimited: true. - The balance may go slightly below zero, down to
overdraft_limit, before sending is blocked.
Every account gets 3 free documents a month, and credit packs are one-time purchases with no subscription. Current packs and prices are on the pricing page.
Check the balance
GET /credits returns the balance and can_send, which says whether a request that needs a new credit can go out right now. Check it before sending in bulk, so you can ask for a top-up instead of hitting an error halfway.
curl https://app.signwith.co/api/v1/credits \
-H "Authorization: Bearer $SIGNWITH_API_KEY"const response = await fetch('https://app.signwith.co/api/v1/credits', {
headers: {
Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
},
})
console.log(response.status, await response.json())import os
import requests
response = requests.get(
"https://app.signwith.co/api/v1/credits",
headers={
"Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
},
)
print(response.status_code, response.json())When credits run out
When the account can't cover a new document, POST /signature_requests returns:
{
"error": {
"code": "insufficient_credits",
"message": "Not enough credits to send this document. List credit packs with GET /api/v1/credit_packs and buy one with POST /api/v1/checkouts."
}
}
The status is 402. Nothing was sent. Show the user the purchase_url from GET /credits to buy credits in SignWith, or buy them from the API as below.
Buy credits from the API
An API client or AI agent can top up without leaving your product. Payment always happens on a hosted page: the API never handles card details.
- List the packs on sale with
GET /credit_packsand let the user choose one. - Start a checkout with
POST /checkouts, passingcredit_pack_idand, optionally, adiscount_code. Send anIdempotency-Keyso a retry doesn't start a second payment. - Send the user to the returned
checkout_urlto pay. - Poll
GET /checkouts/{id}every few seconds, then less often, untilstatusiscompleted(credits added) orfailed. - Retry the request that failed. If you sent it with an
Idempotency-Key, reuse the same key and body: failed responses aren't stored, so the retry runs normally.
curl -X POST https://app.signwith.co/api/v1/checkouts \
-H "Authorization: Bearer $SIGNWITH_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"credit_pack_id": 4
}'const response = await fetch('https://app.signwith.co/api/v1/checkouts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
credit_pack_id: 4,
}),
})
console.log(response.status, await response.json())import os
import uuid
import requests
response = requests.post(
"https://app.signwith.co/api/v1/checkouts",
headers={
"Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"credit_pack_id": 4,
},
)
print(response.status_code, response.json())Use the pack IDs that GET /credit_packs returns, rather than hard-coding them.
Checkouts need a full-access key and a billing country on the user's SignWith profile; without one the API returns 422 billing_details_required. Buying the lifetime deal twice returns 422 already_purchased. If the payment provider can't start the payment, the API returns 502 payment_provider_error and nothing is charged.
Start building
The API and MCP server come with every account. 3 free documents a month, then pay per document.