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.
Wthaiq-Version: 2026-07-01
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.
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.
- AddingError messages are in English with the request header
Accept-Language: enor 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. - Adding
upgrade_urlis now a field in the errors402 plan_requiredand402 plan_expired, andverify_urlis a field in the error403 kyb_required, andmax_signersis a field in the error400 too_many_signers. - Change
GET /v1/verifications/{reference}for an unknown reference returns a 404 error in the standard format with the codenot_found, instead of a body that looks like a success response. - Fix
GET /v1/webhook_endpointsnow returnsnext_cursorand acceptsstarting_after, so you can reach every endpoint page by page. - FixThe field
docsinGET /v1points to the documentation in the developer portal.
- 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_holdthensigner.identity_match_decidedafter the decision. - AddingA new endpoint for the decision:
POST /v1/signers/{id}/identity_matchwith 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_matchwith the match state and both names, and from the same page you can choose “Record the difference only” instead of holding signing.
- 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_requiredor402 plan_expiredor403 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_balanceand the request is not created. - AddingThe API returns
403 plan_feature_unavailablewhen a request asks for a capability your plan does not include, with the fieldsfeatureandrequired_planandupgrade_url. - ChangeThe endpoints
GET /v1/usageandGET /v1/balancenow return amounts as objects in your wallet currency, together with the plan and its prices, and no longer return the keysamount_egpandmonth_spent_egpandsend_egp. The fieldcostin 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
trialremains on older requests only.
- AddingThree new events to follow a signer identity confirmation before it is approved:
signer.identity_in_reviewandsigner.identity_resubmission_requestedandsigner.identity_declined. Each event fires once per state change. - ChangeAdded the field
identity.verification_idto the objectsigner, and the values were extended for the fieldsidentity.statusandidentity_verification.status.
- AddingTest keys are back, with the prefixes
sk_test_andpk_test_alongside the live keyssk_andpk_. The key type is chosen when the key is created, and thelivemodein 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
seswithout identity verification; no evidence record is sealed for its requests, and it does not emit the eventsdocument.sealedandverification.created. - ChangeTest events are delivered to webhook endpoints created with a test key via
POST /v1/webhook_endpointsonly.
- Substantive changeThe two-environment system was removed
sk_live_/sk_test_. Every secret key now follows one unified format: the prefixsk_followed by 40 hexadecimal characters, and the key is live from the moment it is created; there is no separate test mode, and the fieldlivemodeequalstruealways. 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 throughallowed_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.
- AddingThe Signature Requests API was released publicly at the path
POST /v1/signature_requestswith the full lifecycle (draftthensentthencompleted) and the endpointssendandcancelandremindersanddownloadandcertificate. - AddingWebhooks signed through the header
Wthaiq-Signature(HMAC-SHA256 int=..,v1=..) with a 300-second tolerance window and escalating retries for up to 24 hours. - AddingAPI keys in the two forms
sk_live_andsk_test_, and the Webhook signing secretwhsec_; 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-01is the default dated version for all new accounts, with the headerWthaiq-Request-Idin 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.
- AddingTwo template endpoints:
GET /v1/templatesandGET /v1/templates/{id}with the field definitions (keyandlabelandtypeandrequired). - AddingCreate a signature request directly from a template via
source.type = "template"passing the field values insigners[].fields. - FixFixed the computation of default field values when the object is absent
fieldsfrom the request body.
- AddingThe public verification endpoint by reference number:
GET /v1/verifications/{reference}(prefixesWTQ-andWTH-) without authentication, to check the integrity of the document and its parties. - AddingField
integritywith the valuesintactandmodifiedandunknownin the objectverification, with the names of the parties masked. - AddingEvent
verification.createdto the Webhooks event list.
- AddingWhite-label embedded signing sessions:
POST /v1/signers/{id}/signing_sessionIssues a short-lived signing link or session token for embedding inside your app. - ChangeAdded the field
signing_urlto the objectsignerto support the hosted and the embedded page through the same field. - FixStrict adherence of embedded tokens to
expires_atand invalidate it as soon as signing is completed or declined.
- AddingIdentity verification for the advanced level (AES) through a specialized identity-verification provider — the object
identity_verificationand the endpointGET /v1/identity_verifications/{id}(official document + live face match). - AddingRequirement
require_identityat the request and signer levels, and the two eventssigner.otp_verifiedandsigner.identity_verified. - AddingSupport
legal_level = "aes"which ties the signature to a verified real person before the signing page opens.
- AddingSeal
pades-ltwith 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 levelaesinstead ofpades-t. - AddingEvent
document.sealedFired when the request's evidence record is sealed after all signatures are complete.
- 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-Keyon requestsPOST(stored for 24 hours) to make retries safe. - AddingThe rate limit is 100 requests per 10 seconds, with the headers
X-RateLimit-LimitandRemainingandReset, and a 429 code accompanied byRetry-After. - DeprecationDeprecation of the old undated preview path
/v1/previewin favor of the new dated version; the endpoint will be removed in a later dated version.
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
stringtointeger). - 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
enumnew (handle unknown values gracefully). - Adding a new Webhook event type to the list.
- Adding a new optional parameter to an existing request.
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:
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
Wthaiq-Version in production. There is no need to upgrade all at once — each integration upgrades at its own pace. Ready to build your integration?
Start from the full API documentation, pin your dated version, and subscribe to receive every update as it ships.