Inkless Digital Signing API v1

Introduction

The Inkless API lets you programmatically create and send signing links (“envelopes”) based on your email templates and document templates, with signing order, merge fields, auditing, and expiry. To get started you must create an API Token, to do this you can browse to Admin -> Company then click on the API Details Tab, Once their type a description in the input box and click "Create Token". Copy the token and store it in a secure place as this will not be shown again and will require you to revoke the token and create a new one if lost.

Tip: Tokens are company-scoped. The email_template_id and all document_template_id values must belong to the same company as the token.

API Endpoints

Use the same base path for all API requests. Each action is called by posting to its route under /api.

https://dev.inkless.co.uk/api

Example routes: /api/send_link, /api/get_documents, /api/get_emails, /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 the format:

ink_live_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 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.

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://dev.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://dev.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://dev.inkless.co.uk/api/get_emails" \
 -H "Authorization: Bearer YOUR_API_TOKEN" \
 -H "Content-Type: application/json"

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://dev.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://dev.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://dev.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://dev.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://dev.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

We return 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 response body.

Validation failures may also include an errors array, and some server-side failures include a user-facing 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 errorsBearer token is missing, expired, revoked, malformed, or invalid.
422validation_errorThe request body failed validation. Inspect the errors array for field-specific failures.
400missing_company_or_envelope_tokenThe request did not include a required envelope_token or the authenticated token had no 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 foundCompany configuration is incomplete for sending.
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 planning.
402insufficient_fundsWallet balance is too low for the requested send.
402document_debit_failedDocument billing failed after planning completed.
500document_planning_failedDocument preparation or recipient grouping failed.
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 encoding.
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.
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

  • 2025-09-04 — Added docs for get_credits, list_email_templates, list_document_templates, and get_artifact. Kept layout, added PHP/Python examples, generic tab & copy handling.
  • 2025-09-04 — Initial docs for send_link. Credits check & debit, ownership checks, audit logging, first-batch mailing.