Inkless Digital Signing API v1

Introduction

The Inkless API lets your application create, send, track, and download digital signing requests. In Inkless, a send is usually called an envelope: one email template, one or more document templates, and one or more recipients moving through a signing flow.

A typical integration looks like this: fetch your templates, send an envelope, store the returned tokens, wait for completion, then download the final signed files or bundle.

Create API tokens from Admin > Company > API Details. Tokens are shown only once when created, so store them securely. If a token is lost or exposed, revoke it and issue a new one.

Tip: Tokens are company-scoped. The email_template_id, every document_template_id, and every template helper request must belong to the same company as the token you are sending with.

API Endpoints

Use the same base path for all API requests. Most endpoints accept JSON plus a bearer token. File upload endpoints use multipart/form-data instead.

https://inkless.co.uk/api

Sandbox hosts: https://sandbox.inkless.co.uk/api and https://sandbox.inkless.uk/api

Use a sandbox host when you want safe integration testing. In the current system, sandbox send-style endpoints do not behave like production sends: /api/send_link rewrites recipient email addresses to the authenticated company's contact_email and blanks recipient phone numbers, and /api/send_id_check rewrites the recipient email address to that same company contact_email.

Common routes: /api/send_link, /api/get_documents, /api/get_emails, /api/get_template_mapping, /api/preview_documents, /api/download_signed, /api/download_audit_log

Authentication

To access the API, you must include your API token in the Authorization header:

Header
Authorization: Bearer YOUR_API_TOKEN

API Token Format

The API token must follow one of these formats:

ink_live_key.secret
ink_test_key.secret
  • key is a unique identifier for the key (8-16 alphanumeric characters)
  • secret is the secret key (20+ alphanumeric characters)

Authentication Flow

When you send a request with the API token in the Authorization header, the following steps occur:

  1. The token is extracted and validated against the expected format.
  2. If the token does not match the expected format, a 401 Unauthorized error is returned.
  3. The system checks if the token is valid and not revoked. If the token is revoked or invalid, a 401 Unauthorized error is returned.
  4. The system checks if the token has expired. If the token is expired, a 401 Unauthorized error is returned.
  5. The system verifies that the provided HMAC matches the stored HMAC. If it does not match, a 401 Unauthorized error is returned.
  6. If the token is short-lived, Inkless rotates it after a successful authenticated request and returns the replacement value in X-New-Api-Token.
  7. If all checks pass, the request proceeds and the token data is returned for use in subsequent operations.

Response Codes

The following error codes may be returned during the authentication process:

Missing API token
401 Unauthorized
Invalid API token format
401 Unauthorized
Revoked API token
401 Unauthorized
Expired API token
401 Unauthorized
Invalid HMAC (token integrity check failed)
401 Unauthorized

Rate Limiting

Each API token is subject to rate limiting based on the following parameters:

  • Limit: The maximum number of requests allowed within a specified time window.
  • Window: The time period within which requests are counted.

If the rate limit is exceeded, a 429 Too Many Requests error will be returned. The rate_limit_limit and rate_limit_window values are provided as part of the token data.

Last Used IP

The IP address associated with the API token is updated each time the token is used. The system tracks this and logs the IP in case of misuse or troubleshooting.

Short-Lived Tokens

Short-lived tokens are supported across authenticated API routes. When one is used successfully, your client should immediately replace its stored token with the value returned in the X-New-Api-Token response header.

Get Balance

POST /api/get_balance

Each document sent (after being combined) will deduct from your overall balance.
For example: If 1 envelope with 2 documents priced at £0.70 is sent, it will cost £1.40. If the payload has a combine: 1 for both documents, they will be combined into one document, costing you only £0.70.

Response Codes

No credits left
402 insufficient_funds
Successful response
200 OK

Response Example

Example
                    
{
    "ok":true,
    "company_id":127,
    "balance":"£0.50",
    "as_of":"2025-10-13T15:51:23+00:00"
}
                    

Errors

If the company does not exist or the API token is invalid, a 404 Not Found error will be returned with the message "company not found".

How to Request the Balance

To retrieve the balance for a company, send a POST request to /api/get_balance with the API token in the Authorization header. The request will return the company's wallet balance and the date and time the balance was last updated.

curl -sS -X POST "https://inkless.co.uk/api/get_balance" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json"

Limitations

The endpoint currently does not allow you to directly modify your balance. It only provides the current balance associated with the authenticated company.

Get Document Templates

POST /api/get_documents

This endpoint retrieves the document templates associated with your company. It returns a list of available templates for your account. If you're working in the sandbox environment, predefined templates will be returned.

Response Codes

No templates available
404 Not Found
Successful response
200 OK

Response Example

Example
                    
{
    "ok":true,
    "documents":[
        {
        "id":1,
            "name":"template 1"
        },
        {
            "id":2,
            "name":"template 2"
        }
    ]
}
                    

How to Request Document Templates

To retrieve document templates, send a POST request to /api/get_documents with your API token in the Authorization header. If you're working in the sandbox environment, you will receive predefined templates.

curl -sS -X POST "https://inkless.co.uk/api/get_documents" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json"

Get Email Templates

POST /api/get_emails

This endpoint retrieves the email templates associated with your company. It returns a list of available email templates for your account. If you're working in the sandbox environment, predefined templates will be returned.

Response Codes

No templates available
404 Not Found
Successful response
200 OK

Response Example

Example
                    
{
    "ok":true,
    "templates":[
        {
            "id":1,
            "name":"document 1"
        },
        {
            "id":2,
            "name":"document 2"
        }
    ]
}
                    

How to Request Email Templates

To retrieve email templates, send a POST request to /api/get_emails with your API token in the Authorization header. If you're working in the sandbox environment, you will receive predefined templates.

curl -sS -X POST "https://inkless.co.uk/api/get_emails" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json"

Template Tools

These endpoints support template inspection, one-off uploads, and rendered previews before you send an envelope.

Get Template Mapping

POST /api/get_template_mapping

Returns document metadata, merge fields, merge examples, recipient count, and the saved field mappings for a template.

Request
{
  "doc_id": 125
}
curl -sS -X POST "https://inkless.co.uk/api/get_template_mapping" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "doc_id": 125
 }'
Response
{
  "ok": true,
  "document": {
    "id": 125,
    "name": "Personal Guarantee",
    "file_name": "company/documents/template-125.docx",
    "pdf_path": "company/documents/template-125.pdf",
    "version": "3",
    "mapping_version": "12",
    "merge_fields": ["first_name", "last_name"],
    "merge_examples": {
      "first_name": "Joe",
      "last_name": "Blogs"
    },
    "recipient_count": 2
  },
  "mappings": []
}

Preview Documents

POST /api/preview_documents

Builds PDF previews for one or more template documents, including overlay coordinates for mapped fields. Combined documents are returned as merged preview items.

Request
{
  "documents": [
    {
      "doc_id": 125,
      "merge_fields": {
        "first_name": "Joe",
        "last_name": "Blogs"
      },
      "combine": 1,
      "combine_key": "set-a"
    }
  ]
}
curl -sS -X POST "https://inkless.co.uk/api/preview_documents" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "documents": [
     {
       "doc_id": 125,
       "merge_fields": {
         "first_name": "Joe",
         "last_name": "Blogs"
       },
       "combine": 1,
       "combine_key": "set-a"
     }
   ]
 }'
Response
{
  "ok": true,
  "items": [
    {
      "name": "Combined Document",
      "page_count": 4,
      "pdf_base64": "BASE64_ENCODED_PDF",
      "overlays": {
        "1": [
          {
            "x": 10,
            "y": 20,
            "w": 25,
            "h": 8,
            "type": "signature",
            "source": "recipient_1_signature",
            "label": "recipient_1_signature"
          }
        ]
      }
    }
  ]
}

Utilities

These helper endpoints expose company send settings, recipient counts, and wallet pricing checks used by the current send flow.

Get Company Settings

POST /api/get_company_settings

Returns the default send behaviour for the authenticated company.

curl -sS -X POST "https://inkless.co.uk/api/get_company_settings" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json"
Response
{
  "ok": true,
  "email_reminders": 1,
  "email_completed_pdf": 0,
  "enforce_signing_order": 1
}

Wallet Precheck

POST /api/wallet_precheck

Calculates the projected cost of a send before submission, including document groups, SMS usage, and identity verification charges.

Request
{
  "doc_groups": 2,
  "sms_otp_recips": 1,
  "sms_link_recips": 1,
  "identity_verification_recips": 0
}
curl -sS -X POST "https://inkless.co.uk/api/wallet_precheck" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "doc_groups": 2,
   "sms_otp_recips": 1,
   "sms_link_recips": 1,
   "identity_verification_recips": 0
 }'
Response
{
  "ok": true,
  "needed_p": 80,
  "have_p": 930,
  "short_p": 0,
  "after_p": 850,
  "needed": "£0.80",
  "have": "£9.30",
  "short": "£0.00",
  "after": "£8.50",
  "doc_groups": 2,
  "sms_otp_recips": 1,
  "sms_link_recips": 1,
  "identity_verification_recips": 0,
  "doc_p": "£0.70",
  "otp_p": "£0.05",
  "link_p": "£0.05",
  "identity_verification_p": "£0.00",
  "per_doc": "£0.70",
  "per_sms": "£0.05",
  "per_identity_verification": "£1.00",
  "note": "Doc cost capped at £1.50 for 1-5 docs."
}

Recipient Count

POST /api/recipient_count

Returns the configured recipient count for a document template.

Request
{
  "doc_id": 125
}
curl -sS -X POST "https://inkless.co.uk/api/recipient_count" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "doc_id": 125
 }'
Response
{
  "ok": true,
  "recipient_count": 2
}

End-to-End Example

This example shows the simplest production flow to build first: send an envelope, store the returned identifiers, wait for completion, then download the final bundle.

1. Send The Envelope

Before you call /api/send_link, make sure you already know which template IDs and recipients you want to use. At minimum, you need:

  • A valid API token in the Authorization header.
  • An email_template_id that belongs to the same company as the token.
  • At least one document_template_id in documents.
  • At least one recipient, either envelope-level or legacy per-document recipients.
  • Any merge fields your template expects.
Send request
{
  "email_template_id": 21,
  "client_reference_id": "INV-10042",
  "email_reminders": true,
  "email_completed_pdf": false,
  "enforce_routing_order": true,
  "recipients": [
    {
      "recipient_number": 1,
      "routing_order": 1,
      "name": "Joe Blogs",
      "email": "joe@example.com",
      "phone": "447700900123",
      "send_otp_sms": false,
      "send_link_sms": false
    }
  ],
  "documents": [
    {
      "document_template_id": 125,
      "recipient_numbers": [1],
      "merge": {
        "first_name": "Joe",
        "invoice_number": "INV-10042"
      }
    }
  ]
}

2. Store These Fields From The Response

Do not treat the send response as disposable. After a successful /api/send_link call, store the identifiers you will need later:

  • client_reference_id or your own foreign key, so you can map Inkless back to your record.
  • envelope_token, which you need later for /api/get_envelope_status and /api/download_envelope_archive.
  • Each document document_token, which you need later for /api/download_signed, /api/download_archive, and /api/download_audit_log.
  • Optionally each recipient secure_link_id if you want recipient-level tracking or resend operations.
Example response to persist
{
  "ok": true,
  "envelope_id": 1234,
  "envelope_token": "abcdef1234567890",
  "documents": [
    {
      "document_template_id": 125,
      "document_token": "94c82c53c6fef99e6b35cda0e9bf1f420cf1d7a5c71c0acdac02c556dcbbcbef"
    }
  ],
  "secure_links": [
    {
      "recipient_number": 1,
      "secure_link_id": 271,
      "recipient_email": "joe@example.com",
      "verify_url": "https://sign.inkless.co.uk/verify/recipient-token-1"
    }
  ],
  "client_reference_id": "INV-10042"
}
Suggested local record
{
  "your_record_id": "INV-10042",
  "client_reference_id": "INV-10042",
  "envelope_token": "abcdef1234567890",
  "documents": [
    {
      "document_template_id": 125,
      "document_token": "94c82c53c6fef99e6b35cda0e9bf1f420cf1d7a5c71c0acdac02c556dcbbcbef"
    }
  ],
  "recipients": [
    {
      "recipient_number": 1,
      "secure_link_id": 271
    }
  ]
}

3. Wait For Completion Webhooks

Inkless can notify your webhook as the envelope progresses. For most integrations, the key event is envelope_complete, because that is the point where you can safely fetch the final envelope bundle.

Example completion webhook
{
  "event": "envelope_complete",
  "company_id": 1,
  "envelope_id": 1234,
  "envelope_token": "abcdef1234567890",
  "timestamp": "2026-07-24T14:10:00Z"
}

In your webhook handler, match envelope_token back to the record you stored after /api/send_link, then trigger your download step from there.

4. Download The Final Bundle

Use the stored envelope_token to download the completed envelope ZIP from /api/download_envelope_archive. For most integrations, this is the simplest single result to store in your own system.

curl -sS -X POST "https://inkless.co.uk/api/download_envelope_archive" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"envelope_token":"abcdef1234567890"}'

5. Optional Per-Document Downloads

If you also stored the per-document document_token values, you can fetch individual outputs instead of, or as well as, the full envelope bundle:

  • /api/download_signed for the signed PDF.
  • /api/download_archive for the per-document court bundle ZIP.
  • /api/download_audit_log for the audit log file.

Send ID Check Link

POST /api/send_id_check

This endpoint creates a verification-only envelope, charges one ID verification credit, queues the verification email, and returns the created envelope and secure link details.

Use this when you want to send a standalone identity check without attaching any documents.

Sandbox behaviour: when this endpoint is called on https://sandbox.inkless.co.uk, Inkless rewrites the recipient email address to the authenticated company's contact_email before sending.

curl -sS -X POST "https://inkless.co.uk/api/send_id_check" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Jane Example",
   "email": "jane@example.com",
   "phone": "447700900123",
   "client_reference_id": "IDCHK-1001"
 }'

Request Body

FieldTypeRequiredNotes
namestringYesRecipient name.
emailstringYesRecipient email address.
phonestringYesRecipient phone number.
client_reference_idstringNoOptional reference stored against the secure link.
allow_embedbooleanNoWhen true, the returned embed_link is allowed to load inside a third-party iframe, but only from origins whitelisted in Company Settings.

Success Response

200 OK
{
  "ok": true,
  "status": "queued",
  "message": "ID verification link queued successfully.",
  "envelope_id": 1281,
  "envelope_token": "0f4f7f8c5a0b4c2f9d68c2d4e65f99a0",
  "secure_link_id": 2195,
  "recipient_name": "Jane Example",
  "recipient_email": "jane@example.com",
  "expires_at": "2026-06-30 13:45:00",
  "verify_url": "https://sign.inkless.co.uk/verify/...",
  "embed_link": "https://sign.inkless.co.uk/verify/...?embed=1",
  "spent": "£1.00",
  "remaining": "£145.95",
  "client_reference_id": "IDCHK-1001"
}

Follow-up Events

Verification-only sends use the same queued notification pipeline as standard sends.

  • When the email is queued and sent, Inkless emits the identity_verification_link_sent company webhook event.
  • Once the recipient completes the ID check, use /api/download_envelope_archive with the returned envelope_token to fetch the verification evidence bundle.
Webhook example
{
  "event": "identity_verification_link_sent",
  "company_id": 1,
  "envelope_id": 1281,
  "envelope_token": "0f4f7f8c5a0b4c2f9d68c2d4e65f99a0",
  "secure_link_id": 2195,
  "channel": "email",
  "recipient": {
    "name": "Jane Example",
    "email": "j***@e*****.com",
    "phone": ""
  },
  "verify_url": "https://sign.inkless.co.uk/verify/...",
  "embed_link": "https://sign.inkless.co.uk/verify/...?embed=1",
  "timestamp": "2026-06-25T14:10:00Z"
}

Errors

HTTPerrorMeaning
401unauthorizedAPI token missing or invalid.
402insufficient_fundsNot enough balance to send the ID check.
402identity_verification_debit_failedThe ID verification charge could not be applied.
422validation_errorRequired fields were missing or invalid.
500envelope_create_failedThe envelope could not be created.
500secure_link_create_failedThe secure link could not be created.
500notification_queue_failedThe verification email could not be queued.

Download Signed Document

POST /api/download_signed

Returns the signed PDF for a document token as base64 JSON.

Authentication uses the Authorization: Bearer ... header. The request body must be JSON. Short-lived bearer tokens are supported and may return a replacement token in X-New-Api-Token.

Request Payload

JSON
{
  "document_token": "your_document_token"
}

Successful Response

200 OK
{
  "ok": true,
  "file": {
    "filename": "personal-guarantee-signed.pdf",
    "mime": "application/pdf",
    "size": 350170,
    "sha256": "2a4bd9a8d0a2b8eda8b076cb1db9e94b777dc6e7c1c653032c70f0568e296165",
    "content_base64": "BASE64_ENCODED_CONTENT"
  }
}
curl -sS -X POST "https://inkless.co.uk/api/download_signed" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"document_token":"your_document_token"}'

Error Responses

HTTPErrorMeaning
404not_foundThe document token does not exist for the authenticated company.
409not_signedThe document exists but is not signed yet.
404signed_file_not_foundThe document record exists but the signed PDF could not be found in storage.
500read_failedThe signed file could not be read after retrieval.
401auth errorsBearer token is missing, expired, revoked, or invalid.

Download Document Archive

POST /api/download_archive

Builds and returns the court bundle ZIP for a single document token as base64 JSON.

Authentication uses the Authorization: Bearer ... header. The request body must be JSON. Short-lived bearer tokens are supported and may return a replacement token in X-New-Api-Token.

Request Payload

JSON
{
  "document_token": "your_document_token"
}

Successful Response

200 OK
{
  "ok": true,
  "file": {
    "filename": "court-bundle-94c82c53.zip",
    "mime": "application/zip",
    "size": 1213940,
    "sha256": "b52c96bebe60885f34063ef5706c340e052614ef29deffff1a6b5af2c0dd5e69",
    "content_base64": "BASE64_ENCODED_CONTENT"
  }
}
curl -sS -X POST "https://inkless.co.uk/api/download_archive" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"document_token":"your_document_token"}'

Error Responses

HTTPErrorMeaning
400server_errorThe bundle could not be built or the token was invalid for this company.
400server_error + messageThe response includes a user-friendly message when bundle generation fails.
500read_failedThe built ZIP could not be read before encoding.
401auth errorsBearer token is missing, expired, revoked, or invalid.

Download Audit Log

POST /api/download_audit_log

Returns the audit log for a single document token as base64 JSON.

Authentication uses the Authorization: Bearer ... header. The request body must be JSON. Short-lived bearer tokens are supported and may return a replacement token in X-New-Api-Token.

Request Payload

JSON
{
  "document_token": "your_document_token"
}

Successful Response

200 OK
{
  "ok": true,
  "file": {
    "filename": "your_document_token.ndjson",
    "mime": "application/x-ndjson",
    "size": 12458,
    "sha256": "2a4bd9a8d0a2b8eda8b076cb1db9e94b777dc6e7c1c653032c70f0568e296165",
    "content_base64": "BASE64_ENCODED_CONTENT"
  }
}

The audit file type depends on what is stored for that document. Common values are .ndjson, .jsonl, .json, .log, or .txt.

curl -sS -X POST "https://inkless.co.uk/api/download_audit_log" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"document_token":"your_document_token"}'

Error Responses

HTTPErrorMeaning
404not_foundThe document token does not exist for the authenticated company.
404audit_log_not_foundThe document exists but no audit log file could be found in storage.
500read_failedThe audit log file could not be read after retrieval.
401auth errorsBearer token is missing, expired, revoked, or invalid.

Download Envelope Archive

POST /api/download_envelope_archive

Builds and returns the envelope bundle ZIP as base64 JSON.

Authentication uses the Authorization: Bearer ... header. The request body must be JSON. Short-lived bearer tokens are supported and may return a replacement token in X-New-Api-Token.

Request Payload

JSON
{
  "envelope_token": "your_envelope_token"
}

Successful Response

200 OK
{
  "ok": true,
  "file": {
    "filename": "envelope_94c82c53c6fe.zip",
    "mime": "application/zip",
    "size": 1536000,
    "sha256": "3b6c5d9a3b5c9e89fabae0234567890abcdef1234567890abcdef1234567890",
    "content_base64": "BASE64_ENCODED_CONTENT"
  },
  "included": [
    {
      "document_token": "94c82c53c6fef99e6b35cda0e9bf1f420cf1d7a5c71c0acdac02c556dcbbcbef",
      "document_name": "Personal Guarantee",
      "inner_file": "01-personal-guarantee.zip",
      "size": 1213940,
      "sha256": "b52c96bebe60885f34063ef5706c340e052614ef29deffff1a6b5af2c0dd5e69"
    }
  ],
  "skipped": []
}
curl -sS -X POST "https://inkless.co.uk/api/download_envelope_archive" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"envelope_token":"your_envelope_token"}'

Error Responses

HTTPErrorMeaning
400missing_company_or_envelope_tokenThe company context or envelope token was missing.
500read_failedThe built envelope ZIP could not be read before encoding.
409no_complete_documentsNo complete documents were available to include in the envelope bundle.
400Envelope not found or other thrown messageThe envelope was invalid or bundle generation failed before reading.
401auth errorsBearer token is missing, expired, revoked, or invalid.

Get Envelope Status

POST /api/get_envelope_status

Returns a single envelope record with its documents and recipients for one envelope token.

Authentication uses the Authorization: Bearer ... header. The request body must be JSON. Short-lived bearer tokens are supported and may return a replacement token in X-New-Api-Token.

Request Payload

JSON
{
  "envelope_token": "your_envelope_token"
}

Successful Response

200 OK
{
  "ok": true,
  "envelope": {
    "id": 1234,
    "token": "abcdef1234567890",
    "status": "completed",
    "created_at": "2026-03-11 12:00:00",
    "total_documents": 1,
    "total_recipients": 2
  },
  "documents": [
    {
      "document_token": "94c82c53c6fef99e6b35cda0e9bf1f420cf1d7a5c71c0acdac02c556dcbbcbef",
      "document_name": "Personal Guarantee",
      "pending": 0,
      "complete": true,
      "can_replace": false
    }
  ],
  "recipients": [
    {
      "name": "Joe Blogs",
      "email": "joe@example.com",
      "phone_number": null,
      "used": 1,
      "expires_at": "2026-03-14 12:00:00",
      "access_link_date_time": "2026-03-11 12:05:00",
      "status": "signed",
      "status_label": "Signed"
    },
    {
      "name": "Manager",
      "email": "manager@example.com",
      "phone_number": null,
      "used": 1,
      "expires_at": "2026-03-14 12:00:00",
      "access_link_date_time": "2026-03-11 12:07:00",
      "status": "signed",
      "status_label": "Signed"
    }
  ]
}
curl -sS -X POST "https://inkless.co.uk/api/get_envelope_status" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"envelope_token":"your_envelope_token"}'

Error Responses

HTTPErrorMeaning
400missing_company_or_envelope_tokenThe company context or envelope token was missing.
404envelope_not_foundThe envelope token does not exist for the authenticated company.
500server_errorStatus lookup failed unexpectedly.
401auth errorsBearer token is missing, expired, revoked, or invalid.

Error Handling

When a request fails, Inkless returns a non-2xx HTTP status and a JSON body with ok: false and an error key. Your client should check both the HTTP status and the JSON body.

Some failures include extra detail. Validation failures may include an errors array, and some server-side failures also include a human-readable message.

Validation Example
{
  "ok": false,
  "error": "validation_error",
  "errors": [
    "email_template_is_required",
    "documents[0].document_template_id_is_required"
  ]
}
Server Example
{
  "ok": false,
  "error": "server_error",
  "message": "Server error. Please try again."
}

Common API Errors

HTTPErrorMeaning
401auth errorsThe bearer token is missing, expired, revoked, malformed, or invalid.
422validation_errorThe request body was understood, but one or more fields failed validation. Check the errors array for the fields to fix.
400missing_company_or_envelope_tokenA required envelope_token was missing, or the authenticated token had no usable company context.
404envelope_not_foundThe envelope token does not exist for the authenticated company.
404not_foundThe document token does not exist for the authenticated company.
409not_signedThe document exists but has not been fully signed yet.
404signed_file_not_foundThe document exists, but the signed PDF could not be found in storage.
400Company contact email not foundThe company is missing required send configuration.
404email_template_not_found_for_this_company <id>The email template does not belong to the authenticated company.
400no_documents_to_sendNo valid document outputs were created after request planning.
402insufficient_fundsThe company wallet balance is too low for the requested send.
402document_debit_failedCost calculation succeeded, but the wallet debit failed when Inkless tried to charge the send.
500document_planning_failedInkless could not finish document preparation or recipient grouping.
500envelope_create_failedThe envelope record could not be created.
500secure_link_create_failedOne or more secure links could not be created.
500read_failedA generated file or bundle could not be read before Inkless encoded the response.
400server_errorA general server-side failure occurred. Some endpoints also include a human-readable message.
409no_complete_documentsNo completed documents were available to include in an envelope bundle.

Company Webhooks

Inkless can POST JSON to your company webhook URL when subscribed events occur. Webhook deliveries are queued and sent asynchronously.

Available Events

Event When It Fires
otp_sentAn OTP is sent for a signing session.
otp_verifiedAn OTP is successfully verified.
document_signing_link_sentA recipient is sent a signing link for the envelope.
identity_verification_link_sentA verification-only ID check link is sent to a recipient.
link_viewedA signing link is opened.
link_resentA signing link is resent to a recipient.
document_signedA recipient signs a document.
document_completeThe document has finished processing and the archive is ready.
envelope_completeAll documents in the envelope have completed processing.
sms_sentAn SMS message is accepted/submitted by the SMS provider.
sms_deliveredAn SMS message is reported as delivered.
sms_failedAn SMS message fails.
email_deliveredAn email is reported as delivered.
email_openedAn email is opened.
email_clickedAn email link is clicked.
email_bouncedAn email bounces.
email_rejectedAn email is rejected.

Example Payload

Example
{
  "event": "document_signed",
  "secure_link_id": 271,
  "document_token": "a1b2c3d4...",
  "timestamp": "2026-03-11T23:25:31Z"
}

Webhook Verification

When you create or update a webhook, Inkless verifies the endpoint by POSTing a JSON payload containing a verification_secret. Your endpoint must respond with that exact token as plain text and HTTP 200.

Verification request
{
  "verification_secret": "abc123...",
  "provider": "inkless",
  "webhook_id": 42,
  "timestamp": "2026-03-11T23:25:31Z"
}

Signing

Webhook requests are signed with HMAC-SHA256 so your endpoint can verify that the request genuinely came from Inkless and that the request body was not altered in transit.

The webhook secret itself is not sent in the request. Inkless stores the secret when you configure the webhook, computes a signature from the exact raw request body, and sends only the derived signature in the headers.

Header Description
X-Inkless-SignatureBase64-encoded HMAC-SHA256 signature of the raw request body, computed using your webhook secret.
X-Inkless-AlgSignature algorithm identifier. Currently always SHA256.

Your endpoint should recompute the HMAC using the exact raw request body and your stored secret, then compare it to X-Inkless-Signature. If they match, the webhook is authentic. If they do not match, reject the request.

Quick Verification Examples

Use the exact raw request body bytes, not a re-serialized JSON object. Compute HMAC-SHA256, base64-encode it, then compare it to X-Inkless-Signature.

# BODY_FILE contains the exact raw request body
# HEADER_SIG is the X-Inkless-Signature header value
# SECRET is your webhook secret

computed=$(openssl dgst -sha256 -hmac "$SECRET" -binary BODY_FILE | openssl base64 -A)

if [ "$computed" = "$HEADER_SIG" ]; then
  echo "valid"
else
  echo "invalid"
fi

Configure company webhooks in Company Settings. Use HTTPS endpoints only.

Changelog

  • 2026-07-24 Updated the developer API docs to match the current router and controller, added coverage for template tools and utility endpoints, documented short-lived token rotation, and removed duplicated sections.
  • 2026-06-25 Added public docs for send_id_check, resend_envelope_links, and download_envelope_archive.