API reference

E-signature API: envelopes

An envelope is a document out for signature. Sending freezes a snapshot, so later edits cannot change what anybody agreed to; when the last signer finishes, the completed PDF and its certificate of completion are ready to download. ESIGN and UETA compliant.

Base URL https://xdocs.io/api/v1, with Authorization: Bearer xdk_… on every request. Pagination, rate limits, scopes and error codes are the same for every endpoint and are described once, in how the API behaves.

Envelopes

A document out for signature. Sending freezes a snapshot, so later edits cannot change what somebody agreed to, and the completed PDF carries a certificate with the whole audit trail.

GET/api/v1/envelopesenvelopes:read

Envelopes you sent, newest first, each with its parties.

Query parameters

statusstring
sent, completed, declined, voided or expired. Anything else is a 400.
limitinteger
Rows per page, up to 100. Defaults to 50.
cursorstring
The previous page's nextCursor. Opaque — pass it back unchanged.

Returns

{ data: Envelope[], nextCursor } — id, documentId, title, kind, pageCount, subject, message, senderName, senderEmail, status, sequential, contentHash, completionHash, expiresAt, reminderEveryDays, lastReminderAt, sentAt, completedAt, voidedAt, voidReason, recipients: [{ id, name, email, role, routingOrder, status, viewedAt, signedAt, declinedAt, declineReason, notifiedAt, deliveryFailedAt, deliveryError, authMethod, authenticatedAt, delegatedToEmail, delegatedFromId }]. deliveryFailedAt is set when the signing email bounced; authMethod is email or email+access_code, and the code itself is never returned.

POST/api/v1/envelopesenvelopes:write

Send a prepared document for signature. Recipients and field placement come from the document, because that is where they are authored.

Body (JSON)

documentIdstringrequired
A draft with at least one signer, each with a name, an address and at least one field to complete — see POST /documents/:id/signature-blocks.
subjectstring
The email subject, up to 300 characters. Defaults to “Please sign: <title>”.
messagestring
A note inside the email, up to 2,000 characters.
sequentialboolean
True routes signers one after another; false sends to everybody at once.
expiresAtISO 8601 datetime
After this the envelope stops accepting signatures.
reminderEveryDaysinteger 1–30
Nudge whoever is holding it up on this cadence.

Returns

201 { data: Envelope, delivery: [{ email, delivered, reason }] } — check delivery: the envelope is real and its links work even when a notification bounced.

  • 409 That document is already out for signature — including when a concurrent send claimed it first, so a retried request cannot mail one agreement twice.
  • 404 No such document.
  • 422 Not ready to send: no signers, a recipient missing a name or address, a signer with no field to complete, a field bound to a recipient no longer on the list, unresolved suggestions in the body, a placeholder left in it (`[COMPANY NAME]`, “TBD”) or a signature line with no field — or a spreadsheet or shared file, neither of which can be signed. The message names which.
  • 402 The plan's sends for this month are used and the credit balance will not cover another. Nothing was charged; top up on the billing page or upgrade the plan.
  • 503 Billing did not answer, so nothing was sent or charged. Safe to retry.
POST/api/v1/envelopes/bulkenvelopes:write

One envelope per row of a sheet, each with its own copy of the document — the app's bulk send. The document's recipients are the slots: columns are matched to them by position, so their fields stay bound. All rows are paid for up front (the plan's included sends first, credits for the rest) and whatever was charged for a row that did not go out is refunded in one go. A row that fails does not stop the run.

Body (JSON)

documentIdstringrequired
A document with its recipient slots and their fields in place, as for POST /envelopes.
csvstringrequired
A header row, then one row per envelope, up to 250. A one-recipient document takes name,email; with more, a pair per slot in routing order headed name1,email1,name2,email2. Quoted fields are read as RFC 4180.
subjectstring
Up to 300 characters. Defaults to “Please sign: <title>”.
messagestring
Up to 2,000 characters.
sequentialboolean
Route each envelope's signers one after another.

Returns

201 { data: { sent, failed: [{ line, reason }], refunded }, maxRows } — 200 when no row went out. line is the CSV line; refunded is credits actually returned. List the envelopes for what was sent.

  • 402 The plan's sends and the credit balance will not cover the rows. Nothing was sent or charged.
  • 422 A header or row that does not match the document's slots, an address that is not one, more than 250 rows, a document with no recipients, the plan's envelope ceiling where credits are not sold — or a spreadsheet or shared file, which cannot be signed.
  • 503 Billing did not answer (nothing sent or charged), or the run stopped part way — list the envelopes before retrying.
GET/api/v1/envelopes/:idenvelopes:read

Full status, with every party and every field.

Query parameters

includestring
signingUrls adds each outstanding recipient's signing link. That link is the capability to sign, so it needs the envelopes:write scope.

Returns

{ data: Envelope & { recipients[], fields: [{ id, recipientId, type, label, required, completedAt }] } } — with signingUrls, each recipient also carries signingUrl, null for anyone who has signed, declined or passed it on

  • 403 Signing links were asked for by a key that cannot send.
POST/api/v1/envelopes/:id/remindenvelopes:write

Nudge whoever the envelope is waiting on — on a sequential envelope that is one person, not everybody unsigned.

Returns

{ data: Envelope, reminded: number }

  • 409 The envelope has ended, or nobody is currently waiting.
POST/api/v1/envelopes/:id/voidenvelopes:write

Cancel an envelope in flight. Everyone outstanding is told the reason and the document returns to draft.

Body (JSON)

reasonstringrequired
Up to 500 characters. Sent to the recipients and written to the audit trail.

Returns

{ data: Envelope }

  • 409 The envelope has already ended.
POST/api/v1/envelopes/:id/recipients/:recipientId/reassignenvelopes:write

Move a signature to somebody else. The fields follow the person, and the original stays on the envelope as delegated.

Body (JSON)

namestringrequired
emailstringrequired
reasonstring
Up to 500 characters. Recorded in the trail.

Returns

{ data: Envelope, replacementId } — replacementId is the new recipient's id

  • 409 The envelope has already ended.
  • 422 That recipient declined, has already signed, already passed it on, or the address is unchanged.
GET/api/v1/envelopes/:id/pdfenvelopes:read

The executed document with every signature and the certificate of completion.

Returns a file

The PDF bytes. For a completed envelope, the copy archived at completion rather than a fresh render.

  • 422 The PDF could not be built.
GET/api/v1/envelopes/:id/certificateenvelopes:read

The same evidence as data: signers, consent records, authentication, the audit trail and the integrity digests.

Returns

{ data: Certificate } — the digests are recomputed from the stored rows and reported as documentHashVerified / completionHashVerified, not merely echoed back.

GET/api/v1/envelopes/:id/attachmentsenvelopes:read

Files a signer returned, as metadata.

Returns

{ data: Attachment[] } — id, envelopeId, recipientId, fieldId, filename, contentType, byteSize, sha256, uploadedAt, newest first. sha256 is the digest of the bytes as received.

GET/api/v1/envelopes/:id/attachments/:attachmentIdenvelopes:read

The bytes of one returned file, streamed through rather than exposed as a storage URL.

Returns a file

The file bytes.

← The whole API referenceNext: Tracked share links API →