Overview
The Wthaiq API is a REST API organised 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, and downloading the PDF, which is application/pdf). 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:
| Prefix | Resource | Example |
|---|---|---|
| sr_ | signature_request | sr_3n8Kd2Qa1V |
| sgr_ | signer | sgr_9fA2 |
| doc_ | document | doc_7Yq |
| tpl_ | template | tpl_employment |
| idv_ | identity_verification | idv_5k |
| evt_ | event | evt_2M |
| we_ | webhook_endpoint | we_1a |
| key_ | api_key | key_88 |
https://wthaiq.com/api/v1. The version is pinned by date through the header Wthaiq-Version, and the changes are dated in Changelog.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.
| Key | The format | Description |
|---|---|---|
| The secret key | sk_... | Full privileges, server-side only. Live from creation: it sends real messages, issues legal certificates, and is billed. See No test mode. |
| The publishable key | pk_... | Safe to expose in the browser, locked to your domains, and limited to a fixed set of paths. |
| The Webhook secret | whsec_... | Used to verify the signature of Webhook messages (HMAC-SHA256). |
curl https://wthaiq.com/api/v1/signature_requests \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
401 and an error type authentication_error. Manage your keys and delete any leaked key from the dashboard 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 behaviour stays fixed even if we ship later changes. If you omit the header, the latest version pinned to your account is used.
curl https://wthaiq.com/api/v1/templates \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
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": {
"type": "invalid_request_error",
"code": "parameter_missing",
"message": "The signers parameter is required.",
"param": "signers",
"request_id": "req_9f2"
}
}
| Type | HTTP code | Meaning |
|---|---|---|
| authentication_error | 401 | Missing or invalid key. |
| invalid_request_error | 400 / 404 | A missing or invalid parameter, or a resource that does not exist. |
| quota_error | 402 | Quota exceeded, or a higher plan is required. |
| rate_limit_error | 429 | More requests than allowed. |
| identity_error | 422 | Identity verification failed or could not be completed. |
| signing_error | 422 | Signing could not be completed (invalid state for the operation). |
| idempotency_error | 409 | Idempotency key conflict. |
| api_error | 5xx | An internal error on the Wthaiq servers. |
200 Success · 201 Created · 403 Forbidden · domain 5xx Server error.Pagination
All list endpoints use cursor-based pagination. They are controlled by three query parameters, and every list returns a consistent envelope carrying object: "list".
| Parameter | Type | Description |
|---|---|---|
| limit | integer | The number of items per page, from 1 to 100 (default 20). |
| starting_after | string | The ID of the item after which pagination starts (the next page). |
| ending_before | string | The ID of the item before which pagination ends (the previous page). |
{
"object": "list",
"data": [
{ "id": "sr_3n8Kd2Qa1V", "object": "signature_request", "status": "sent" }
],
"has_more": true,
"next_cursor": "sr_2m7Xa9"
}
next_cursor in starting_after. Stop paginating once has_more with the value false.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.
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." }'
409 and an error type idempotency_error.Rate limits
The default limit in live mode is 100 requests per 10 seconds. 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 header | Description |
|---|---|
| X-RateLimit-Limit | The maximum number of requests in the current window. |
| X-RateLimit-Remaining | The number of requests remaining in the current window. |
| X-RateLimit-Reset | The Unix timestamp at which the window resets. |
| Retry-After | Appears with status 429: the number of seconds to wait before retrying. |
# HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1754000010
Retry-After: 4
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.
# HTTP/1.1 200 OK
Content-Type: application/json
Wthaiq-Request-Id: req_9f2a1c
No test mode — sk_ versus pk_
There is no separate test environment in Wthaiq. Every sk_ Live from the moment it is created: it sends real email to signers, issues legally effective certificates, and charges your balance with every call. The field livemode equals true on every object, always — so do not check it to tell one environment from another.
The real distinction between keys is not test/live, but Access scope:
| Aspect | sk_ (secret) | pk_ (publishable) |
|---|---|---|
| Where it is used | Server only — never exposed | Safe to expose in the browser |
| Permissions | full across all resources | Limited to specific paths (templates, signature requests, signers, flows) for reading, with the creation of signature requests only |
| Domain locking | There is no | Locked to the domains allowed_origins that you define |
| Billing | Every call is genuinely billed | Every call is genuinely billed |
sk_ on your server only, andpk_ 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.
| Constraint | Limit |
|---|---|
| Number of keys | Up to 50 keys per object. |
| Key length | Up to 40 characters. |
| Value length | Up to 500 characters. |
{
"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_requestsCreate a new signature request — as a draft, or sent to the signers immediately.
| The field | Type | Required | Description |
|---|---|---|---|
| title | string | Required | The request title shown to the signers. |
| source | object | Required | The source of the document. type either template with template_id, or document with document_id. |
| legal_level | string | Required | Legal level: ses or aes or qes. |
| signers | array | Required | The list of signers (see the fields below). |
| format | string | Optional | The 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). |
| ordered | boolean | Optional | Sequential signing according to the field order (default false). |
| require_identity | boolean | Optional | Require identity verification before signing, at the request level. |
| cc | array | Optional | Copy recipients — they receive the signed contract on completion without signing (up to 20). Each item { name, email }. |
| reminders | object | Optional | Reminder settings: enabled, interval_hours, max. |
| expires_at | integer | Optional | The Unix timestamp of the request's expiry. |
| send | boolean | Optional | Send immediately after creation; otherwise it is created as a draft. |
| metadata | object | Optional | Key/value metadata. |
| signers[].name | string | Required | The signer's name. |
| signers[].email | string | Required | The signer's email. |
| signers[].method | string | Optional | draw (a drawn signature + OTP) or token (a QES certificate on a hardware token). |
| signers[].require_identity | boolean | Optional | Identity verification for this specific signer (AES). |
| signers[].order | integer | Optional | The signing order when ordered: true. |
| signers[].fields | object | Optional | The pre-filled template field values. |
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" }
}'
import Wthaiq from '@wthaiq/node';
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 }
]
});
{
"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": [
{
"id": "sgr_9fA2",
"object": "signer",
"name": "Ahmed Mohamed",
"email": "ahmed@example.com",
"type": "individual",
"method": "draw",
"require_identity": true,
"order": 1,
"status": "sent",
"signing_url": "https://sign.wthaiq.com/s/uZ8..",
"viewed_at": null,
"signed_at": null,
"identity": { "status": "pending", "provider": "didit", "level": "aes" },
"fields": { "job_title": "Software Engineer", "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
}
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.
| Parameter | Type | Required | Description |
|---|---|---|---|
| source | object | Required | The contract source — such as { "type": "template", "template_id": "tpl_..." }. |
| recipients | array | Required | The list of signers; each item { name, email }. |
| fields | object | Optional | The shared field values for all the contracts. |
| legal_level | string | Optional | ses or aes or qes. |
| cc | array | Optional | Copy recipients for each contract. |
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"
}'{
"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": []
}
List signature requests with cursor pagination, with optional filtering by status and date (created_after / created_before).
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | Optional | From 1 to 100 (default 20). |
| starting_after | string | Optional | The cursor for the next page. |
| ending_before | string | Optional | The previous page cursor. |
| status | string | Optional | Filter by status: draft, sent, completed ... |
curl "https://wthaiq.com/api/v1/signature_requests?limit=3&status=sent" \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
const list = await wt.signatureRequests.list({ limit: 3, status: 'sent' });
{
"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"
}
Retrieve a signature request by its ID, with its list of signers and their status.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signature request ID (sr_). |
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
const sr = await wt.signatureRequests.retrieve('sr_3n8Kd2Qa1V');
{
"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
}
Send a request from draft status and push it to the signers.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signature request ID. |
curl -X POST https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/send \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"id": "sr_3n8Kd2Qa1V",
"object": "signature_request",
"status": "sent",
"created_at": 1754000000
}
Cancel a signature request that has not yet completed; its status becomes canceled.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signature request ID. |
curl -X POST https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/cancel \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"id": "sr_3n8Kd2Qa1V",
"object": "signature_request",
"status": "canceled",
"completed_at": null,
"created_at": 1754000000
}
Trigger an immediate reminder to the pending signers on this request.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signature request ID. |
curl -X POST https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/reminders \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"object": "reminder",
"signature_request": "sr_3n8Kd2Qa1V",
"sent_to": ["ahmed@example.com"],
"sent_at": 1754050000
}
Downloading the signed PDF (application/pdf) — available only once the request is complete.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The ID of the completed signature request. |
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/download \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01" \
-o agreement-signed.pdf
# HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="agreement-signed.pdf"
Wthaiq-Request-Id: req_9f2a1c
422 and an error type signing_error.The completion certificate with the audit trail — PDF by default, or JSON through ?format=json.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signature request ID. |
| format | string · query | Optional | pdf (default) or json. |
curl "https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/certificate?format=json" \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"object": "certificate",
"signature_request": "sr_3n8Kd2Qa1V",
"reference": "WTQ-000123",
"legal_level": "aes",
"format": "pades-lt",
"document": { "sha256": "a3f1..", "sealed_at": 1754500000 },
"signers": [
{ "name": "Ahmed Mohamed", "signed_at": 1754500000, "identity": "approved" }
],
"events_count": 7,
"issued_at": 1754500050
}
The chronological audit trail for this request — every event from opening to signing.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signature request ID. |
| limit | integer · query | Optional | From 1 to 100 (default 20). |
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/events \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"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/signersRetrieve a signer by ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signer ID (sgr_). |
curl https://wthaiq.com/api/v1/signers/sgr_9fA2 \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"id": "sgr_9fA2",
"object": "signer",
"name": "Ahmed Mohamed",
"email": "ahmed@example.com",
"type": "individual",
"method": "draw",
"require_identity": true,
"order": 1,
"status": "viewed",
"signing_url": "https://sign.wthaiq.com/s/uZ8..",
"viewed_at": 1754000100,
"signed_at": null,
"identity": { "status": "approved", "provider": "didit", "level": "aes" },
"fields": { "job_title": "Software Engineer", "start_date": "2026-08-01" }
}
Generate a short-lived embedded signing link/token (white-label) to display the signing page inside your app.
| The field | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The signer ID. |
| expires_in | integer | Optional | The session lifetime in seconds (default 3600). |
| redirect_url | string | Optional | A URL the signer is returned to after completion. |
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 '{ "expires_in": 3600, "redirect_url": "https://app.acme.com/done" }'
{
"object": "signing_session",
"signer": "sgr_9fA2",
"signing_url": "https://sign.wthaiq.com/s/uZ8..?t=st_9Qa..",
"token": "st_9Qa1V..",
"expires_at": 1754003600
}
Documents
A document represents an uploaded PDF file on which signature requests are built (as an alternative to the ready-made templates). It is stored with its SHA-256 hash, its page count and its size.
/v1/documentsUpload a PDF file via multipart/form-data to be used as a document source.
| The field | Type | Required | Description |
|---|---|---|---|
| file | file | Required | The PDF file (multipart form field). |
| kind | string | Optional | Document type: pdf (default) or contract. |
| field_map | string (JSON) | Optional | A coordinate field map that prints the values in their places on the pages. The coordinates relative (0..1) from the top left of the page. |
{ "key", "label", "type", "page", "x", "y", "w", "h", "required" }.
When a signature request is sent with this document, the values of fields at exactly the specified positions. 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}
]'
{
"id": "doc_7Yq",
"object": "document",
"kind": "pdf",
"filename": "agreement.pdf",
"pages": 4,
"bytes": 183221,
"sha256": "a3f1..",
"created_at": 1754000000
}
Templates
Templates are the ready-made contracts (more than 250 templates) with their fillable fields. Signature requests reference them via source.template_id.
List the ready-made templates, with optional filtering by category.
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer · query | Optional | From 1 to 100 (default 20). |
| category | string · query | Optional | Filter by category, such as hr. |
| starting_after | string · query | Optional | The cursor for the next page. |
curl "https://wthaiq.com/api/v1/templates?category=hr" \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
const tpls = await wt.templates.list({ category: 'hr' });
{
"object": "list",
"data": [
{
"id": "tpl_employment",
"object": "template",
"name": "Employment contract",
"category": "hr",
"languages": ["ar"],
"created_at": 1754000000
}
],
"has_more": false,
"next_cursor": null
}
Retrieve a template together with the definition of its fillable fields.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The template ID (tpl_). |
curl https://wthaiq.com/api/v1/templates/tpl_employment \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
const tpl = await wt.templates.retrieve('tpl_employment');
{
"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 Didit (an official document and a live face match), and it is a requirement of the advanced level (AES).
/v1/identity_verificationsRetrieve an identity verification by its ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The identity verification ID (idv_). |
curl https://wthaiq.com/api/v1/identity_verifications/idv_5k \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"id": "idv_5k",
"object": "identity_verification",
"provider": "didit",
"signer": "sgr_9fA2",
"status": "approved",
"level": "aes",
"verification_url": "https://verify.wthaiq.com/i/..",
"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.
Public verification of a document through its reference.
| Parameter | Type | Required | Description |
|---|---|---|---|
| reference | string · path | Required | The public reference, such as WTQ-000123. |
curl https://wthaiq.com/api/v1/verifications/WTQ-000123 \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"object": "verification",
"reference": "WTQ-000123",
"found": true,
"status": "completed",
"integrity": "intact",
"document": {
"title": "Employment contract",
"sha256": "a3f1..",
"format": "pades-lt",
"legal_level": "aes"
},
"signed_at": 1754500000,
"parties": [
{ "name": "A**** M****", "role": "signer" },
{ "name": "C**** W****", "role": "owner" }
],
"qr": "https://wthaiq.com/verify?c=WTQ-000123"
}
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/eventsList the account events, with optional filtering by type.
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer · query | Optional | From 1 to 100 (default 20). |
| type | string · query | Optional | Filter by event type, such as signer.signed. |
| starting_after | string · query | Optional | The cursor for the next page. |
curl "https://wthaiq.com/api/v1/events?limit=10&type=signer.signed" \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"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"
}
Retrieve a single event by its ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The event ID (evt_). |
curl https://wthaiq.com/api/v1/events/evt_2M \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"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
}
Webhook Endpoints
A Webhook endpoint registers a URL that receives real-time notifications of the events you subscribe to. See the guide Webhooks to verify the signature and to retry.
/v1/webhook_endpointsCreate a new Webhook endpoint. The secret value is returned whsec_ once, at creation.
| The field | Type | Required | Description |
|---|---|---|---|
| url | string | Required | The HTTPS URL that receives POST messages. |
| enabled_events | array | Required | The event types subscribed to, such as signature_request.completed. |
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"]
}'
const we = await wt.webhookEndpoints.create({
url: 'https://api.acme.com/hooks/wthaiq',
enabled_events: ['signature_request.completed', 'signer.signed']
});
{
"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
}
List the registered Webhook endpoints.
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer · query | Optional | From 1 to 100 (default 20). |
curl https://wthaiq.com/api/v1/webhook_endpoints \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"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
}
Retrieve a Webhook endpoint by its ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The Webhook endpoint ID (we_). |
curl https://wthaiq.com/api/v1/webhook_endpoints/we_1a \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"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 a Webhook endpoint; events stop being sent to it immediately.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string · path | Required | The Webhook endpoint ID. |
curl -X DELETE https://wthaiq.com/api/v1/webhook_endpoints/we_1a \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Wthaiq-Version: 2026-07-01"
{
"id": "we_1a",
"object": "webhook_endpoint",
"deleted": true
}
The central object of a 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 field | Type | Description |
|---|---|---|
| id | string | The request ID. |
| status | string | draft · sent · partially_signed · completed · declined · expired · canceled. |
| legal_level | string | ses · aes · qes. |
| format | string | The 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. |
| source | object | The source of the document (a template or an uploaded document). |
| signers | array | The signer objects. |
| ordered | boolean | Sequential signing. |
| require_identity | boolean | Identity verification before signing (AES). |
| reference | string · null | The public verification code (WTQ-XXXXXX) on completion. |
| download_url | string · null | The signed PDF URL, which appears on completion. |
| created_at | integer | The Unix timestamp of creation. |
A signing party within a request.
{
"id": "sgr_9fA2",
"object": "signer",
"name": "Ahmed Mohamed",
"email": "ahmed@example.com",
"type": "individual",
"method": "draw",
"require_identity": true,
"order": 1,
"status": "viewed",
"signing_url": "https://sign.wthaiq.com/s/uZ8..",
"viewed_at": 1754000100,
"signed_at": null,
"identity": { "status": "approved", "provider": "didit", "level": "aes" },
"fields": { "job_title": "Software Engineer", "start_date": "2026-08-01" }
}
| The field | Type | Description |
|---|---|---|
| type | string | individual or company. |
| method | string | draw (drawn signature + email OTP) or token (a QES certificate on a hardware token). |
| status | string | pending · sent · viewed · otp_verified · identity_verified · signed · declined. |
| signing_url | string | The hosted or embeddable signing page. |
| identity | object | The identity verification result at require_identity. |
| fields | object | The pre-filled template field values. |
An uploaded PDF file.
{
"id": "doc_7Yq",
"object": "document",
"kind": "pdf",
"filename": "agreement.pdf",
"pages": 4,
"bytes": 183221,
"sha256": "a3f1..",
"created_at": 1754000000
}
| The field | Type | Description |
|---|---|---|
| kind | string | pdf or contract. |
| pages | integer | The page count. |
| bytes | integer | The file size in bytes. |
| sha256 | string | The document's SHA-256 hash. |
A ready-made contract with fillable fields.
{
"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 field | Type | Description |
|---|---|---|
| name | string | The template name. |
| category | string | The template category, such as hr. |
| languages | array | The languages available for the template. |
| fields | array | Field definitions: key, label, type, required. |
The result of a signer's identity verification through Didit.
{
"id": "idv_5k",
"object": "identity_verification",
"provider": "didit",
"signer": "sgr_9fA2",
"status": "approved",
"level": "aes",
"verification_url": "https://verify.wthaiq.com/i/..",
"created_at": 1754000000
}
| The field | Type | Description |
|---|---|---|
| provider | string | The verification provider (didit). |
| signer | string | The associated signer ID. |
| status | string | pending · approved · declined · in_review. |
| level | string | The target legal level. |
The result of a public check of a document's integrity by its reference.
{
"object": "verification",
"reference": "WTQ-000123",
"found": true,
"status": "completed",
"integrity": "intact",
"document": {
"title": "Employment contract",
"sha256": "a3f1..",
"format": "pades-lt",
"legal_level": "aes"
},
"signed_at": 1754500000,
"parties": [
{ "name": "A**** M****", "role": "signer" },
{ "name": "C**** W****", "role": "owner" }
],
"qr": "https://wthaiq.com/verify?c=WTQ-000123"
}
| The field | Type | Description |
|---|---|---|
| reference | string | The public reference (WTQ-/WTH-). |
| found | boolean | Whether the document was found. |
| integrity | string | intact · modified · unknown. |
| parties | array | Parties with partially masked names. |
| qr | string | The public verification page URL. |
An immutable entry in the audit trail.
{
"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 field | Type | Description |
|---|---|---|
| type | string | The event type, such as signer.signed. |
| actor | string | owner · signer · system. |
| ip | string | The actor's IP address. |
| user_agent | string | The actor's user agent. |
A registered URL for receiving events.
{
"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 field | Type | Description |
|---|---|---|
| url | string | The receiving HTTPS address. |
| enabled_events | array | The subscribed event types. |
| status | string | enabled or disabled. |
| secret | string | The signing secret whsec_ to verify the HMAC. |
An API access key (the full secret is not shown after creation).
{
"id": "key_88",
"object": "api_key",
"name": "Production",
"prefix": "sk_9a1b2c3d4e5f6",
"livemode": true,
"created_at": 1754000000,
"last_used_at": 1754500000
}
| The field | Type | Description |
|---|---|---|
| name | string | The key's descriptive name. |
| prefix | string | The visible prefix of the key. |
| livemode | boolean | Whether the key is live. |
| last_used_at | integer · null | Last used (Unix timestamp). |
Legal levels — quick reference
determines the value of legal_level The strength of evidence and the target assurance level. The full detail is on the page Legal standing and trust.
| Level | Description | PAdES format |
|---|---|---|
| ses | Simple electronic signature: drawn signature + mandatory email OTP. | pades-b / pades-t |
| aes | Advanced signature: SES + an identity verified through Didit (an official document and a live face match) that ties the signature to a real person. | up to pades-lt |
| qes | Qualified signature: a digital certificate on a hardware token from a licensed authority (Misr for Central Clearing / MCDR) — the highest legal standing under Egyptian Electronic Signature Law No. 15 of 2004. | up to pades-lta |
| The format | What it adds |
|---|---|
| pades-b | The baseline signature. |
| pades-t | + a trusted timestamp (RFC 3161). |
| pades-lt | + DSS: certificates, OCSP and CRL for long-term preservation. |
| pades-lta | + an archival timestamp — Wthaiq targets this level. |
GET /api/evidence.php?scope=api&doc=<id> (with owner authentication).SubFilter adbe.pkcs7.detached · SHA256withRSA · ESS signingCertificateV2. With QES the token key never leaves the device; a local desktop agent signs (prepare signedAttributes → sign on the device → embed CMS).