Skip to content
Developers · Changelog

Release notes — Everything new in the API as they happen.

The Wthaiq API evolves continuously without disrupting your integration, and the version is pinned with a dated header Wthaiq-Version: 2026-07-01: changes non-breaking — such as a new endpoint, an optional field or an event type — ship continuously on your same version, while changes that are breaking come in a new dated version that does not apply to you until you choose to upgrade to it yourself. This page documents every change with its date and its tag.

Read the documentation
Current stable version: v1 · 2026-07-01
The pinned dated version Wthaiq-Version: 2026-07-01
AddingChangeSecurity
AddingFix
Adding
ChangeDiscontinued
Current stable version · v1
Color and type — and impact on your integration

Tag guide

Every change in the log is tagged with its color and its type, so you can read its impact on your integration at a glance.

Adding Change Fix Deprecation Security
Timeline

Versions Newest first.

The timeline covers the stable v1 release and its updates, followed by the beta releases that preceded it, with their exact dates and tags.

English error messages and clearer error fields
  • AddingError messages are in English with the request header Accept-Language: en or the parameter ?lang=en; Arabic stays the default, and error codes do not change.
  • FixThe path /en/api/v1/… now works exactly like /api/v1/… , and its error messages are in English.
  • Addingupgrade_url is now a field in the errors 402 plan_required and 402 plan_expired, and verify_url is a field in the error 403 kyb_required, and max_signers is a field in the error 400 too_many_signers.
  • ChangeGET /v1/verifications/{reference} for an unknown reference returns a 404 error in the standard format with the code not_found, instead of a body that looks like a success response.
  • FixGET /v1/webhook_endpoints now returns next_cursor and accepts starting_after, so you can reach every endpoint page by page.
  • FixThe field docs in GET /v1 points to the documentation in the developer portal.
Matching the signer's name with their identity document
  • AddingAfter identity verification, we match the name on the signer's document with the name sent in the request. When they differ, signing is held until you decide, and you receive the event signer.identity_match_hold then signer.identity_match_decided after the decision.
  • AddingA new endpoint for the decision: POST /v1/signers/{id}/identity_match with the value approve or reject, plus an “Identity review” page in the developer console with a new “Identity reviewer” role.
  • AddingThe signer object carries identity.name_match with the match state and both names, and from the same page you can choose “Record the difference only” instead of holding signing.
Developer accounts and yearly plans
  • ChangeThe developer console is now a separate product with its own developer account, created from its sign-up page and not linked to Wthaiq platform accounts in sign-in, data or balances.
  • ChangeLive sending requires a paid yearly plan and a verified company; otherwise the API returns 402 plan_required or 402 plan_expired or 403 kyb_required. Test keys remain free, within daily limits.
  • ChangeEvery signer on a live request counts as one send from your annual plan balance, with a maximum of five signers per request. Once it runs out, the overage is charged to the wallet at your plan's rate, and identity verification is always charged to the wallet. If the balance isn't enough, the error returned is 402 insufficient_balance and the request is not created.
  • AddingThe API returns 403 plan_feature_unavailable when a request asks for a capability your plan does not include, with the fields feature and required_plan and upgrade_url.
  • ChangeThe endpoints GET /v1/usage and GET /v1/balance now return amounts as objects in your wallet currency, together with the plan and its prices, and no longer return the keys amount_egp and month_spent_egp and send_egp. The field cost in a session is now an object with the amount, currency and source.
  • DeprecationThe free live requests that were available before account verification have been removed; the field trial remains on older requests only.
Identity review events
  • AddingThree new events to follow a signer identity confirmation before it is approved: signer.identity_in_review and signer.identity_resubmission_requested and signer.identity_declined. Each event fires once per state change.
  • ChangeAdded the field identity.verification_id to the object signer, and the values were extended for the fields identity.status and identity_verification.status.
Test keys
  • AddingTest keys are back, with the prefixes sk_test_ and pk_test_ alongside the live keys sk_ and pk_. The key type is chosen when the key is created, and the livemode in every object and event shows which of the two keys created it.
  • ChangeA test key charges nothing to your balance and sends no invitation, reminder or copy to anyone; its signers are limited to your account's email or number and those of your team members.
  • ChangeA test key is limited to the simple signature ses without identity verification; no evidence record is sealed for its requests, and it does not emit the events document.sealed and verification.created.
  • ChangeTest events are delivered to webhook endpoints created with a test key via POST /v1/webhook_endpoints only.
Test mode removed — key format unified
  • Substantive changeThe two-environment system was removed sk_live_/sk_test_. Every secret key now follows one unified format: the prefix sk_ followed by 40 hexadecimal characters, and the key is live from the moment it is created; there is no separate test mode, and the field livemode equals true always. Note (2026-09-26): Test keys were later brought back; see the update at the top of the log.
  • AddingPublishable keys with the prefix pk_ Safe to expose in the browser: locked to specific domains through allowed_origins, and limited to a fixed set of paths (templates, signature requests, signers, flows) with writes to templates/signers/flows blocked.
  • SecurityEvery API call — with any key type — is genuinely charged against your prepaid balance: a price per signature request, plus an additional price per signer who requires identity verification. There is no test environment exempt from billing. Note (2026-09-26): This no longer applies to test keys since they were brought back; see the update at the top of the log.
Stable version v1
  • AddingThe Signature Requests API was released publicly at the path POST /v1/signature_requests with the full lifecycle (draft then sent then completed) and the endpoints send and cancel and reminders and download and certificate.
  • AddingWebhooks signed through the header Wthaiq-Signature (HMAC-SHA256 in t=..,v1=..) with a 300-second tolerance window and escalating retries for up to 24 hours.
  • AddingAPI keys in the two forms sk_live_ and sk_test_, and the Webhook signing secret whsec_; test mode does not send real email and does not issue legal certificates. Note (2026-07-26): This two-environment system was removed later — see the top of the changelog.
  • AvailableOfficial SDKs: wthaiq/wthaiq-php (PHP) · wthaiq (Node.js) · wthaiq (Python) — they pin the version header by default and follow SemVer. Note: These packages were published at the official launch, together with the two in-app signing libraries (iOS · Android); install commands are on the official libraries page.
  • Changebecame Wthaiq-Version: 2026-07-01 is the default dated version for all new accounts, with the header Wthaiq-Request-Id in every response.
  • SecurityTLS 1.2 or higher was made mandatory, and rotation of the Webhook secret was made available whsec_ from the dashboard, with no service interruption.
Contract templates beta
  • AddingTwo template endpoints: GET /v1/templates and GET /v1/templates/{id} with the field definitions (key and label and type and required).
  • AddingCreate a signature request directly from a template via source.type = "template" passing the field values in signers[].fields.
  • FixFixed the computation of default field values when the object is absent fields from the request body.
Public verification by reference number beta
  • AddingThe public verification endpoint by reference number: GET /v1/verifications/{reference} (prefixes WTQ- and WTH-) without authentication, to check the integrity of the document and its parties.
  • AddingField integrity with the values intact and modified and unknown in the object verification, with the names of the parties masked.
  • AddingEvent verification.created to the Webhooks event list.
Embedded signing sessions beta
  • AddingWhite-label embedded signing sessions: POST /v1/signers/{id}/signing_session Issues a short-lived signing link or session token for embedding inside your app.
  • ChangeAdded the field signing_url to the object signer to support the hosted and the embedded page through the same field.
  • FixStrict adherence of embedded tokens to expires_at and invalidate it as soon as signing is completed or declined.
Identity verification (AES) through a specialized identity-verification provider beta
  • AddingIdentity verification for the advanced level (AES) through a specialized identity-verification provider — the object identity_verification and the endpoint GET /v1/identity_verifications/{id} (official document + live face match).
  • AddingRequirement require_identity at the request and signer levels, and the two events signer.otp_verified and signer.identity_verified.
  • AddingSupport legal_level = "aes" which ties the signature to a verified real person before the signing page opens.
PAdES-LT and DSS for token signatures beta
  • AddingSeal pades-lt with DSS/LTV on token signatures (embedded certificates and CRLs) for long-term preservation and for verification without contacting the issuing authority.
  • Changebecame format = "pades-lt" The default value for requests at the level aes instead of pades-t.
  • AddingEvent document.sealed Fired when the request's evidence record is sealed after all signatures are complete.
Platform fundamentals (first public beta) beta
  • AddingAn RFC 3161 timestamp on the evidence record of every completed request, to prove the moment of sealing independently.
  • ChangeAll endpoints share a single error envelope { error: { type, code, message, param, request_id } } with standard HTTP codes (400/401/402/409/422/429).
  • AddingSupport for the header Idempotency-Key on requests POST (stored for 24 hours) to make retries safe.
  • AddingThe rate limit is 100 requests per 10 seconds, with the headers X-RateLimit-Limit and Remaining and Reset, and a 429 code accompanied byRetry-After.
  • DeprecationDeprecation of the old undated preview path /v1/preview in favor of the new dated version; the endpoint will be removed in a later dated version.
Versioning policy

How we ship changes without breaking your integration.

We follow date-based versioning. The behavior of your pinned version never changes through a breaking change — you alone decide when to upgrade it.

Breaking changes

Require a new dated version

  • Removing an endpoint, a field or a value enum, or renaming it.
  • Changing the type of an existing field (for example from string to integer).
  • Adding a new required parameter (required) to an existing request.
  • Tightening validation rules so that requests previously accepted are now rejected.
  • Changing the default semantics of a response, or the order of the items in a list.

Non-breaking changes

ship continuously on your same version

  • Adding an entirely new endpoint.
  • Adding a new field Optional into a response body.
  • Adding a value enum new (handle unknown values gracefully).
  • Adding a new Webhook event type to the list.
  • Adding a new optional parameter to an existing request.
The deprecation window: We announce any deprecation in this changelog with a "Deprecation" tag, and we send the header Wthaiq-Deprecation on the responses concerned, and we keep the old behavior working for at least 6 months before removing it in a new dated version — leaving enough time to upgrade safely.

Pin the version by sending the header Wthaiq-Version with every request. If you do not send it, the last dated version pinned to your account is used (or the latest default version). The behavior of your pinned version never changes through a breaking change. Example:

pin-version.sh
curl https://wthaiq.com/api/v1/signature_requests \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"

# The response returns the version actually used in the header:
# Wthaiq-Version: 2026-07-01
# Wthaiq-Request-Id: req_9f2a1c
Upgrade deliberately: When you are ready to adopt a newer dated version, review its differences in this changelog, try it first with a small request on your account (there is no separate test key — the request is real and billed), then switch the value of Wthaiq-Version in production. There is no need to upgrade all at once — each integration upgrades at its own pace.
From the changelog — to the documentation

Ready to build your integration?

Start from the full API documentation, pin your dated version, and subscribe to receive every update as it ships.