Skip to content
Developers · API reference

Reference for theAPI Full

A precise technical reference for every endpoint and object in the Wthaiq API: authentication, errors, pagination, Idempotency, rate limits, signature requests, signers, documents, templates, identity verification, verification, events and Webhooks. Ready examples in cURL and Node for every call.

BASE URL https://wthaiq.com/api/v1
Version 2026-07-01 Authentication Bearer sk_... Response application/json
create-signature-request.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3c9c2e-..." \
  -d '{
    "title": "Employment Contract — Ahmed M.",
    "source": { "type": "template", "template_id": "tpl_employment" },
    "legal_level": "aes",
    "ordered": true,
    "signers": [
      { "name": "Ahmed Mohamed", "email": "ahmed@example.com",
        "method": "draw", "require_identity": true }
    ]
  }'

Overview

The Wthaiq API is a REST API organized around resources; it uses predictable HTTP paths, encodes errors with standard HTTP codes, and sends and receives payloads of application/json (except for file uploads, which use multipart/form-data). All requests go over HTTPS only.

Timestamps are integers in Unix epoch seconds. Every resource carries a unique ID prefixed with its type, which makes tracing objects in logs straightforward:

PrefixResourceExample
sr_signature_requestsr_3n8Kd2Qa1V
sgr_signersgr_9fA2
doc_documentdoc_7Yq
tpl_templatetpl_employment
idv_identity_verificationidv_5k
evt_eventevt_2M
we_webhook_endpointwe_1a
key_api_keykey_88
Base URL: All paths are relative to https://wthaiq.com/api/v1. The version is pinned by date through the header Wthaiq-Version, and the changes are dated in Changelog.
Node examples: The Node examples on this page use the official wthaiq library; its install command and the other libraries' examples are on the official libraries page.

Authentication

Requests are authenticated with a secret key in the header Authorization using the HTTP Bearer scheme. Your keys carry full privileges; keep them on the server only, and never place them in client-side code, public repositories or mobile applications.

KeyThe formatDescription
The secret keysk_...Full permissions, for server-side use only. A live key sends real messages, issues legal certificates and its sends are billed, while a test key sk_test_ does none of that. See the section “Test keys and live keys”.
The publishable keypk_...Safe to expose in the browser, locked to your domains, and limited to a fixed set of paths.
The Webhook secretwhsec_...Used to verify the signature of Webhook messages (HMAC-SHA256).
auth.sh
curl https://wthaiq.com/api/v1/signature_requests \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Security warning: Any request without a valid key is rejected with status 401 and an error type authentication_error. Manage your keys and delete any leaked key from the developer console immediately.

Versioning

The version is pinned by date. Send the header Wthaiq-Version with the date of the version you built your integration against, so API behavior stays fixed even if we ship later changes. If you omit the header, the latest version pinned to your account is used.

version.sh
curl https://wthaiq.com/api/v1/templates \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Every breaking change ships under a new date and is documented in Changelog. Non-breaking additions (new fields, new enum values) may appear without a change of date, so design your client to tolerate unexpected fields.

Errors

Wthaiq uses conventional HTTP response codes: the range 2xx success, and the range 4xx indicates an error in the input, and the range 5xx indicates an error on our servers. Every error is returned inside an envelope error consistent, carrying a type, a code and a message, and usually the name of the offending parameter and the request ID.

error.json
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "The signers parameter is required.",
    "param": "signers",
    "request_id": "req_9f2"
  }
}
Error types and HTTP codes
TypeHTTP codeMeaning
authentication_error401Missing or invalid key.
invalid_request_error400 / 404A missing or invalid parameter, or a resource that does not exist.
quota_error402Quota exceeded, or a higher plan is required.
permission_error403Your plan or account status does not allow the operation: company verification is required for a live request, the feature is not in your plan, or the IP address is not allowed for the key.
rate_limit_error429More requests than allowed.
idempotency_error409Idempotency key conflict.
api_error5xxAn internal error on the Wthaiq servers.
Other HTTP codes: 200 Success · 201 Created · 403 Forbidden · the range 5xx Server error.
Extra fields in some errors
The fieldWith codeMeaning
upgrade_urlplan_required · plan_expired · plan_feature_unavailableLink to the plans page in the developer portal, to choose, renew or upgrade a plan.
verify_urlkyb_requiredLink to the Company verification page in the developer portal.
feature · required_planplan_feature_unavailableThe requested feature, and the lowest plan that includes it.
max_signerstoo_many_signersThe maximum number of signers in a single live request, which is 5.
Message language: The message text is in Arabic by default and in English in three cases: the request header Accept-Language when its value starts with en, the parameter ?lang=en, or the path /en/api/v1/… which behaves like /api/v1/… in every respect. The code field never changes with the language, so build your integration logic on it, not on the message text.

Idempotency

to make retries safe on requests POST, send the header Idempotency-Key with a unique UUID for each logical operation. If the same request arrives twice (because of a dropped network connection, for example), we return the original response instead of creating a duplicate resource. Keys are retained for 24 hours.

idempotency.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3c9c2e-8b1a-4c7d-9e21-2f0a6b3d1c44" \
  -d '{ "title": "Employment Contract — Ahmed M." }'
If you reuse the same key with a different request body, the status returned is 409 and an error type idempotency_error.
If the repeat arrives while the first request is still running, the status 409 with the code idempotency_in_progress with the header Retry-Afteris returned; retry in a moment to receive the original response without a second execution.

Rate limits

The limit is 100 requests per 10 seconds per account, a single limit shared by test and live mode. Every response carries headers showing your remaining quota, and when you exceed it the status returned is 429 with the header Retry-After with the number of seconds to wait before retrying.

The headerDescription
X-RateLimit-LimitThe maximum number of requests in the current window.
X-RateLimit-RemainingThe number of requests remaining in the current window.
X-RateLimit-ResetThe Unix timestamp at which the window resets.
Retry-AfterAppears with status 429: the number of seconds to wait before retrying.
429.txt
# HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1754000010
Retry-After: 4
Best practice: implement retries with exponential backoff when you receive a 429, and respect the value of Retry-After.

Request IDs

Every response carries the header Wthaiq-Request-Id with a value prefixed byreq_, and the same ID appears inside the field request_id on any error. Store this ID in your logs; it is what we ask for when you contact support, so we can trace any request precisely.

request-id.txt
# HTTP/1.1 200 OK
Content-Type: application/json
Wthaiq-Request-Id: req_9f2a1c

Test keys and live keys

Every key comes in two forms: live sk_ / pk_ and test sk_test_ / pk_test_. You choose the test form when creating the key with the “Test key” option under: Developer console → API keys. The field livemode in every object and event shows which of the two keys created it.

AspectLive keyTest key
BillingEvery request you send is charged to your balanceNothing is charged
MessagesInvitations, reminders and copies are actually sentThe invitation and reminders arrive by email marked “Test”, and no copies are sent; WhatsApp messages are not sent but logged in the request events as “Would have been sent via WhatsApp to …”
LimitsAs per your plan, and so are the featuresEvery feature except the custom domain; 20 requests and 50 emails a day per account, 5 signers per request and 10 recipients per bulk batch
SignersAny email or numberOnly your account’s email or number, or a team member’s email or number
Legal levelses · aes · qesThe requested level itself; identity verification is a simulation in which the signer chooses “Approve” or “Decline” with no provider session, and the whole request has no legal effect
Evidence recordSealed on completion, emitting the events document.sealed and verification.createdNot sealed and no timestamp is requested, and neither event is emitted; GET /signature_requests/{id}/evidence returns an unsealed test record with the test field, and the final file carries the watermark “TEST — no legal effect”
Event notificationsDelivered to live webhook endpointsDelivered to webhook endpoints created with a test key via POST /v1/webhook_endpoints only; endpoints added from the developer console are live

The secret and publishable keys also differ in Access scope:

Aspectsk_ (secret)pk_ (publishable)
Where it is usedServer only — never exposedSafe to expose in the browser
Permissionsfull across all resourcesLimited to specific paths (templates, signature requests, signers, flows) for reading, with the creation of signature requests only
Domain lockingThere is noLocked to the domains allowed_origins that you define — This reduces risk but is not authentication: the Origin header is issued by the browser, and any script outside a browser can forge it. The real protections are the key's daily spend cap and rotating it the moment you suspect exposure.
Daily capThere is noEach key has a daily cap on create and send operations, regardless of how many IP addresses are used. Once reached, status 429 is returned with the code daily_cap_reached until the start of the next day (UTC), and a notification reaches your dashboard at 80% of the cap and when it is reached.
A live key is real and billed. Every signer on a request you send with it counts as one send from your annual plan balance, with a maximum of five signers per request. Once it runs out, it's charged to your wallet at your plan's overage rate. Identity verification is charged to the wallet for every signer who requires it: $1.50. Once a request has been sent, its cost is not refunded, even if it is canceled before anyone signs it.
The safe way to test: Build your integration with a test key and make your own email the signer, then switch to the live key at launch. Use sk_ on your server only, and pk_ locked to your domain for any code running in the browser.

Metadata

Most creatable objects accept the field metadata: a string key/value map in which you store your own internal references (an order number, a user ID in your system, a campaign tag). We do not use these values internally, and they are returned unchanged in every response and in Webhook messages.

ConstraintLimit
Number of keysUp to 50 keys per object.
Key lengthUp to 40 characters.
Value lengthUp to 500 characters.
metadata.json
{
  "metadata": {
    "order_id": "A-1024",
    "crm_contact": "cust_58231",
    "campaign": "q3-onboarding"
  }
}

Signature Requests

The signature request is the central object: it represents a document (from a template or an uploaded file) sent to one or more signers at a defined legal (assurance) level, with full tracking of each signer's status through to completion, at which point the request is sealed with an authenticated, independently verifiable evidence record.

/v1/signature_requests
POST/v1/signature_requests

Create a new signature request — as a draft, or sent to the signers immediately.

The fieldTypeRequiredDescription
titlestringRequiredThe request title shown to the signers.
sourceobjectRequiredThe source of the document; the value of type either template with template_id, or document with document_id. The document source (an uploaded PDF) is not available yet (coming soon) and is rejected with a 400 error.
legal_levelstringRequiredLegal level: ses or aes or qes.
signersarrayRequiredThe list of signers (see the fields below).
formatstringOptionalThe requested assurance level; it is recorded and returned on the object: pades-b / pades-t / pades-lt / pades-lta (default pades-lt). The API path does not currently issue a PAdES signature embedded inside the PDF file; the cryptographic evidence is the sealed evidence record (an Ed25519 signature that any party can verify with the public key at /trust, plus an RFC 3161 timestamp).
orderedbooleanOptionalSequential signing in the order of the signers in the array signers (default false).
require_identitybooleanOptionalRequire identity verification before signing, at the request level.
ccarrayOptionalCopy recipients — they receive the signed contract on completion without signing (up to 20). Each item { name, email }.
remindersobjectOptional{ "enabled": true } sends up to three automatic reminders to the signer whose turn has come, five days, then three days, then one day before the deadline, for sent live requests only. interval_hours and max are stored and returned as sent, without being used. A request expires 7 days after it is sent.
sendbooleanOptionalSend the request as soon as it is created (default true). The value false creates a draft whose signing link does not work until you send it via POST /v1/signature_requests/{id}/send.
metadataobjectOptionalKey/value metadata.
signers[].namestringRequiredThe signer's name.
signers[].emailstringOptional*The signer’s email address. * Required unless you send phone.
signers[].phonestringOptional*The signer’s WhatsApp number (normalised to international format automatically, for example 201012345678). Sent together with an email, the invitation goes out through both channels. Sending it on its own is accepted only while verification codes can be delivered over WhatsApp; otherwise the request is rejected with 400 — so that no signer is left facing a code that cannot reach them.
signers[].methodstringOptionaldraw (a drawn signature + OTP) or token (a QES certificate on a hardware token).
signers[].require_identitybooleanOptionalRequire identity verification for this specific signer (AES).
signers[].fieldsobjectOptionalThe pre-filled template field values.
cURLNode
request.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3c9c2e-..." \
  -d '{
    "title": "Employment Contract — Ahmed M.",
    "source": { "type": "template", "template_id": "tpl_employment" },
    "legal_level": "aes",
    "ordered": true,
    "signers": [
      { "name": "Ahmed Mohamed", "email": "ahmed@example.com", "type": "individual",
        "method": "draw", "require_identity": true,
        "fields": { "job_title": "Software Engineer", "salary": "25000" } }
    ],
    "reminders": { "enabled": true, "interval_hours": 48, "max": 3 },
    "metadata": { "order_id": "A-1024" }
  }'
create.js
import Wthaiq from 'wthaiq';
const wt = new Wthaiq('sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');

const sr = await wt.signatureRequests.create({
  title: 'Employment Contract — Ahmed M.',
  source: { type: 'template', template_id: 'tpl_employment' },
  legal_level: 'aes',
  ordered: true,
  signers: [
    { name: 'Ahmed Mohamed', email: 'ahmed@example.com', method: 'draw', require_identity: true }
  ]
});
Response · 201 Created
signature_request.json
{
  "id": "sr_3n8Kd2Qa1V",
  "object": "signature_request",
  "livemode": true,
  "status": "sent",
  "title": "عقد عمل — أحمد م.",
  "legal_level": "aes",
  "format": "pades-lt",
  "source": { "type": "template", "template_id": "tpl_employment" },
  "signers": [
    {
      "id": "sgr_9fA2",
      "object": "signer",
      "name": "أحمد محمد",
      "email": "ahmed@example.com",
      "type": "individual",
      "method": "draw",
      "require_identity": true,
      "order": 1,
      "status": "sent",
      "signing_url": "https://wthaiq.com/sign.php?token=uZ8..",
      "viewed_at": null,
      "signed_at": null,
      "identity": { "status": "required", "provider": "external", "level": "aes" },
      "fields": { "job_title": "مهندس برمجيات", "start_date": "2026-08-01" }
    }
  ],
  "ordered": true,
  "require_identity": true,
  "reference": null,
  "reminders": { "enabled": true, "interval_hours": 48, "max": 3 },
  "expires_at": 1755000000,
  "completed_at": null,
  "download_url": null,
  "metadata": { "order_id": "A-1024" },
  "created_at": 1754000000
}
POST/v1/signature_requests/bulk

Bulk send: the same contract to several signers at once — creates A separate signature request for each signer (up to 200). The balance is checked for the entire batch before it starts. Every recipient is also validated before any request is created; if one is invalid, the whole batch is rejected with a 400 error that names it in the param field, and nothing is created.

ParameterTypeRequiredDescription
sourceobjectRequiredThe contract source — such as { "type": "template", "template_id": "tpl_..." }.
recipientsarrayRequiredThe list of signers; each item { name, email }.
fieldsobjectOptionalThe shared field values for all the contracts.
legal_levelstringOptionalses or aes or qes.
ccarrayOptionalCopy recipients for each contract.
terminal
curl -X POST https://wthaiq.com/api/v1/signature_requests/bulk \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "source": { "type": "template", "template_id": "tpl_265" },
    "recipients": [
      { "name": "Mohamed Salem", "email": "m1@example.com" },
      { "name": "Sara Ahmed", "email": "s2@example.com" }
    ],
    "fields": { "amount": "5000" },
    "legal_level": "ses"
  }'
Response
{
  "object": "bulk_send",
  "created": 2,
  "failed": 0,
  "requests": [
    { "signature_request": "sr_3n8Kd2Qa1V", "email": "m1@example.com", "status": "sent" },
    { "signature_request": "sr_9Kx2Ld7Pq3", "email": "s2@example.com", "status": "sent" }
  ],
  "errors": []
}
GET/v1/signature_requests

List signature requests with cursor pagination, with optional filtering by status and date (created_after / created_before).

ParameterTypeRequiredDescription
limitintegerOptionalFrom 1 to 100 (default 20).
starting_afterstringOptionalThe cursor for the next page.
statusstringOptionalFilter by status: draft, sent, completed ...
cURLNode
list.sh
curl "https://wthaiq.com/api/v1/signature_requests?limit=3&status=sent" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
list.js
const list = await wt.signatureRequests.list({ limit: 3, status: 'sent' });
Response · 200 OK
list.json
{
  "object": "list",
  "data": [
    {
      "id": "sr_3n8Kd2Qa1V",
      "object": "signature_request",
      "livemode": true,
      "status": "sent",
      "title": "Employment Contract — Ahmed M.",
      "legal_level": "aes",
      "format": "pades-lt",
      "created_at": 1754000000
    }
  ],
  "has_more": true,
  "next_cursor": "sr_2m7Xa9"
}
GET/v1/signature_requests/{id}

Retrieve a signature request by its ID, with its list of signers and their status.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signature request ID (sr_).
cURLNode
retrieve.sh
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
retrieve.js
const sr = await wt.signatureRequests.retrieve('sr_3n8Kd2Qa1V');
Response · 200 OK
signature_request.json
{
  "id": "sr_3n8Kd2Qa1V",
  "object": "signature_request",
  "livemode": true,
  "status": "partially_signed",
  "title": "Employment Contract — Ahmed M.",
  "legal_level": "aes",
  "format": "pades-lt",
  "source": { "type": "template", "template_id": "tpl_employment" },
  "ordered": true,
  "require_identity": true,
  "reference": null,
  "expires_at": 1755000000,
  "completed_at": null,
  "download_url": null,
  "metadata": { "order_id": "A-1024" },
  "created_at": 1754000000
}
POST/v1/signature_requests/{id}/send

Send a request from draft status and push it to the signers.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signature request ID.
send.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/send \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
signature_request.json
{
  "id": "sr_3n8Kd2Qa1V",
  "object": "signature_request",
  "status": "sent",
  "created_at": 1754000000
}
POST/v1/signature_requests/{id}/cancel

Cancel a signature request that has not yet completed; its status becomes canceled. A request that is already completed or canceled is rejected with status 409 and the code request_not_cancelable. Once a request has been sent, its cost is not refunded, even if it is canceled before anyone signs it.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signature request ID.
cancel.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/cancel \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
signature_request.json
{
  "id": "sr_3n8Kd2Qa1V",
  "object": "signature_request",
  "status": "canceled",
  "completed_at": null,
  "created_at": 1754000000
}
POST/v1/signature_requests/{id}/reminders

Trigger an immediate reminder to the pending signers on this request. A draft or canceled request is rejected with status 400.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signature request ID.
reminders.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/reminders \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
reminder.json
{
  "object": "reminder",
  "signature_request": "sr_3n8Kd2Qa1V",
  "reminders_sent": 1
}
GET/v1/signature_requests/{id}/download

Returns the signed contract data as JSON once the request is complete: pdf_url is the link to the final PDF (the frozen contract text with the verification certificate, its reference and QR code), pdf_status is its state: ready or pending or unavailable, and pdf_sha256 is its fingerprint, final_document_url is the final document page, and reference is the verification reference. The same file is downloaded via GET /v1/signature_requests/{id}/download/pdf with a secret key, and in live mode its link is e-mailed to every signer and to the sender on completion. The independent cryptographic proof is the evidence record via GET /v1/signature_requests/{id}/evidence.

ParameterTypeRequiredDescription
idstring · pathRequiredThe ID of the completed signature request.
download.sh
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/download \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
download.json
{
  "object": "download",
  "signature_request": "sr_3n8Kd2Qa1V",
  "pdf_url": "https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/download/pdf",
  "pdf_status": "ready",
  "pdf_sha256": "455e49ec8a9975bb6ba5500fffb0d3af1a364ab2a1b1c1335020b17aef8316ef",
  "pdf_bytes": 100993,
  "pdf_generated_at": 1791021338,
  "final_document_url": "https://wthaiq.com/final/9c1e..",
  "reference": "WTQ-1A2B3C4D5E6F",
  "format": "pades-lt",
  "legal_level": "aes"
}
If the request is not complete, the status returned is 400 and an error type invalid_request_error.
GET/v1/signature_requests/{id}/certificate

Completion certificate data with the audit trail, as JSON.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signature request ID.
certificate.sh
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/certificate \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
certificate.json
{
  "object": "certificate",
  "signature_request": "sr_3n8Kd2Qa1V",
  "status": "completed",
  "reference": "WTQ-1A2B3C4D5E6F",
  "legal_level": "aes",
  "format": "pades-lt",
  "completed_at": 1754500000,
  "signers": [
    { "name": "Ahmed Mohamed", "email": "ahmed@example.com", "phone": null, "status": "signed", "signed_at": 1754500000 }
  ],
  "audit_trail": [
    { "event": "sent", "actor": "owner", "ip": "203.0.113.7", "at": 1754000000 },
    { "event": "signed", "actor": "signer", "ip": "198.51.100.4", "at": 1754500000 }
  ],
  "verify_url": "https://wthaiq.com/verify?c=WTQ-1A2B3C4D5E6F"
}
GET/v1/signature_requests/{id}/evidence

The sealed evidence record of a completed request, for independent verification: the record’s canonical text record_raw with the Ed25519 signature over it, the public key and the RFC 3161 timestamp. Requires a secret key sk_, and returns 404 until the record is sealed; test requests are never sealed.

evidence.sh
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/evidence \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
evidence.json
{
  "object": "evidence",
  "signature_request": "sr_3n8Kd2Qa1V",
  "format": "wthaiq-evidence-v1",
  "verify_ref": "WTQ-1A2B3C4D5E6F",
  "record_raw": "{\"document\":{..}}",
  "seal": {
    "signature_alg": "ed25519",
    "signature": "b64..",
    "public_key": "b64..",
    "trust_url": "https://wthaiq.com/trust",
    "timestamp_token": "b64.."
  }
}
GET/v1/signature_requests/{id}/events

The chronological audit trail for this request — every event from opening to signing.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signature request ID.
limitinteger · queryOptionalFrom 1 to 100 (default 20).
events.sh
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/events \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
events.json
{
  "object": "list",
  "data": [
    {
      "id": "evt_2M",
      "object": "event",
      "type": "signer.signed",
      "signature_request": "sr_3n8Kd2Qa1V",
      "signer": "sgr_9fA2",
      "actor": "signer",
      "ip": "197.44.x.x",
      "user_agent": "..",
      "created_at": 1754500000
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Signers

A signer represents a party to a signature request, with its own status, signing method and identity verification result. It is created implicitly when the request is created, and it can be retrieved or given an embedded signing session.

/v1/signers
GET/v1/signers/{id}

Retrieve a signer by ID.

ParameterTypeRequiredDescription
idstring · pathRequiredThe signer ID (sgr_).
retrieve.sh
curl https://wthaiq.com/api/v1/signers/sgr_9fA2 \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
signer.json
{
  "id": "sgr_9fA2",
  "object": "signer",
  "name": "أحمد محمد",
  "email": "ahmed@example.com",
  "type": "individual",
  "method": "draw",
  "require_identity": true,
  "order": 1,
  "status": "identity_verified",
  "signing_url": "https://wthaiq.com/sign.php?token=uZ8..",
  "viewed_at": 1754000100,
  "signed_at": null,
  "identity": { "status": "approved", "provider": "external", "level": "aes" },
  "fields": { "job_title": "مهندس برمجيات", "start_date": "2026-08-01" }
}
POST/v1/signers/{id}/signing_session

Creates an embedded signing link valid for 30 minutes, to show the signing page inside your app under your brand (white-label). It cannot be created for a draft or canceled request.

The fieldTypeRequiredDescription
idstring · pathRequiredThe signer ID.
return_urlstringOptionalA full https URL on a domain accepted in your account, to which the signer returns after signing; available on the Business plan and above. The session lifetime is fixed at 30 minutes.
modestringOptionaliframe (default) to embed in a frame on a page under a domain accepted in your account, or redirect to send the browser to the signing page and then back to success_url or cancel_url. Do not send return_url with mode redirect.
success_urlstringRequired with redirectAn https URL on a domain accepted on your account (up to 500 characters, no username, no #). The signer is redirected to it after signing, with session_id (the request ID), signer_id and status=completed. {signature_request} and {signer} in the URL are replaced with the request and signer IDs.
cancel_urlstringOptionalLike success_url; the signer is redirected to it after declining, with status=declined. If omitted, the signer stays on the signing page after declining. Rely on the signed webhook for the outcome, not on the redirect.
signing_session.sh
curl -X POST https://wthaiq.com/api/v1/signers/sgr_9fA2/signing_session \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -d '{ "return_url": "https://app.acme.com/done" }'
Response · 201 Created
signing_session.json
{
  "object": "signing_session",
  "signer": "sgr_9fA2",
  "signing_url": "https://wthaiq.com/embed/sign/9Qa1V..",
  "expires_at": 1754001800
}

Documents

A document is an uploaded PDF saved in your account with its digital fingerprint (SHA-256), page count and size. Using it as a signature-request source through the API is not available yet (coming soon).

/v1/documents
POST/v1/documents

Upload a PDF file via multipart/form-data and saves it in your account; it counts toward your plan’s contract limit. It cannot yet be used as a signature-request source; a request that references it is rejected with a 400 error until this becomes available (coming soon).

The fieldTypeRequiredDescription
filefileRequiredThe PDF file (multipart form field).
kindstringOptionalDocument type: pdf (default) or contract.
field_mapstring (JSON)OptionalA coordinate field map by which the values are printed in their positions on the pages. The coordinates are relative (0..1) measured from the top left of the page.
Field map (field_map): An array of items in the form { "key", "label", "type", "page", "x", "y", "w", "h", "required" }. The map is saved with the document and returned in the field fields, but its values are not printed on the file yet (coming soon).
upload.sh
curl -X POST https://wthaiq.com/api/v1/documents \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -F "file=@agreement.pdf" \
  -F "kind=pdf" \
  -F 'field_map=[
    {"key":"signer_name","label":"Signer name","type":"text",
     "page":1,"x":0.12,"y":0.34,"w":0.30,"h":0.04,"required":true},
    {"key":"contract_date","label":"Date","type":"date",
     "page":1,"x":0.62,"y":0.34,"w":0.22,"h":0.04}
  ]'
Response · 201 Created
document.json
{
  "id": "doc_7Yq",
  "object": "document",
  "kind": "pdf",
  "filename": "agreement.pdf",
  "pages": 4,
  "bytes": 183221,
  "sha256": "a3f1..",
  "created_at": 1754000000
}

Templates

Templates are the contracts saved in your account, with their fillable fields. Signature requests refer to them through source.template_id.

/v1/templates
GET/v1/templates

List the templates saved in your account.

ParameterTypeRequiredDescription
limitinteger · queryOptionalFrom 1 to 100 (default 20).
categorystring · queryOptionalFilter by category, such as hr.
starting_afterstring · queryOptionalThe cursor for the next page.
cURLNode
list.sh
curl "https://wthaiq.com/api/v1/templates?category=hr" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
list.js
const tpls = await wt.templates.list({ category: 'hr' });
Response · 200 OK
list.json
{
  "object": "list",
  "data": [
    {
      "id": "tpl_employment",
      "object": "template",
      "name": "Employment Contract",
      "category": "hr",
      "languages": ["ar"],
      "created_at": 1754000000
    }
  ],
  "has_more": false,
  "next_cursor": null
}
GET/v1/templates/{id}

Retrieve a template together with the definition of its fillable fields.

ParameterTypeRequiredDescription
idstring · pathRequiredThe template ID (tpl_).
cURLNode
retrieve.sh
curl https://wthaiq.com/api/v1/templates/tpl_employment \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
retrieve.js
const tpl = await wt.templates.retrieve('tpl_employment');
Response · 200 OK
template.json
{
  "id": "tpl_employment",
  "object": "template",
  "name": "Employment Contract",
  "category": "hr",
  "languages": ["ar"],
  "fields": [
    { "key": "job_title", "label": "Job title", "type": "text", "required": true },
    { "key": "salary", "label": "Salary", "type": "number", "required": true }
  ],
  "created_at": 1754000000
}

Identity Verifications

Identity verification ties the signer's signature to a real person verified through a specialized identity-verification provider (an official document and a live face match), and it is a requirement of the advanced level (AES).

/v1/identity_verifications
GET/v1/identity_verifications/{id}

Retrieve an identity verification by its ID.

ParameterTypeRequiredDescription
idstring · pathRequiredThe identity verification ID (idv_).
retrieve.sh
curl https://wthaiq.com/api/v1/identity_verifications/idv_5k \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
identity_verification.json
{
  "id": "idv_5k",
  "object": "identity_verification",
  "provider": "external",
  "signer": "sgr_9fA2",
  "status": "approved",
  "level": "aes",
  "verification_url": "https://verify.wthaiq.com/u/..",
  "created_at": 1754000000
}

Verifications

Public verification of a signed document's integrity through its public reference (WTQ- / WTH-), without exposing the parties' full details. It compares the document's current hash with the sealed one.

/v1/verifications
GET/v1/verifications/{reference}

Public verification of a document through its reference.

ParameterTypeRequiredDescription
referencestring · pathRequiredThe public reference, such as WTQ-1A2B3C4D5E6F.
verify.sh
curl https://wthaiq.com/api/v1/verifications/WTQ-1A2B3C4D5E6F \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
verification.json
{
  "object": "verification",
  "reference": "WTQ-1A2B3C4D5E6F",
  "found": true,
  "status": "completed",
  "integrity": "intact",
  "document": {
    "title": "Employment Contract",
    "sha256": "a3f1..",
    "hash_alg": "hmac-sha256",
    "format": "platform-evidence",
    "legal_level": "aes"
  },
  "signed_at": 1754500000,
  "parties": [
    { "name": "A**** M****", "role": "signer" },
    { "name": "W**** C****", "role": "owner" }
  ],
  "qr": "https://wthaiq.com/verify?c=WTQ-1A2B3C4D5E6F"
}

Events

Every event is an immutable object that represents an entry in the audit trail and reflects a change in a resource. These same events are what Webhook messages deliver, and they can be listed and retrieved later.

/v1/events
GET/v1/events

List the account events, with optional filtering by type.

ParameterTypeRequiredDescription
limitinteger · queryOptionalFrom 1 to 100 (default 20).
typestring · queryOptionalFilter by event type, such as signer.signed.
starting_afterstring · queryOptionalThe cursor for the next page.
list.sh
curl "https://wthaiq.com/api/v1/events?limit=10&type=signer.signed" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
list.json
{
  "object": "list",
  "data": [
    {
      "id": "evt_2M",
      "object": "event",
      "type": "signer.signed",
      "signature_request": "sr_3n8Kd2Qa1V",
      "signer": "sgr_9fA2",
      "actor": "signer",
      "ip": "197.44.x.x",
      "user_agent": "..",
      "created_at": 1754500000
    }
  ],
  "has_more": true,
  "next_cursor": "evt_1L"
}
GET/v1/events/{id}

Retrieve a single event by its ID.

ParameterTypeRequiredDescription
idstring · pathRequiredThe event ID (evt_).
retrieve.sh
curl https://wthaiq.com/api/v1/events/evt_2M \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
event.json
{
  "id": "evt_2M",
  "object": "event",
  "type": "signer.signed",
  "signature_request": "sr_3n8Kd2Qa1V",
  "signer": "sgr_9fA2",
  "actor": "signer",
  "ip": "197.44.x.x",
  "user_agent": "..",
  "created_at": 1754500000
}
POST/v1/events/{id}/redeliver

Redelivers the webhook of a past event with the same payload and the same ID, signed with the endpoint's current secret. A new delivery is created and attempted immediately, and follows the usual retry schedule if your server does not respond with 2xx. Limit: five per event and thirty per account every ten minutes, then 429.

ParameterTypeRequiredDescription
idstring · pathRequiredThe event ID (evt_).
endpointstringOptionalID of an enabled endpoint (we_) to redeliver to it only. Without it, the event is redelivered to every enabled endpoint subscribed to its type.
redeliver.sh
curl -X POST https://wthaiq.com/api/v1/events/evt_2M/redeliver \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -d '{ "endpoint": "we_8Hk2" }'
Response · 200 OK
event_redelivery.json
{
  "object": "event_redelivery",
  "event": "evt_2M",
  "deliveries": [
    { "endpoint": "we_8Hk2", "status": "succeeded", "response_code": 200, "error": null }
  ]
}

Webhook Endpoints

A Webhook endpoint registers a URL that receives real-time notifications of the events you subscribe to. See the guide Webhooks for how to verify the notification signature and how retries work.

/v1/webhook_endpoints
POST/v1/webhook_endpoints

Create a new Webhook endpoint. The secret value is returned whsec_ once, at creation.

The fieldTypeRequiredDescription
urlstringRequiredThe HTTPS URL that receives POST messages.
enabled_eventsarrayRequiredThe event types subscribed to, such as signature_request.completed.
cURLNode
create.sh
curl -X POST https://wthaiq.com/api/v1/webhook_endpoints \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://api.acme.com/hooks/wthaiq",
    "enabled_events": ["signature_request.completed", "signer.signed"]
  }'
create.js
const we = await wt.webhookEndpoints.create({
  url: 'https://api.acme.com/hooks/wthaiq',
  enabled_events: ['signature_request.completed', 'signer.signed']
});
Response · 201 Created
webhook_endpoint.json
{
  "id": "we_1a",
  "object": "webhook_endpoint",
  "url": "https://api.acme.com/hooks/wthaiq",
  "enabled_events": ["signature_request.completed", "signer.signed"],
  "status": "enabled",
  "secret": "whsec_..",
  "created_at": 1754000000
}
GET/v1/webhook_endpoints

List the registered Webhook endpoints.

ParameterTypeRequiredDescription
limitinteger · queryOptionalFrom 1 to 100 (default 20).
list.sh
curl https://wthaiq.com/api/v1/webhook_endpoints \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
list.json
{
  "object": "list",
  "data": [
    {
      "id": "we_1a",
      "object": "webhook_endpoint",
      "url": "https://api.acme.com/hooks/wthaiq",
      "enabled_events": ["signature_request.completed", "signer.signed"],
      "status": "enabled",
      "created_at": 1754000000
    }
  ],
  "has_more": false,
  "next_cursor": null
}
GET/v1/webhook_endpoints/{id}

Retrieve a Webhook endpoint by its ID.

ParameterTypeRequiredDescription
idstring · pathRequiredThe Webhook endpoint ID (we_).
retrieve.sh
curl https://wthaiq.com/api/v1/webhook_endpoints/we_1a \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
webhook_endpoint.json
{
  "id": "we_1a",
  "object": "webhook_endpoint",
  "url": "https://api.acme.com/hooks/wthaiq",
  "enabled_events": ["signature_request.completed", "signer.signed"],
  "status": "enabled",
  "secret": "whsec_..",
  "created_at": 1754000000
}
DELETE/v1/webhook_endpoints/{id}

Delete a Webhook endpoint; events stop being sent to it immediately.

ParameterTypeRequiredDescription
idstring · pathRequiredThe Webhook endpoint ID.
delete.sh
curl -X DELETE https://wthaiq.com/api/v1/webhook_endpoints/we_1a \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"
Response · 200 OK
deleted.json
{
  "id": "we_1a",
  "object": "webhook_endpoint",
  "deleted": true
}
signature_request

The central object of a signature request.

signature_request
{
  "id": "sr_3n8Kd2Qa1V",
  "object": "signature_request",
  "livemode": true,
  "status": "sent",
  "title": "Employment Contract — Ahmed M.",
  "legal_level": "aes",
  "format": "pades-lt",
  "source": { "type": "template", "template_id": "tpl_employment" },
  "signers": [ ],
  "ordered": true,
  "require_identity": true,
  "reference": null,
  "reminders": { "enabled": true, "interval_hours": 48, "max": 3 },
  "expires_at": 1755000000,
  "completed_at": null,
  "download_url": null,
  "metadata": { "order_id": "A-1024" },
  "created_at": 1754000000
}
The fieldTypeDescription
idstringThe request ID.
statusstringdraft · sent · partially_signed · completed · declined · expired · canceled.
legal_levelstringses · aes · qes.
formatstringThe requested assurance level recorded on the object (pades-b / t / lt / lta). The API path does not issue a PAdES signature embedded inside the PDF; the proof is the sealed evidence record, which is independently verifiable.
sourceobjectThe source of the document (a template or an uploaded document).
signersarrayThe signer objects.
orderedbooleanSequential signing.
require_identitybooleanIdentity verification before signing (AES).
referencestring · nullThe public verification reference (WTQ-XXXXXXXXXXXX), issued on completion.
download_urlstring · nullThe signed PDF URL, which appears on completion.
created_atintegerThe Unix timestamp of creation.
signer

A signing party within a request.

signer
{
  "id": "sgr_9fA2",
  "object": "signer",
  "name": "أحمد محمد",
  "email": "ahmed@example.com",
  "type": "individual",
  "method": "draw",
  "require_identity": true,
  "order": 1,
  "status": "identity_verified",
  "signing_url": "https://wthaiq.com/sign.php?token=uZ8..",
  "viewed_at": 1754000100,
  "signed_at": null,
  "identity": { "status": "approved", "provider": "external", "level": "aes" },
  "fields": { "job_title": "مهندس برمجيات", "start_date": "2026-08-01" }
}
The fieldTypeDescription
typestringindividual or company.
methodstringdraw (drawn signature + email OTP) or token (a QES certificate on a hardware token).
statusstringpending · sent · viewed · otp_verified · identity_verified · signed · declined.
signing_urlstringThe URL of the hosted or embeddable signing page.
identityobjectThe identity verification result, when enabled via require_identity.
identity.statusstringnone · required · in_review · resubmission_requested · declined · approved. The value changes with the signer.identity_* events.
identity.verification_idstringID of the latest identity verification for the signer (idv_), or null before one starts.
identity.reason_codestringA general classified reason on decline, with no personal data: reviewer_decision · face_mismatch · face_unclear · document_expired · document_unreadable · document_not_original · document_not_supported · not_accepted.
identity.resubmit_stepsarrayThe steps to redo when resubmission is requested: document · liveness.
identity.updated_atintegerTime of the last change in the identity confirmation status.
fieldsobjectThe pre-filled template field values.
document

An uploaded PDF file.

document
{
  "id": "doc_7Yq",
  "object": "document",
  "kind": "pdf",
  "filename": "agreement.pdf",
  "pages": 4,
  "bytes": 183221,
  "sha256": "a3f1..",
  "created_at": 1754000000
}
The fieldTypeDescription
kindstringpdf or contract.
pagesintegerThe page count.
bytesintegerThe file size in bytes.
sha256stringThe document's SHA-256 hash.
template

A ready-made contract with fillable fields.

template
{
  "id": "tpl_employment",
  "object": "template",
  "name": "Employment Contract",
  "category": "hr",
  "languages": ["ar"],
  "fields": [
    { "key": "job_title", "label": "Job title", "type": "text", "required": true },
    { "key": "salary", "label": "Salary", "type": "number", "required": true }
  ],
  "created_at": 1754000000
}
The fieldTypeDescription
namestringThe template name.
categorystringThe template category, such as hr.
languagesarrayThe languages available for the template.
fieldsarrayField definitions: key, label, type, required.
identity_verification

The result of a signer's identity verification through a specialized identity-verification provider.

identity_verification
{
  "id": "idv_5k",
  "object": "identity_verification",
  "provider": "external",
  "signer": "sgr_9fA2",
  "status": "approved",
  "level": "aes",
  "verification_url": "https://verify.wthaiq.com/u/..",
  "created_at": 1754000000
}
The fieldTypeDescription
providerstringThe verification provider (external).
signerstringThe associated signer ID.
statusstringpending · in_review · resubmission_requested · approved · declined · expired.
levelstringThe target legal level.
verification

The result of a public check of a document's integrity by its reference.

verification
{
  "object": "verification",
  "reference": "WTQ-1A2B3C4D5E6F",
  "found": true,
  "status": "completed",
  "integrity": "intact",
  "document": {
    "title": "Employment Contract",
    "sha256": "a3f1..",
    "hash_alg": "hmac-sha256",
    "format": "platform-evidence",
    "legal_level": "aes"
  },
  "signed_at": 1754500000,
  "parties": [
    { "name": "A**** M****", "role": "signer" },
    { "name": "W**** C****", "role": "owner" }
  ],
  "qr": "https://wthaiq.com/verify?c=WTQ-1A2B3C4D5E6F"
}
The fieldTypeDescription
referencestringThe public reference (WTQ-/WTH-).
foundbooleanWhether the document was found.
integritystringintact compared and matched · modified compared and differed · recorded hash on record, file not available for comparison · unknown no hash on record.
structurestringStructural commitment — covers tags, attributes, formatting and images, which the text hash does not cover: match · changed · absent for a signature predating this commitment.
document.sha256stringThe document fingerprint recorded at sealing; its algorithm is given in the hash_alg field.
document.hash_algstringhmac-sha256 For WTQ- references: a fingerprint of the document text keyed with a secret held by the platform, so it does not equal a hash of the downloaded PDF and cannot be recomputed by a third party; it is matched through the verification page. · sha256 For WTH- references: a hash of the final file itself, which anyone can recompute.
document.formatstringThe PAdES signature level actually embedded in the file when the party signs with a token: pades-b · pades-t · pades-lt · pades-lta. Otherwise platform-evidence: a time-stamped evidence record, with no signature embedded in the file.
partiesarrayParties with partially masked names.
qrstringThe public verification page URL.
event

An immutable entry in the audit trail.

event
{
  "id": "evt_2M",
  "object": "event",
  "type": "signer.signed",
  "signature_request": "sr_3n8Kd2Qa1V",
  "signer": "sgr_9fA2",
  "actor": "signer",
  "ip": "197.44.x.x",
  "user_agent": "..",
  "created_at": 1754500000
}
The fieldTypeDescription
typestringThe event type, such as signer.signed.
actorstringowner · signer · system.
ipstringThe actor's IP address.
user_agentstringThe actor's user agent.
webhook_endpoint

A registered URL for receiving events.

webhook_endpoint
{
  "id": "we_1a",
  "object": "webhook_endpoint",
  "url": "https://api.acme.com/hooks/wthaiq",
  "enabled_events": ["signature_request.completed", "signer.signed"],
  "status": "enabled",
  "secret": "whsec_..",
  "created_at": 1754000000
}
The fieldTypeDescription
urlstringThe receiving HTTPS address.
enabled_eventsarrayThe subscribed event types.
statusstringenabled or disabled.
secretstringThe signing secret whsec_ to verify the HMAC.
api_key

An API access key (the full secret is not shown after creation).

api_key
{
  "id": "key_88",
  "object": "api_key",
  "name": "Production",
  "prefix": "sk_9a1b2c3d4e5f6",
  "livemode": true,
  "created_at": 1754000000,
  "last_used_at": 1754500000
}
The fieldTypeDescription
namestringThe key's descriptive name.
prefixstringThe visible prefix of the key.
livemodebooleanWhether the key is live.
last_used_atinteger · nullLast used (Unix timestamp).

Ready to build on Wthaiq?

Start from the quickstart guide and issue your first signature request in minutes with a free test key, using your own email as the recipient of the first test.

Get started in five minutes