VerityProAPI

Overview

VerityPro provides KYC identity verification, address verification, enhanced due diligence (EDD), and transaction monitoring (AML) as modular APIs and SDKs. Each product is independently activatable — your integration only calls the services your compliance programme requires.

KYC
Document capture + biometric liveness with PEP/sanctions screening.
Address Verification
Proof-of-address with geocoding and document matching.
Enhanced Due Diligence
Deep customer risk profiling triggered by TM or rule conditions.
Transaction Monitoring
Real-time AML scoring, velocity rules, and case management.

Base URL

https://api.skylinefare.com

Request format

All requests are JSON (Content-Type: application/json). Authenticate every server-side call with your x-api-key header.

Authentication

VerityPro uses API key authentication. Every request must include both headers below. Retrieve your keys from the Integrations page in the VerityPro portal.

ParameterTypeRequiredDescription
x-api-keystringRequiredYour integration API key. Treat this as a secret — never expose it in client-side code.
IntegrationidUUIDOptionalYour integration UUID. Required only for JWT-authenticated dashboard calls. Not needed when authenticating with x-api-key — the key already identifies your integration.

Key rotation

Rotate keys from the portal under Settings → Integration → Keys → Rotate. When the rotation runs immediately, the new key is displayed once — copy it into your secrets manager before you close the dialog. If your organisation requires approval for key rotation, the request is queued instead and the new key is not shown in that dialog; ask your approver how it will be delivered before you rotate.

Never put your API key in client code
The x-api-key header must only be sent from your server. Mobile and web SDK calls use a short-lived session token minted by your server.

Environments

EnvironmentBase URLNotes
Livehttps://api.veritypro.ai
Portal: https://app.veritypro.ai
Production. Real verifications; billing applies.
Sandboxhttps://api.skylinefare.com
Portal: https://skylinefare.com
Test environment: test documents accepted. Billing runs in Stripe test mode, so there are no real charges.

Each environment has its own API keys. Server-side calls use the base URL directly. The mobile SDKs need it set explicitly: pass apiBaseUrl (iOS and Android VerityOption, Flutter VerityProSDK). It is required: https://api.veritypro.ai for Live, https://api.skylinefare.com for Sandbox. The Web SDK takes the portal origin as baseUrl.

Create KYC Session

Your server creates a verification session and receives back a sessionUrl. Send that URL to your customer — VerityPro hosts the entire document capture and liveness flow with your branding applied. Your API key stays server-side only.

POST/kycintegration/v2/sessions
ParameterTypeRequiredDescription
vendorDatastringRequiredYour internal customer identifier — returned unchanged in every webhook. Use the same value for EDD and Step-Up.
stepsstring[]RequiredSteps to run: 'DOCUMENT', 'BIOMETRIC', 'ADDRESS', 'EDD'. Shortcut: 'DEFAULT' = DOCUMENT + BIOMETRIC. 'COMBINED' = all four.
firstNamestringOptionalCustomer's legal first name — improves name-match accuracy.
lastNamestringOptionalCustomer's legal last name.
dateOfBirthYYYY-MM-DDOptionalPre-fills the document verification step.
ISO2CodestringOptionalCustomer's country of residence (ISO 3166-1 alpha-2, e.g. 'AU').
previousSessionIdUUIDOptionalLink a new session to a prior one (e.g. add ADDRESS after BIOMETRIC was completed).

Response

{ "statusCode": 200, "data": { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "status": "Active", "currentStep": "DOCUMENT", "requestedSteps": ["DOCUMENT", "BIOMETRIC"], "completedSteps": [], "nextAction": { "step": "DOCUMENT", "type": "SDK_CAPTURE", "engineSessionId": "eng_abc123", "sessionUrl": "https://skylinefare.com/verify?s=eng_abc123" } } }

id — v2 session ID. Store this to poll status and for returning-user sessions.
attemptId — unique per evidence submission. Matches kycverification.AttemptId in every decision webhook — use it to correlate polling with webhook delivery.
kycEngineSessionId — null at creation; populated after the document step submits.
Send nextAction.sessionUrl to your customer. Sessions expire in 60 minutes.

Hosted Web Page (v2)

The recommended integration path. Use the same POST /kycintegration/v2/sessions endpoint as Create Session. The response includes nextAction.sessionUrl — redirect your user to that URL or embed it in an iframe. VerityPro renders the full verification flow with your branding. Your API key never touches the browser.

POST/kycintegration/v2/sessions

The session URL is in data.nextAction.sessionUrl in the response.

Redirect (full-page)

window.location.href = data.nextAction.sessionUrl;

Iframe embed + postMessage

<iframe id="vp-frame" src={data.nextAction.sessionUrl} allow="camera; microphone" style="width:100%;height:100%;border:none" /> <script> window.addEventListener('message', (e) => { if (e.data?.type === 'veritypro:complete') { const { status, verificationId } = e.data; // status: 'approved' | 'declined' | 'pending' document.getElementById('vp-frame').remove(); } }); </script>

Poll session state anytime

GET/kycintegration/v2/sessions/{id}

Returns current status, completedSteps, currentStep, attemptId, and kycEngineSessionId. The attemptId matches kycverification.AttemptId in the decision webhook — use it to correlate polling with webhook delivery. No auth header required — the session ID is the capability.

iOS SDK

Add to your Podfile:

# Option A — direct git reference (no spec repo needed): pod 'VerityPro', :git => 'https://github.com/TopRateTransfer-Pty-Ltd/verity-pro-ios.git', :tag => '1.4.0' # Option B — via VerityPro spec repo (add once to your system): # pod repo add veritypro https://github.com/TopRateTransfer-Pty-Ltd/veritypro-podspecs.git # Then use: pod 'VerityPro', '~> 1.4.0'

Then run pod install.

Requirements

  • iOS 17.0+ deployment target
  • Camera and FaceID usage descriptions in Info.plist
  • Session token minted by your server (see Create Session)

Info.plist entries required

<key>NSCameraUsageDescription</key> <string>Required for document capture and liveness check.</string> <key>NSFaceIDUsageDescription</key> <string>Used for biometric authentication.</string>

Result handling

The VerityResult returned in the completion block contains the outcome, completed steps, and any error details including whether the error is recoverable.

Brand customisation (optional)

Pass your logo and primary colour to show your brand inside the verification flow:

let options = VerityOption( apiKey: "YOUR_API_KEY", integrationId: "YOUR_INTEGRATION_ID", ... ) let sdk = VerityProSDK(options: options, brandConfig: VpBrandConfig( primaryColor: "#FF5500", // hex, leading # optional logoUrl: URL(string: "https://yourcompany.com/logo.png") ))

Android SDK

Add the GitHub Packages repository and dependency to your build.gradle:

repositories { maven { url = uri("https://maven.pkg.github.com/TopRateTransfer-Pty-Ltd/veritypro-android-sdk-maven") credentials { username = System.getenv("GITHUB_USER") password = System.getenv("GITHUB_TOKEN") } } } dependencies { implementation("com.example.veritypro:veritypro-sdk:1.4.0") }

Manifest permissions

<uses-permission android:name="android.permission.CAMERA" />

Activity result launcher

Register the launcher in onCreate before the activity is started. Use VerityPro.extractResult(result) to get the typed result.

Brand customisation (optional)

Pass VpBrandConfig to show your logo and colour inside the flow:

val options = VerityOption( apiKey = "YOUR_API_KEY", integrationId = "YOUR_INTEGRATION_ID", ..., brandConfig = VpBrandConfig( primaryColor = "#FF5500", logoUrl = "https://yourcompany.com/logo.png" ) )

Flutter SDK

Dart plugin bridging to the native iOS/Android SDKs — same product coverage. Installed via git dependency (not published to pub.dev).

pubspec.yaml

dependencies: verity: git: url: https://github.com/TopRateTransfer-Pty-Ltd/verity_flutter_sdk.git ref: "1.4.0"

v2 — server-driven (recommended): pass serverSessionId from your backend and mode: VerityMode.serverDriven. The full Dart example is in the code panel.

Brand customisation: pass an optional brandConfig: VpBrandConfig(logoUrl: ..., primaryColor: ...) to show your logo and colour. The logo must be an HTTPS URL.

v1 — legacy: use mode: VerityMode.biometric (or .address / .edd) with preCreatedSessionId.

Web SDK

Install: npm install @veritypro/web-sdk

Presentation modes

ModeDescription
modalOverlay on top of your page
embedMounted into a container element you provide
hostedFull-page redirect to VerityPro hosted URL

Use the embedToken from your server session call. Do not pass your API key to the web SDK.

Optional: modules hint

Pass modules to pre-render the correct verification steps on the welcome screen before the backend session loads. The backend session's requestedSteps always win once fetched — this is a display hint only.

VerityWeb.mount({ embedToken: 'your-embed-token', baseUrl: 'https://your-portal-url.com', modules: ['DOCUMENT', 'BIOMETRIC'], // optional hint branding: { logoUrl: 'https://your-cdn.com/logo.png' }, onResult: (result) => { console.log(result.status, result.sessionId) } });

Reading the Attempt ID

The onSessionEstablished callback fires with the KYC engine session ID once created. The Attempt ID is included in the onResult payload and in every webhook for that session.

KYC Webhooks

VerityPro delivers a webhook to your registered endpoint when a KYC session reaches a terminal state. Configure the URL in Settings → Integration → Webhooks.

Payload fields

ParameterTypeRequiredDescription
EventCodenumberRequiredNumeric event code. 9001=Approved, 9102=Declined, 9105=ManualReview, 7001=started, 7002=submitted, 9301=address approved, 9302=address declined.
ActionstringRequiredHuman-readable outcome: approved | declined | resubmission_requested | expired | review | started | submitted
VendorDatastringRequiredYour internal customer identifier — the same value you passed at session creation
kycverification.IdUUIDRequiredVerityPro verification identifier
kycverification.AttemptIdstringRequiredUnique per evidence submission. Matches the attemptId field in GET /kycintegration/v2/sessions/{id} — use this to correlate webhook decisions with session polling and as your deduplication key.
kycverification.VerificationStatusstringRequiredApproved | Declined | ManualReview | Resubmission | Expired | Processing
kycverification.SessionIdstringRequiredKYC engine session identifier
kycverification.ISO2CodestringOptionalCountry code used in the session
DocumentobjectOptionalDocument details (type, country, expiry) — present on decision webhooks
AddressVerificationobjectOptionalAddress outcome fields — present on address event webhooks (EventCode 9301–9305)

Verify the X-Veritypro-Signature header on every webhook before processing. See Verify Signature for details.

Address SDK

Address verification is triggered through the same SDK as KYC — set mode: .address (iOS) or mode = VerityMode.ADDRESS.name (Android). No separate SDK install is needed.

SDK options for address verification

ParameterTypeRequiredDescription
streetAddressstringRequiredUser's street address to verify
citystringOptionalCity / suburb
stateOrProvincestringOptionalState or province code
postalCodestringOptionalPostcode / ZIP
countrystringRequiredCountry of the address (full name or ISO code)

Address Server API

Add ADDRESS to the steps array when creating a session. This works standalone or combined with KYC in a single session.

POST/kycintegration/v2/sessions
ParameterTypeRequiredDescription
vendorDatastringRequiredYour internal customer identifier
stepsstring[]RequiredInclude 'ADDRESS'. Combine with 'DOCUMENT' and 'BIOMETRIC' for a full KYC + address flow.
firstNamestringOptionalCustomer's first name
lastNamestringOptionalCustomer's last name
dateOfBirthYYYY-MM-DDOptionalUsed for cross-verification
ISO2CodestringOptionalCountry of address (ISO 3166-1 alpha-2)

The response nextAction.sessionUrl takes the customer through the address proof upload step. A webhook fires with event address_completed when done.

Basic EDD Assessment

The Basic EDD assessment is a four-step lifecycle for financial-consistency and source-of-funds checks. Your backend creates the assessment with your API key, the SDK or hosted page captures and attaches the supporting document, then you submit and poll for the verdict. This replaces the older one-step upload and gives you a tracked assessment ID, status, and a machine-readable verdict.

1. Create the assessment

POST/edd/api/v1/edd/basic/assessments
ParameterTypeRequiredDescription
subjectIdstringRequiredYour internal customer identifier
subjectNamestringRequiredCustomer name
employerNamestringOptionalUser-declared employer name (collected in the SDK flow)
idempotencyKeystringOptionalOptional — a repeat returns the original assessment
clientReferencestringOptionalYour reference for reconciliation
transactionSummary.declaredMonthlyIncomenumberRequiredDeclared monthly income (source of funds), &gt; 0
transactionSummary.totalAmountSentnumberRequiredTotal sent over the observation window, &gt;= 0
transactionSummary.periodDaysnumberRequiredObservation window in days, &gt; 0
transactionSummary.transactionCountnumberOptionalNumber of transactions in the period
transactions[]arrayOptionalOptional line-items for credit→balance→transfer correlation
currencyISO 4217Optional3-letter code, default AUD

Returns 201 with assessmentId and status AwaitingDocuments.

2. Attach the document

POST/edd/api/v1/edd/basic/assessments/{assessmentId}/documents

Multipart upload of the supporting income document (payslip, statement, or tax return).

3. Submit

POST/edd/api/v1/edd/basic/assessments/{assessmentId}/submit

Starts the asynchronous check. Returns 202.

4. Poll for the verdict

GET/edd/api/v1/edd/basic/assessments/{assessmentId}

Poll until status reaches a terminal value. The response carries the verdict, findings, and a review recommendation.

{ "assessmentId": "3fa85f64-...", "status": "Completed", "verdict": "Consistent", "reviewRecommended": false, "financialSummary": { "declaredMonthlyIncome": 5000, "verifiedMonthlyIncome": 5100, "totalAmountSent": 12000, "currency": "AUD" }, "findings": [] }

Verdict values: Consistent, Inconsistent, ReviewRequired, UnableToAssess. Status values: Created, AwaitingDocuments, DocumentsReceived, Processing, Completed, ReviewRequired, UnableToAssess, Failed.

A best-effort webhook fires with event basic_edd.affordability.completed when the check resolves. The verdict is also returned synchronously in the submit response.

Trigger EDD

Enhanced Due Diligence (EDD) is triggered when your risk programme identifies a customer requiring deeper scrutiny — typically after a high-risk transaction flag or on a scheduled review cycle. The customer must have an Approved KYC session in the system first.

POST/kycintegration/kyc-verification/trigger-edd?vendorData={your-customer-id}

No request body required. Pass your internal customer identifier as the vendorData query parameter — it must match the value used at KYC onboarding. Returns 200 on success or 404 if no approved KYC session exists for that customer.

EDD can also be included as a step at session creation — pass steps: ["DOCUMENT", "BIOMETRIC", "EDD"] to run it as part of the onboarding flow. A webhook fires with event edd_completed when the case is resolved.

EDD Status

Poll the session state to track EDD progress. The session also receives an edd_completed webhook when the case is resolved.

GET/kycintegration/v2/sessions/{sessionId}

Response (EDD fields)

{ "data": { "id": "3fa85f64-...", "status": "Active", "completedSteps": ["DOCUMENT", "BIOMETRIC"], "currentStep": "EDD", "eddCaseId": "case_abc123" } }

EDD reviews are completed by your compliance team in the VerityPro case management portal.

Process Transaction

Submit transactions to VerityPro's AML engine for real-time risk scoring. Each transaction is checked against velocity rules, sanctions screening, and ML-based anomaly detection. A risk decision is returned synchronously.

POST/transactionprocessing/api/v1/transactions/process

Headers: x-api-key and X-Account-Id. X-Account-Id must equal the account your API key belongs to, or the request is rejected with 401. The integration needs the Transaction Monitoring capability. The body is snake_case and amounts are strings.

ParameterTypeRequiredDescription
transaction_idstringRequiredYour unique transaction reference.
user_idstringRequiredYour internal identifier for the sending customer.
transaction_amountstringRequiredAmount as a decimal string, e.g. 500.00.
transaction_currencyISO 4217Required3-letter currency code, e.g. AUD.
transaction_typeenumOptionalPayment | Remittance | P2PTransfer | Withdrawal | Deposit | OnlinePayment (default Payment).
user_firstname, user_lastnamestringOptionalSender name (improves sanctions screening).
email, phone_number, ipstringOptionalSender contact and network signals for risk scoring.
user_countrystringOptionalSender country (ISO 3166-1 alpha-2).
receiver_fullname, receiver_countrystringOptionalBeneficiary details for remittances.
payment_modestringOptionale.g. bank_transfer, card, wallet.
sessionstringOptionalDevice session token (vpds_...) from the Device SDK.

The full field list (card, billing, shipping, merchant, crypto and custom_fields) is in the OpenAPI spec under All Endpoints.

Response

{ "Id": "TXN-2026-0001", "State": "APPROVE", "FraudScore": 0.04, "RiskLevel": "LOW", "RulesEvaluated": 52, "RulesTriggered": 0, "AppliedRules": [], "RiskIndicators": [], "ScreeningDegraded": false, "HoldReasons": [] }

State is one of APPROVE | REVIEW | CHALLENGE | BLOCK. Treat REVIEW as a hold pending analyst review and BLOCK as a hard stop. When ScreeningDegraded is true a screening stage did not run: the decision is provisional and you must hold funds (see HoldReasons). A 503 means no decision was made; retry.

Step-Up Biometric Authentication

Re-verify a returning user's identity using face liveness + face match against the template enrolled during KYC onboarding. Use this for risk-triggered moments — high-value transactions, new-device logins, suspicious activity — rather than full re-onboarding. The subject must have completed a liveness-verified KYC session with the BIOMETRIC module before step-up is available.

Authentication: x-api-key only (JWT is not accepted on step-up endpoints). The subjectId must exactly match the vendorData value used at KYC onboarding.

1 — Create a challenge

POST/kycintegration/api/v1/step-up/challenges
ParameterTypeRequiredDescription
subjectIdstringRequiredMust equal the vendorData used at KYC onboarding.
riskReasonstringOptionalWhy step-up was triggered, e.g. 'high_value_txn'. For audit trail only.
channelOriginstringOptional'mobile_ios' | 'mobile_android' | 'web'.
alertIdstringOptionalAML alert ID that prompted this step-up — surfaces the biometric outcome on the alert row in your dashboard.

Returns challengeId (your primary reference, valid 300s, max 3 attempts) and hostedUrl — send this link to your customer by SMS, email, or deep-link. VerityPro renders the liveness UI. A 422 means the subject has no enrolled biometric template — route to full KYC first.

2 — Get AWS Rekognition credentials (native SDK path only)

POST/kycintegration/api/v1/step-up/challenges/{challengeId}/begin-liveness

Only needed for the native mobile SDK path (you embed the AWS Face Liveness widget directly). Returns livenessSessionId, region, and short-lived AWS credentials — pass all of them to the AWS Amplify Face Liveness widget in your app. Skip this step when using the hosted URL path.

3 — Complete after liveness (native SDK path only)

POST/kycintegration/api/v1/step-up/challenges/{challengeId}/complete
ParameterTypeRequiredDescription
livenessSessionIdstringRequiredThe AWS Face Liveness session ID from step 2.
selfieImageB64stringOptionalBase64-encoded JPEG/PNG selfie captured by the AWS SDK. Optional on the hosted path — the engine fetches it directly from the Rekognition result.

Verdicts

verdictAction
PassedIdentity confirmed — proceed with the action
ManualReviewHold pending operator review; a webhook follows
FailedDeny the action; retry available while attemptCount < 3
NoEnrolledTemplateSubject has no enrolled face — route to full KYC

Webhook Event Types

VerityPro delivers events to your registered HTTPS endpoint. Configure the URL and secret in Settings → Integration → Webhooks.

EventTrigger
KycDecision (EventCode 9001)KYC Approved
KycDecision (EventCode 9102)KYC Declined
KycDecision (EventCode 9105)KYC ManualReview — hold pending operator review
KycDecision (EventCode 9301–9305)Address verification outcome — check VerificationStatus
kyc.session.expiredKYC session timed out without completion
step_up.completedStep-up biometric finished — check verdict: Passed | Failed | ManualReview
step_up.failedStep-up explicitly failed or max attempts reached
step_up.manual_reviewStep-up requires operator review before verdict
step_up.expiredStep-up challenge expired (TTL 300s) without completion
transaction.risk.flaggedTransaction flagged REVIEW by TM engine — hold pending review
transaction.blockedTransaction blocked DECLINED by TM engine — hard block

Your endpoint must return HTTP 200 within 10 seconds. Failed deliveries are retried with exponential backoff for up to 24 hours.

Verify Webhook Signature

Every webhook request carries two headers: X-Veritypro-Signature, an HMAC-SHA512 signature, and X-Veritypro-Timestamp, the unix epoch seconds the payload was signed at. Always verify both before processing the payload.

The signature is computed as HMAC-SHA512(webhookSecret, "{timestamp}.{rawBody}") — the timestamp header value, a literal dot, then the raw request body bytes before JSON parsing. It is encoded as lowercase hex, 128 characters, with no prefix.

Sign the timestamped payload, not the body alone
The timestamp is part of the signed input. Computing the HMAC over the body by itself will never match. Reject any delivery whose timestamp is more than 5 minutes from your own clock in either direction — that bounds how long a captured request stays replayable, but it does not make deliveries unique, so still key your own processing on the event id.
Use raw body, not parsed JSON
JSON serialisation is not deterministic. Always compute the HMAC over the raw bytes received from the network, not over a re-serialised object.

All Endpoints

Every public endpoint, generated from the OpenAPI spec. A Postman collection is generated from the same spec, with Sandbox and Live environments.

Hosted Verification (v2)

POST/kycintegration/v2/embed/mintMint an embed token (S2S)x-api-key + Integrationid
POST/kycintegration/v2/embed/exchangeExchange embed token for a session bearer (browser)none
POST/kycintegration/v2/sessionsCreate a verification session (S2S)x-api-key
GET/kycintegration/v2/sessions/{id}Get session state (S2S)x-api-key + Integrationid
POST/kycintegration/v2/sessions/{id}/steps/{step}/completeMark a step complete (hosted SDK internal)x-api-key + Integrationid

KYC Verification

POST/kycintegration/kyc-verification/update-kyc-verificationSubmit captured ID document images (DOCUMENT step)Bearer
POST/kycintegration/kyc-verification/add-kyc-verificationCreate a KYC session (legacy v1)x-api-key + Integrationid

Address Verification

POST/addressverification/address-verification/add-verificationCreate an address verification (S2S or hosted flow)x-api-key + Integrationid

Enhanced Due Diligence

POST/edd/api/v1/edd/basic/screenBasic EDD screen (S2S)x-api-key + Integrationid
POST/kycintegration/kyc-verification/trigger-eddTrigger EDD for a verified customerx-api-key
POST/edd/api/v1/edd/basic/assessmentsCreate a Basic EDD assessmentx-api-key
POST/edd/api/v1/edd/basic/assessments/{assessmentId}/documentsAttach a supporting documentx-api-key
POST/edd/api/v1/edd/basic/assessments/{assessmentId}/submitSubmit the assessment for processingx-api-key
GET/edd/api/v1/edd/basic/assessments/{assessmentId}Get assessment status and verdictx-api-key

Step-Up Authentication

POST/kycintegration/api/v1/step-up/challengesCreate a step-up challengex-api-key
POST/kycintegration/api/v1/step-up/challenges/{challengeId}/begin-livenessBegin the liveness check (native integration)x-api-key
POST/kycintegration/api/v1/step-up/challenges/{challengeId}/completeComplete the challengex-api-key

AML Transaction Monitoring

POST/transactionprocessing/api/v1/transactions/processProcess a transaction (AML risk decision)x-api-key + X-Account-Id

Device Intelligence

POST/aml-intelligence/api/v1/device/sessionsCreate a device sessionnone

Result Types

VerityOutcome

ValueMeaning
approvedAll required modules passed. Customer is verified.
pendingManualReviewRequires analyst review — do not approve or reject automatically.
rejectedVerification failed. Check VerityErrorCode for reason.
cancelledUser exited the SDK before completing.
failedTechnical error. Check recoverable flag before re-launching.

VerityVerificationError

ParameterTypeRequiredDescription
codeVerityErrorCodeRequiredNamed error code, e.g. DOCUMENT_EXPIRED
messagestringRequiredHuman-readable error description
recoverablebooleanRequiredTrue if re-launching the SDK may succeed
recommendedActionstringOptionalUX copy to show the user

Error Codes

HTTP errors use standard status codes. The response body contains a typed error payload.

StatusMeaning
400Bad Request — missing or invalid parameters
401Unauthorized — API key missing or invalid
403Forbidden — integration disabled or insufficient permissions
404Not Found — session or resource does not exist
409Conflict — duplicate request or resource already exists
422Unprocessable — request is well-formed but semantically invalid
429Rate Limited — slow down and retry after the Retry-After header
500Internal Error — transient; safe to retry with backoff

Error response body

{ "error": "SESSION_NOT_FOUND", "message": "The session token is invalid or has expired.", "traceId": "req_abc123" }