Developer

API Docs

Complete reference for the Mocha Signature external API — every endpoint, request field, response body, webhook payload and status code.

Overview

Base URLs, authentication and the endpoint index.

All endpoints are POST with a JSON body — including the read-only ones — and every request must carry both the X-Tenant and Api-Key headers. Operations are scoped to your own tenant account.

EnvironmentBase URL
UAThttps://services.us.uat.mochatechnologies.com/signature/api/V1
Productionhttps://services.us.mochatechnologies.com/signature/api/V1

Endpoints

GroupEndpointPurpose
Templates/get-template-by-userList the templates available to your account.
Templates/get-template-detailRead a template's recipient roles and privileges.
Envelopes/send-envelopCreate an envelope from a template and email it out for signing.
Envelopes/envelop-trackingTrack an envelope and each recipient's state.
Webhooks/webhook/deliveriesInspect the delivery log for a single webhook attempt.
Additional/get-signing-linksPer-recipient signing URLs for an envelope.
Additional/get-template-by-doc-codeList templates keyed on document_id instead of user.
Additional/insert-template-fieldCopy a template's field definitions onto an existing envelope.

Additional endpoints are not part of the published guide

The three endpoints tagged Additional exist on the external surface but are not part of the supported integration guide. They are functional but may change without notice — prefer the documented Templates, Envelopes and Webhooks endpoints.

Response shapes vary slightly

Some endpoints return status as a boolean plus a separate status_code, others return status as the numeric HTTP code. The HTTP status code is always authoritative; read data for the payload.

Get Templates By User ID

Templates — list everything available to the account.

POST/get-template-by-userX-Tenant + Api-Key required

Fetches all templates associated with the user account. Each item includes pdf_preview, a pre-signed S3 URL to the template PDF that is valid for 10 minutes — fetch it promptly or re-request the list. pdf_preview is null when the underlying object is missing from storage.

Request body

FieldTypeRequiredDescription
user_idstringRequiredThe account's user identifier.
template_typestring | nullOptionalOptional filter on the template's type, e.g. contract.
Request
{
  "user_id": "acf28c4584f007dca67b"
}

Response — 200

Returns the template list, which may be empty. See TemplateListItem in the Schema Reference.

200 OK
{
  "status_code": 200,
  "status": true,
  "message": "Template record exist.",
  "data": [
    {
      "template_id": "73766101002022",
      "user_id": "acf28c4584f007dca67b",
      "document_id": "1002022",
      "title": "Non-Disclosure Agreement",
      "description": "Standard mutual NDA",
      "total_pages": 3,
      "user_name": "Jane",
      "email": "jane@example.com",
      "job": "Legal Counsel",
      "industry": "Technology",
      "pdf_path": "acf28c4584f007dca67b/documents/73766101002022/73766101002022.pdf",
      "pdf_preview": "https://s3.amazonaws.com/...?X-Amz-Expires=600&X-Amz-Signature=..."
    }
  ]
}

Status codes

StatusMeaning
200Template list (possibly empty).
401Api-Key missing, revoked, or not owned by X-Tenant.
404Tenant not found, or the key's user has no email on record.
422Validation failed. msg names the offending fields.
500Unexpected failure. error carries the reason.
503Authentication dependency unreachable. Safe to retry.

Get Template Details

Templates — read the recipient contract before sending.

POST/get-template-detailX-Tenant + Api-Key required

Retrieves a specific template's configuration, including the recipient roles it expects. recipients_role and required_recipient define the contract for Send Envelope: you must supply exactly these roles, and exactly that many recipients.

Request body

FieldTypeRequiredDescription
template_idstringRequiredIdentifier shown in the Templates list in the web app.
Request
{
  "template_id": "73766101002022"
}

Response — 200

200 OK
{
  "status": 200,
  "message": "Template record exist.",
  "data": {
    "template_id": "73766101002022",
    "title": "Non-Disclosure Agreement",
    "discription": "Standard mutual NDA",
    "status": 1,
    "required_recipient": 2,
    "recipients_role": ["Signer 1", "Approver"]
  }
}

204 carries no body

When no template maps to the supplied template_id the API replies 204. Per HTTP semantics the body of a 204 is not transmitted — branch on the status code, not on the body.

Status codes

StatusMeaning
200Template found.
204No template maps to the supplied template_id.
401Api-Key missing, revoked, or not owned by X-Tenant.
404Tenant not found, or the key's user has no email on record.
422Validation failed. msg names the offending fields.
500Unexpected failure. error carries the reason.
503Authentication dependency unreachable. Safe to retry.

Send Envelope

Envelopes — create an envelope from a template and email it out.

POST/send-envelopX-Tenant + Api-Key required

Creates an envelope from a template and emails it to the recipients for signing. Recipients who do not yet exist as users are provisioned automatically and added to the sender's contacts.

Recipient roles must match the template exactly

Call Get Template Details first: the number of entries in recipients_role must equal required_recipient, and every role value must appear in the template's recipients_role list. A mismatch fails the request with a 500.

Request body

FieldTypeRequiredDescription
user_idstringRequiredSending account's user identifier.
company_namestringRequiredSender's company name; also used when auto-provisioning new recipients.
email_subjectstringRequiredSubject line of the signing invitation email.
messagestringRequiredBody of the invitation email. Declared optional in validation but enforced downstream — omitting it returns 422, so always send it.
template_idstringRequiredTemplate to build the envelope from.
recipients_roleRecipientRole[]RequiredOne entry per template recipient role, each with role, name and email.
metadataobject | nullOptionalFree-form object stored with the envelope and echoed back verbatim in every webhook payload. Use it to carry your own correlation ids.
file_pathstring | nullOptionalOptional override for the document to send. Accepts a base64-encoded PDF (raw, or a data:application/pdf;base64,… URI). Omit it — the normal case — to use the template's own PDF.
statusstring | nullOptionalReserved. Accepted for backwards compatibility and currently has no effect.

RecipientRole

FieldTypeRequiredDescription
rolestringRequiredMust match one of the template's recipient role titles exactly.
namestringRequiredRecipient's name. Used as the first name when provisioning a new user.
emailstring (email)RequiredRecipient's email. If no account exists for it, a user and a sender-side contact are created automatically.
Request
{
  "user_id": "acf28c4584f007dca67b",
  "company_name": "Mocha Technologies",
  "email_subject": "Please sign the Non-Disclosure Agreement",
  "message": "Kindly review and sign the attached document.",
  "template_id": "73766101002022",
  "recipients_role": [
    {
      "role": "Signer 1",
      "name": "John Doe",
      "email": "john.doe@example.com"
    },
    {
      "role": "Approver",
      "name": "Alice Smith",
      "email": "alice.smith@example.com"
    }
  ],
  "metadata": {
    "order_id": "ORD-10021",
    "source": "crm"
  }
}

Response — 200

200 OK
{
  "status": true,
  "message": "Send envelop successfully!",
  "envelope_id": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc",
  "status_code": 200
}

Persist envelope_id

It is the key for Envelope Tracking and appears in every webhook payload for this envelope.

Response — 500

Returned when processing fails: the template could not be verified, the recipient roles could not be mapped to the template's roles, or provisioning a recipient failed. error carries the reason.

500 — role mismatch
{
  "status": false,
  "message": "Something went wrong",
  "error": "Recipients role can not map with required template roles.",
  "status_code": 500
}

Status codes

StatusMeaning
200Envelope created and emailed to the recipients.
401Api-Key missing, revoked, or not owned by X-Tenant.
404Tenant not found.
422Validation failed, or a required value was missing — user_id, template_id, recipients_role, email_subject and message are all enforced at this stage.
500Processing failed. Most commonly the recipient roles did not map to the template's roles.
503Authentication dependency unreachable. Safe to retry.

Envelope Tracking

Envelopes — current state of the envelope and each recipient.

POST/envelop-trackingX-Tenant + Api-Key required

Tracks an envelope and each recipient's state. Use it to render progress in your own UI, and as the reconciliation fallback if you miss a webhook.

Mind the spelling

The request field is envelop_id (single e), while Send Envelope returns it as envelope_id. Map the value across that difference.

Request body

FieldTypeRequiredDescription
envelop_idstringRequiredThe envelope_id returned by Send Envelope.
Request
{
  "envelop_id": "23b89b780dd1ff7b6885a684483a37ef"
}

Response — 200

200 OK
{
  "status": 200,
  "message": "Envelope tracking fetched successfully.",
  "data": {
    "envelope_id": "23b89b780dd1ff7b6885a684483a37ef",
    "mail_status": "Email Sent",
    "envelope_completion_status": "Pending",
    "recipients": [
      {
        "recipient_name": "John Doe",
        "recipient_email": "john.doe@example.com",
        "status": "Completed",
        "decline_reason": null,
        "viewed_at": "2026-08-03 09:41:02",
        "completed_at": "2026-08-03 09:44:37"
      },
      {
        "recipient_name": "Alice Smith",
        "recipient_email": "alice.smith@example.com",
        "status": "Pending Signature",
        "decline_reason": null,
        "viewed_at": null,
        "completed_at": null
      }
    ]
  }
}

Status values

FieldPossible values
mail_statusEmail Sent, Email Failed
envelope_completion_statusPending, Completed, Rejected (a recipient declined), N/A
recipients[].statusPending Signature, Completed, Declined, N/A

Status codes

StatusMeaning
200Tracking data for the envelope.
401Api-Key missing, revoked, or not owned by X-Tenant.
404No envelope matches the supplied envelop_id.
422Validation failed.
500Unexpected failure.
503Authentication dependency unreachable.

Webhook Events

What Mocha Signature POSTs to your endpoint.

Configure your endpoint in the web app under Settings → Custom Webhook. Two events are delivered, both signed with HMAC-SHA256 over the raw request body. Full setup and verification instructions are in Getting Started → Webhooks.

document.completed

Delivered once every required recipient has completed the envelope. data.document.download_url is a pre-signed S3 link to the finished PDF, valid for 15 minutes — download and store the file on receipt rather than persisting the URL.

Delivery
POST https://your-endpoint.example.com/hooks/mocha-signature

X-Webhook-Event: document.completed
X-Webhook-Delivery-Id: bd142d9e-31f6-459f-b8d8-5c5cb902fbd9
X-Webhook-Timestamp: 2026-08-03T10:24:11.482000Z
X-Authorization-Digest: HMACSHA256
X-Webhook-Signature-1: <base64 HMAC-SHA256 of the raw body, secret #1>

{
  "event": "document.completed",
  "data": {
    "user_id": "acf28c4584f007dca67b",
    "envelop_id": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc",
    "status": "completed",
    "generated_at": "2026-08-03T10:24:11.000000Z",
    "metadata": {
      "order_id": "ORD-10021",
      "source": "crm"
    },
    "document": {
      "file_name": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc.pdf",
      "download_url": "https://s3.amazonaws.com/...?X-Amz-Expires=900&X-Amz-Signature=...",
      "mime_type": "application/pdf"
    }
  },
  "timestamp": "2026-08-03T10:24:11.482000Z"
}

document.declined

Delivered when a recipient declines or rejects the envelope. The signing flow stops at that point; remaining recipients are not asked to sign. Use Envelope Tracking to read which recipient declined and their decline_reason.

Payload
{
  "event": "document.declined",
  "data": {
    "user_id": "acf28c4584f007dca67b",
    "envelop_id": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc",
    "status": "declined",
    "generated_at": "2026-08-03T11:02:56.000000Z",
    "metadata": {
      "order_id": "ORD-10021"
    },
    "document": {
      "file_name": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc.pdf",
      "download_url": "https://s3.amazonaws.com/...?X-Amz-Expires=900&X-Amz-Signature=...",
      "mime_type": "application/pdf"
    }
  },
  "timestamp": "2026-08-03T11:02:56.913000Z"
}

Headers

HeaderRequiredDescription
X-Webhook-EventYesdocument.completed or document.declined.
X-Webhook-Delivery-IdYesUnique id for this delivery. Store it — it is the lookup key for Webhook Deliveries.
X-Webhook-TimestampYesISO-8601 time the delivery was sent.
X-Authorization-DigestYesSignature algorithm — always HMACSHA256.
X-Webhook-Signature-1YesBase64 HMAC-SHA256 of the raw request body, computed with your first active secret.
X-Webhook-Signature-2NoPresent when a second secret key is active. Accept the request if any supplied signature matches.

Acknowledging

  • Return any 2xx to acknowledge. Non-2xx — or a timeout past 15 seconds — marks the delivery failed and schedules a retry.
  • Delivery is retried up to 4 attempts with a 60s / 5m / 15m / 30m backoff.
  • Treat handlers as idempotent: a retry can arrive after your side has already processed the event.

Webhook Deliveries

Webhooks — the delivery log for a single attempt.

POST/webhook/deliveriesX-Tenant + Api-Key required

Returns the delivery log for a single webhook attempt — what was sent, the response your endpoint returned, how many attempts were made, and how long it took. Look it up by the X-Webhook-Delivery-Id header value received on the webhook call, so store that header when handling webhooks. Only deliveries belonging to your own tenant are visible.

Request body

FieldTypeRequiredDescription
delivery_idstring (max 100)RequiredValue of the X-Webhook-Delivery-Id header from the webhook call.
Request
{
  "delivery_id": "bd142d9e-31f6-459f-b8d8-5c5cb902fbd9"
}

Response — 200

200 OK
{
  "status": 200,
  "message": "Delivery fetched successfully",
  "data": {
    "envelop_id": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc",
    "id": 4821,
    "webhook_config_id": 17,
    "delivery_id": "bd142d9e-31f6-459f-b8d8-5c5cb902fbd9",
    "event_type": "document.completed",
    "request_payload": "{\"event\":\"document.completed\",\"data\":{...}}",
    "response_status": 200,
    "status": "success",
    "response_body": "{\"received\":true}",
    "error_message": null,
    "attempt_count": 1,
    "duration_ms": 214,
    "delivered_at": "2026-08-03 10:24:12",
    "created_at": "2026-08-03T10:24:11.000000Z",
    "updated_at": "2026-08-03T10:24:12.000000Z",
    "webhook_config": {
      "id": 17,
      "tenant_id": "acme",
      "name": "CRM completion hook",
      "url": "https://crm.example.com/hooks/mocha-signature"
    }
  }
}

request_payload is the exact signed string

Signatures are computed over that string verbatim. If your verification is failing, compare it byte-for-byte with what your handler hashed.

Status codes

StatusMeaning
200Delivery log entry.
401Api-Key missing, revoked, or not owned by X-Tenant.
404No delivery with that id exists for your tenant.
422Validation failed.
500Unexpected failure.
503Authentication dependency unreachable.

Get Templates By Document Code

Additional — the same listing keyed on document_id.

POST/get-template-by-doc-codeX-Tenant + Api-Key required

Not part of the published integration guide

This endpoint is functional but may change without notice.

Same listing as Get Templates By User ID, keyed on the template's document_id instead of the user. Returns raw template rows — no pdf_preview is generated.

Request body

FieldTypeRequiredDescription
document_codestringRequiredThe template's document_id.
Request
{
  "document_code": "1002022"
}

Status codes

StatusMeaning
200Matching templates.
401Api-Key missing, revoked, or not owned by X-Tenant.
422Validation failed.
500Unexpected failure.

Insert Envelope Template Fields

Additional — repair or extend an envelope assembled another way.

POST/insert-template-fieldX-Tenant + Api-Key required

Send Envelope already does this

Copying a template's field definitions onto an envelope is part of the Send Envelope flow. Call this only when repairing or extending an envelope that was assembled another way. Not part of the published integration guide.

Request body

FieldTypeRequiredDescription
template_idstringRequiredTemplate whose field definitions are copied.
envelop_idstringRequiredEnvelope the fields are inserted onto.
recipient_contact_idsinteger[]RequiredContact ids, in the template's recipient-role order.
Request
{
  "template_id": "73766101002022",
  "envelop_id": "b5db5fe9-8a44-4ecc-b3f4-222b14b1d5dc",
  "recipient_contact_ids": [3312, 3313]
}

Response — 201

201 Created
{
  "status": true,
  "message": "Envelope fields inserted successfully",
  "data": {
    "insertedRows": 12
  }
}

Status codes

StatusMeaning
201Fields inserted.
400Insert failed.
401Api-Key missing, revoked, or not owned by X-Tenant.
422Validation failed.
500Unexpected failure.

Schema Reference

The objects returned inside data.

TemplateListItem

FieldTypeDescription
template_idstringTemplate identifier — send this to Send Envelope.
user_idstringTemplate owner's user identifier.
document_idstringUnderlying document code.
titlestringTemplate title.
descriptionstring | nullTemplate description.
total_pagesinteger | nullPage count of the template PDF.
user_namestringTemplate owner's first name.
emailstring (email)Template owner's email.
jobstring | nullOwner's job title.
industrystring | nullOwner's industry.
pdf_pathstringStorage key of the template PDF.
pdf_previewstring | nullPre-signed URL to the template PDF, valid for 10 minutes. null when the object is not present in storage.

TemplateDetail

FieldTypeDescription
template_idstringTemplate identifier.
titlestringTemplate title.
discriptionstring | nullTemplate description. The misspelling is intentional — it is the wire field name.
statusintegerTemplate state flag.
required_recipientintegerNumber of recipients the template expects. Send Envelope requires exactly this many entries in recipients_role.
recipients_rolestring[]The recipient role titles defined on the template. Every role you send must be one of these.

EnvelopeTracking

FieldTypeDescription
envelope_idstringThe envelope being tracked.
mail_statusstringWhether the signing invitation was dispatched: Email Sent or Email Failed.
envelope_completion_statusstringOverall envelope state: Pending, Completed, Rejected or N/A. Rejected means a recipient declined.
recipientsTrackedRecipient[]Recipients in signing order.

TrackedRecipient

FieldTypeDescription
recipient_namestring | nullRecipient's name.
recipient_emailstring | nullRecipient's email.
statusstringPending Signature, Completed, Declined or N/A.
decline_reasonstring | nullThe recipient's stated reason. Non-null only when status is Declined.
viewed_atstring | nullWhen the recipient first opened the document. null if never opened.
completed_atstring | nullWhen the recipient finished their action.

WebhookEnvelope

FieldTypeDescription
eventstringdocument.completed or document.declined.
dataWebhookDocumentDataEvent payload.
timestampstring (date-time)ISO-8601 time the payload was built.

WebhookDocumentData

FieldTypeDescription
user_idstringOwner of the envelope — the sending account.
envelop_idstringMatches the envelope_id returned by Send Envelope.
statusstringcompleted or declined.
generated_atstring (date-time)When the event was generated.
metadataobject | nullThe metadata supplied on Send Envelope, returned verbatim.
document.file_namestring | nullFile name of the signed PDF.
document.download_urlstring | nullPre-signed URL to the signed PDF, valid for 15 minutes. Download the file on receipt; do not store the URL. null if the link could not be generated.
document.mime_typestringAlways application/pdf.

WebhookDelivery

FieldTypeDescription
delivery_idstring (uuid)The delivery you looked up.
envelop_idstring | nullExtracted from the delivered payload for convenience.
idintegerInternal delivery row id.
webhook_config_idintegerConfiguration this delivery belongs to.
event_typestringEvent that triggered the delivery.
request_payloadstringThe exact JSON string that was signed and sent. Signatures are computed over this.
response_statusinteger | nullHTTP status your endpoint returned. null if the request never completed.
statusstringpending, success or failed.
response_bodystring | nullBody your endpoint returned.
error_messagestring | nullTransport-level failure detail, e.g. connection timeout.
attempt_countintegerAttempts made so far — up to 4, backing off 60s / 5m / 15m / 30m.
duration_msinteger | nullRound-trip time of the attempt.
delivered_atstring | nullWhen the delivery succeeded.
webhook_configobjectid, tenant_id, name and url of the configuration.

Error Reference

Every status code the API returns, and the body that comes with it.

StatusMeaning
200Success. Read the payload from data.
201Created — Insert Envelope Template Fields only.
204No template maps to the supplied template_id. No body is transmitted.
400Insert failed — Insert Envelope Template Fields only.
401The Api-Key header is missing, revoked, or does not belong to the tenant in X-Tenant. Also returned if the platform could not issue an internal token for the key's user.
404The tenant in X-Tenant does not exist, the key's user has no email on record, or the requested envelope / delivery was not found.
422Request body failed validation. msg holds a field → messages map.
500Unexpected failure while processing the request. error carries the reason.
503A dependency needed to authenticate the request was unreachable. Safe to retry after a short backoff.

Error bodies

ShapeReturned byFields
ValidationErrorBody422status (false), msg — field name → list of messages.
ServerErrorBody500status (false), message, error, status_code.
MessageBody401, 404, 503message — e.g. Invalid API Key, Tenant 'acme' not found., Central service unavailable.

Retry policy

Retry 503 and transport failures with exponential backoff — the request was not processed. Never retry a 422; it will fail identically until the payload is fixed.