openapi: 3.2.0 info: title: OTP Recovery OTP Recover (Sync flow) API version: 1.0.0 description: API for initiating OTP verification for order recovery flows after declined Riskified decisions. servers: - url: https://otp.self-veri.com/recover/v1/otp description: Production environment - url: https://otp-sandbox.self-veri.com/recover/v1/otp description: Sandbox environment tags: - name: OTP Recover (Sync flow) description: Operations for initiating and verifying one-time password recovery requests. paths: /initiate: post: tags: - OTP Recover (Sync flow) parameters: - $ref: '#/components/parameters/RiskifiedShopDomain' - $ref: '#/components/parameters/RiskifiedSignature' - $ref: '#/components/parameters/ContentType' - $ref: '#/components/parameters/Accept' summary: Initiate OTP description: 'Triggers an OTP SMS to the customer if the order is eligible for recovery. This call should be triggered from the backend after receiving a “declined” response and that the order is eligible for OTP process from /api/decide. The response will provide the widget token which is the JWT (JSON Web Token) for the OTP widget.' operationId: initiateOtp requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/OtpInitiateRequest' example: id: '12345' challenge_access_token: e1d29e6a-c287-452d-8c87-9b4a242d60a1 localization_language: en-US contact_details: support@demo-shop.example channel_method: channel_type: Sms sender_name: Demo Merchant responses: '200': description: Widget token successfully returned content: application/json: schema: $ref: '#/components/schemas/OtpInitiateResponse' example: widgetToken: lkdjflskdjflskjdflkjsdflkj '400': description: "Bad Request\n\n Possible values:\n\n - \"Bad request: Order state is not eligible for recovery\"\n\n - \"Bad request: Recovery eligibility duration has already expired\"" content: application/json: schema: type: string example: 'Bad request: Order state is not eligible for recovery' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/error_response' example: value: error: message: 'Failed verifying request: ''X-RISKIFIED-HMAC-SHA256'' header is either missing or incorrect' '403': description: 'Unauthorized request: Order has already passed the recovery flow' content: application/json: schema: type: string example: 'Unauthorized request: Order has already passed the recovery flow' '500': description: There was an internal server error. content: application/json: schema: type: string example: There was an internal server error. components: schemas: OtpInitiateResponse: type: object properties: widgetToken: type: string description: The JWT (JSON Web Token) for the OTP widget error_response: type: object properties: error: $ref: '#/components/schemas/error' error: type: object properties: message: type: string description: Error message code: type: string description: Error code details: type: string description: Error details OtpInitiateRequest: type: object properties: id: type: string description: The unique identifier for the order challenge_access_token: type: string minLength: 32 description: 'A unique token generated by the merchant. It is used to validate that the order matches the OTP after a successful OTP verification. This is critical to ensure that users cannot tamper with the OTP verification process. The token has to be at least 32 characters long and hard to guess - we recommend on using UUID' localization_language: type: string enum: - en-US - es-ES - fr-FR description: "The widget localization language.\nThe language codes currently supported:\n* “en-US” (English US)\n* “es-ES” (Spanish Spain)\n* “fr-FR” (French France)\n\n Contact your Integration Engineer for instructions on expanded language support." contact_details: type: string description: The merchant’s support contact email channel_method: $ref: '#/components/schemas/channel_method' description: OTP channel details required: - id - challenge_access_token - localization_language - channel_type - sender_name channel_method: type: object properties: channel_type: type: string enum: - Sms description: The OTP sending medium - currently only 'Sms' (case-sensitive) is available sender_name: type: string description: The name of the sender (merchant) that will appear in the SMS required: - channel_type - sender_name parameters: Accept: name: accept in: header required: true schema: type: string enum: - application/vnd.riskified.com; version=2 description: 'Specify the version of the API to target. For example, to target the latest version of the API, use the following: `application/vnd.riskified.com; version=2`' RiskifiedShopDomain: name: x-riskified-shop-domain in: header required: true schema: type: string example: merchant.example.com description: The merchant shop domain registered with Riskified. RiskifiedSignature: name: x-riskified-hmac-sha256 in: header required: true schema: type: string example: b1946ac92492d2347c6235b4d2611184 description: 'Verification hash for the Request. Generated by performing an SHA256 encryption on the request''s POST body and calculating the HMAC hash of the result using your Riskified authentication token. Please use UTF8 encoding.' ContentType: name: content_type in: header required: true schema: type: string enum: - application/json description: 'As payloads are sent to Riskified in JSON format, value should be: `application/json`' x-samples-languages: - json - shell - javascript - python - node x- explorer-enabled: false x-provenance: method: searched source: https://developers.riskified.com/reference harvested: '2026-10-14' tool: harvest-readme-openapi.py note: Assembled verbatim from the OpenAPI definition ReadMe embeds in each operation page of the provider's developer portal; paths and components merged by API title, nothing authored. assembled_from: - https://developers.riskified.com/reference/otp-initiate.md merge: pages: 1 deduped: 0 conflicts_kept_first: 0