Documents API reference
Check signed PDFs.
Verify a signed PDF
/api/v1/documents/verify- Read-only keys can call this
- Accepts Idempotency-Key
Checks a PDF: whether SignWith issued it (it matches a document completed in SignWith) and
whether each embedded digital signature is valid and the document hasn't been modified since.
Use it when a signed document comes back to you from a third party and you need to confirm
it's authentic. Send the PDF as base64 in a JSON file property, or upload it as a
multipart file.
This call doesn't change anything, so read-only API keys may use it. Returns
422 invalid_document if file isn't a PDF.
Headers
Idempotency-KeystringA unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.
at most 255 characters
Request bodyJSON or multipart/form-data
filestringRequiredThe PDF, base64-encoded.
base64
As multipart/form-data, send the same text fields plus the files:
Request sample
curl -X POST https://app.signwith.co/api/v1/documents/verify \
-H "Authorization: Bearer $SIGNWITH_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"file": "JVBERi0xLjcKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoK..."
}'const response = await fetch('https://app.signwith.co/api/v1/documents/verify', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
file: 'JVBERi0xLjcKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoK...',
}),
})
console.log(response.status, await response.json())import os
import uuid
import requests
response = requests.post(
"https://app.signwith.co/api/v1/documents/verify",
headers={
"Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"file": "JVBERi0xLjcKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoK...",
},
)
print(response.status_code, response.json())Response 200
The verification result. Returns a document verification object.
Example response: see the example object below.
Errors
| 400 | The request body is not valid JSON. (invalid_json) |
| 401 | The API key is missing, invalid or expired, or its account has been archived. (unauthenticated, api_key_expired) |
| 409 | A request with the same Idempotency-Key is still being processed. Retry shortly. (idempotency_key_in_use) |
| 422 | The request is valid JSON but can't be processed. See error.code; the codes each endpoint
can return are described in the endpoint's description and in the error table above. (missing_parameter, invalid_parameter, invalid_request, missing_documents, too_many_documents, document_too_large, invalid_document, invalid_file_type, pdf_encrypted, missing_signers, invalid_signer, already_completed, not_open, nothing_to_remind, invalid_field, template_has_no_fields, template_archived, signer_finished, idempotency_key_reused, invalid_discount_code, already_purchased, billing_details_required) |
| 429 | Rate limit exceeded (rate_limited, with Retry-After); more than 20 POST /feedback
messages in an hour (rate_limited, with Retry-After: seconds until the next clock hour); or — for
POST /signature_requests/{id}/remind — signers were reminded less than an hour ago
(remind_too_soon, with Retry-After). (rate_limited, remind_too_soon) |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same Idempotency-Key. (internal_error) |
Codes listed are the examples the spec gives; see all error codes.
The document verification object
objectstringRequiredAlwaysdocument_verificationissued_by_signwithbooleanRequiredWhether this exact file is a document completed in SignWith.
signaturesarray of objectsRequiredEvery digital signature found in the PDF. Empty if the PDF isn't digitally signed.
5 child fields
signer_namestring or nullRequiredsigned_atstring (date-time) or nullRequiredreasonstring or nullRequiredvalidbooleanRequiredtrueif verification produced no errors.messagesarray of objectsRequiredDetails from verifying the signature and certificate chain.
2 child fields
typestringRequiredOne ofinfo,warning,errorcontentstringRequired
{
"object": "document_verification",
"issued_by_signwith": true,
"signatures": [
{
"signer_name": "SignWith",
"signed_at": "2026-09-27T10:15:02Z",
"reason": "Signed by Grace Hopper, Ada Lovelace",
"valid": true,
"messages": [
{
"type": "info",
"content": "Signature valid"
},
{
"type": "info",
"content": "Certificate is trusted"
}
]
}
]
}Base URL, pagination and idempotency work the same on every endpoint: see making requests. Every error code is on errors.
Start building
The API and MCP server come with every account. 3 free documents a month, then pay per document.