Guides

Documents

Create documents from PDFs, add recipients and fields, send them for signature, track status and download signed PDFs.

A document is a PDF sent for electronic signature — what the website calls an agreement. You upload a PDF, say who signs it and where, send it, and download the signed copy with its certificate when everyone has signed.

Lifecycle#

StatusMeaning
document.uploadedReturned by the create call while the upload is stored. Reading the document back gives document.draft.
document.draftProcessed and ready to send.
document.sentSent; waiting for recipients.
document.viewedAt least one recipient has opened the document.
document.completedEveryone has signed. The signed PDF and certificate can be downloaded.
document.declinedA recipient declined to sign.
document.voidedThe sender cancelled the document.
document.expiredThe signing deadline passed before everyone signed.
document.errorProcessing failed after the upload was accepted (rare: unreadable files are refused at creation with 415 or 422).

Changes of status trigger the document_state_changed webhook.

Create a document#

POST/documents

Send multipart/form-data with two parts: file (the PDF) and data (a JSON string). Everything is checked straight away — an unreadable file answers 415 or 422, an unknown text-tag role or unassigned form field 400. The answer is 201 with status document.uploaded; read it back and it is a document.draft, ready to send.

curl https://macaaw.com/public/v1/documents \
  -H "Authorization: API-Key $MACAAW_API_KEY" \
  -H "Idempotency-Key: 0b6c2c2e-7f1d-4a43-9d1b-3f1e8c3f4a10" \
  -F "file=@agreement.pdf;type=application/pdf" \
  -F 'data={"name":"Service agreement","recipients":[{"email":"client@example.com","first_name":"Ana","last_name":"Silva","role":"Client","signing_order":1},{"email":"legal@example.com","first_name":"Joe","last_name":"Park","role":"Legal","type":"cc"}],"fields":[{"type":"signature","role":"Client","page":1,"x":72,"y":640,"width":180,"height":48}],"parse_text_tags":true,"subject":"Please sign the service agreement","message":"Thanks for choosing us.","expires_in_days":14,"reminders":true,"tags":["sales"],"metadata":{"crm_deal_id":"4815"}}'

The data object#

FieldTypeDescription
namestringShown to recipients and in your lists. Required.
recipientsarrayAt least one. Each: email, first_name, last_name, role (unique within the document), optional signing_order, locale (language of emails and the signing page) and type: signer (default) or cc (gets a copy, does not sign). Give any recipient a signing_order (1, 2…) and they sign in that order; without it everyone signs at the same time.
fieldsarrayFields placed by coordinates: type (signature, initials, name, date, text, checkbox), role, page (1-based), x, y, width, height in PDF points with the origin at the top-left of the page, optional required (default true for signatures, false otherwise) and name.
parse_text_tagsbooleanTurn text tags such as {signature:Client} into fields. Default true.
parse_form_fieldsbooleanTurn the PDF's own form fields into fields, assigned by a name prefix Role. (for example Client.signature). Unassigned fields are listed in a 400.
subjectstringEmail subject (can also be given when sending).
messagestringMessage shown in the email and on the signing page.
expires_in_days7 | 14 | 30Signing deadline.
remindersbooleanSend automatic reminders to recipients who have not signed.
access_codestringA code recipients must enter before they can see the document (not needed for embedded signing sessions).
tagsstring[]Your own labels; filter lists with ?tag=.
metadataobjectString keys and values for your own references. Returned in details and webhooks.
Every signer needs at least one field — from fields, text tags or form fields. A tag for a role that has no recipient is refused with 400.
201 Created
{
  "id": "58b66391-30fa-4219-a9b3-4f7badfad583",
  "uuid": "58b66391-30fa-4219-a9b3-4f7badfad583",
  "name": "Service agreement",
  "status": "document.uploaded",
  "date_created": "2026-10-30T11:35:00.342000Z",
  "date_modified": "2026-10-30T11:35:00.342000Z",
  "expiration_date": null,
  "sandbox": false
}

Check the status#

GET/documents/{id}
JSON
{
  "id": "58b66391-30fa-4219-a9b3-4f7badfad583",
  "name": "Service agreement",
  "status": "document.sent",
  "date_created": "2026-10-30T11:35:00.342000Z",
  "date_modified": "2026-10-30T11:36:12.883000Z",
  "expiration_date": "2026-11-13T11:36:12.883000Z",
  "sandbox": false
}

GET /documents/{id}/details adds recipients (each with status: waiting (not their turn yet), sent, viewed, completed or declined, plus has_completed, viewed_at, completed_at), fields, tags, metadata, the event timeline, the sender and download_available.

List documents#

GET/documents
QueryDescription
qSearch by name.
statusOne status, e.g. document.completed.
tagOnly documents with this tag.
created_fromcreated_to — ISO 8601 date range.
order_bydate_created or -date_created (newest first, the default).
pagecount — page number from 1, and page size up to 100 (default 50).

Send#

POST/documents/{id}/send

Only a document.draft can be sent (anything else is 409). Body: optional subject, message and silent. With "silent": true no emails go out — use this with embedded signing. Sending a live document counts one agreement against your monthly limit.

Remind, void and delete#

CallWhat it does
POST /documents/{id}/remindEmails a reminder to one recipient ({ "recipient_id": "…" }) or to everyone who has not signed yet. Answers { "reminded": [ids], "skipped": [{ "recipient_id", "reason" }] }; on a silent document it is 409.
PATCH /documents/{id}/status{ "status": "document.voided", "note": "…" } cancels a document.sent document; recipients are told.
DELETE /documents/{id}Deletes the document and its files now. Answers 204.

Download#

GET/documents/{id}/download

For a completed document this returns the signed PDF with the signing certificate appended; before that it returns the original PDF. Sandbox downloads are stamped on every page.

Documents · Macaaw API