Repository navigation
fix(verification): match the API's session, retrieve and webhook shapes - #64
Merged
Merged
Conversation
- DocumentType.NATIONAL_ID sends national_id, the value the API accepts;
ID_CARD is kept as a deprecated alias that now sends the same value.
- createVerificationSession accepts and returns chip_policy, stops sending
redirect_url, external_id, customer_id and metadata (never accepted by the
API; now deprecated), and is never retried automatically.
- A used-up monthly verification allowance throws VerificationLimitError
with its details.
- Session poll, retrieve and document types follow the served responses:
epoch-millisecond timestamps, age_range, verification_mode,
document_evidence, step_progress, chip_policy, capture, the full set of
document fields, and the document_required status.
- New getVerification(id) and getVerificationConfig({ country, region }).
- WebhookEventType gains verification.completed, minor.detected,
csam.detected and csam.critical; typed delivery payloads; nullable
last_triggered_at and last_error; verifyWebhookSignature for the
X-Tuteliq-Signature-V2 header.
lena-sabadina
approved these changes
Nov 8, 2026
lena-sabadina
left a comment
Collaborator
There was a problem hiding this comment.
Reviewed verification and webhook changes. Merged main in and unified SpeakerStance; CI is green and the full suite passes on the combined tree.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes for users
DocumentType.NATIONAL_ID(national_id) is the national ID card value the API accepts.DocumentType.ID_CARDused to sendid_card, which the API rejects with a 400; it is kept as a deprecated alias that now sendsnational_id, so existing code starts working without changes.createVerificationSessionacceptschip_policy(optional|required|instead_of_photo) and returns it. It is never retried automatically: a retry after a lost response would create a second session and, on plans with a verification allowance, take a second unit. On a timeout, create a new session yourself.VerificationLimitError(402,VERIFY_11014) is thrown when the monthly verification allowance is used up, withlimitDetails(period,next_period_start,included_per_month,buy_credits_url). Previously this surfaced as a genericTuteliqError.created_at/expires_atare epoch milliseconds (were typed as strings), plusverification_mode,document_evidence,step_progress,chip_policy,capture,result.age_range,result.document_evidenceand the full set of document fields (first_name,last_name,issue_date,nationality,chip_verified,national_idand more). Fields the poll never returns (barcode,document_authenticity, requiredface_match.distance,mrz_*) are no longer typed as present.date_of_birth,failure_reasonsandcapturearrive only on the first authenticated poll after the session completes or fails. This is now documented on the method, the types and the README, with theverification.completedwebhook as the push alternative.VerificationSessionStatus.DOCUMENT_REQUIREDadded.CANCELLEDis deprecated: the API never returns it (a cancelled session reads asexpired).getAgeVerificationnow returnsAgeVerificationRetrieveResult(noageorface_confidence, which that route never returns).IdentityRetrieveResultno longer declaresfull_name,date_of_birth,document_type,country_code, which that route never returns.getVerification(id)(GET /verify/{id}, includes the age) andgetVerificationConfig({ country, region })(which check a user in that market gets under this key, and the age threshold).WebhookEventTypegainsVERIFICATION_COMPLETED,MINOR_DETECTED,CSAM_DETECTED,CSAM_CRITICAL. NewWebhookPayload/WebhookEventData/VerificationWebhookDatatypes (data.verificationis optional: it is present onverification.completedfrom a session).Webhook.last_triggered_atandlast_errorare nullable.verifyWebhookSignature(rawBody, header, secret, { toleranceSeconds = 300 })verifies theX-Tuteliq-Signature-V2header (t=<unix>,v1=<hex HMAC-SHA256 of "t.body">): constant-time comparison via Web Crypto, rejects timestamps outside the window in either direction, accepts a string or raw bytes, works in Node 18+, browsers and edge runtimes.ErrorCodegains the verification codes.Deprecated create fields
redirect_url,external_id,customer_idandmetadataare marked@deprecatedand no longer sent. The API's create route reads onlymode,document_typeandchip_policyand ignores anything else without an error, so dropping them changes nothing on the server; it only stops implying they take effect (and stops sending caller metadata that goes nowhere). The redirect URL is a dashboard verification setting. The fields stay on the input type so existing code still compiles.Type-level changes to note for the release
Removing fields that never arrived (retrieve results,
barcode/document_authenticityon the session result) and changing poll timestamps fromstringtonumbercan surface compile errors in code that read them. Every such read wasundefined(or a number) at runtime already.Out of scope by design: the device-side session routes and direct multipart submit routes, which need a capture client and do not belong in a server SDK.
Bugs: failing tests first, then the fix
Reproductions run on unmodified
main(one test per bug):Type reproduction on
main: a session poll and an age retrieve exactly as the API serves them do not typecheck:After the fix, the same assertions (now in
tests/verification.test.ts):plus 19
verifyWebhookSignaturetests (a known vector, raw bytes, array header, modified body, wrong secret, swapped timestamp, both edges of the tolerance window, custom tolerance, malformed headers, legacy body-only signature, empty secret). The served shapes typecheck with no errors (tscexit 0).Checks
npm run build: cleannpx vitest run: 180 passed (146 before; 34 new intests/verification.test.ts, existing verification tests updated where they asserted the old behaviour)Closes #59