> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.withpersona.com/2020-05-18/relay-gateway-service-usage/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.withpersona.com/_mcp/server. # Usage > Make HTTP requests to the Relay Gateway Service. The gateway exposes three endpoints that map directly to the Relay Server SDK methods. You can use any HTTP client in any language. > **Note** > > The URL paths below are relative — the base URL is wherever you've deployed your gateway instance. > **Note** > > Looking for full API documentation? See the [Gateway Service Reference](/relay-gateway-service-reference). #### See every step as a gateway request ## Step 1 — Create a Relay session Call this endpoint before starting your selected client-side integration. Store the returned Relay token and Relay secret on your server — never expose the Relay secret to the client. Return the Relay session access token to your client. > **Recommended: Encrypt your claim payload** > > We recommend generating an asymmetric key pair so that the claim payload is encrypted and only decryptable by your server. ```bash POST /relays ``` ```json // Request { "claim-type": "live_human_presence", "encryption-key-pem": "", // pass null to opt out of encryption "sandbox": false // pass true to create a sandbox relay } ``` ```json // Response { "relay-token": "", "relay-secret": "", "relay-session-access-token": "" } ``` Pass the Relay session access token to the [Embedded Widget](/relay-widget-usage), [Hosted Flow](/relay-hosted-flow), [iOS SDK](/relay-ios-sdk), or [Android SDK](/relay-android-sdk). ### Opting in to sandbox Set `sandbox` to `true` to create the relay in the [sandbox environment](/relay-sandbox): ```json // Request — sandbox { "claim-type": "live_human_presence", "encryption-key-pem": null, "sandbox": true } ``` The `sandbox` field is optional and defaults to `false`. Issue the Privacy Pass in Step 2 with a **sandbox API key**, so the relay and the pass belong to the same environment. Requires gateway image `v0.1.2` or later — earlier images ignore the field. ## Step 2 — Issue a Privacy Pass A Privacy Pass is the billing unit for Relay. It is billed on creation and redeemed to fetch the claim result. Issuance uses your API key and identifies your platform to Persona for billing. Redemption uses the Privacy Pass token instead of your API key. Each Privacy Pass can only be redeemed once. Store `privacy-pass-token` on your server and map it to the corresponding Relay session. This endpoint depends only on the claim type — it is not tied to a specific relay, so it can be called at any time, even before the relay is created. One Privacy Pass must exist before you can redeem any relay. This step requires your Persona API key — you can find it in the [Persona Dashboard under API Keys](https://docs.withpersona.com/api-keys). > **Issue with a key from the same environment as your relay** > > The environment is determined by the API key you issue with. A sandbox relay needs a sandbox API key and a production relay needs a production API key — if they don't match, the pass won't be able to redeem the claim. See [Sandbox](/relay-sandbox). > **Issue against the same claim type as your relay** > > The signing key you receive is determined by the `claim-type` you issue against, so each Privacy Pass is bound to that claim type. A pass can only redeem a relay created with the **same** claim type — if they don't match, the pass won't be able to redeem the claim. Always issue against the same claim type you used to create the relay. ```bash POST /relays/privacy-passes Authorization: Bearer ``` ```json // Request { "claim-type": "live_human_presence" } ``` ```json // Response { "privacy-pass-token": "" } ``` ## Step 3 — Redeem and retrieve the claim Begin claim retrieval when your client-side integration indicates that the user-facing flow is complete: * **[Embedded Widget](/relay-widget-usage):** Call your server from `onComplete`. * **[Hosted Flow](/relay-hosted-flow):** Begin polling your backend when the user launches Hosted Flow. * **[iOS SDK](/relay-ios-sdk) and [Android SDK](/relay-android-sdk):** Call your server after the platform's normal Inquiry completion mechanism reports that the user-facing experience ended. The Privacy Pass is redeemed only on a **successful claim**. Since each pass can only be redeemed once, retrying a successful request with the same already-spent token — for example, after a network drop — would normally result in a double-spend error. Idempotency is handled automatically by the gateway. `claim-payload` is passed through as-is from Persona. If you provided an `encryption-key-pem` in Step 1, decrypt it with your private key before parsing. Otherwise it is a plaintext JSON string — see [Parsing the claim payload](/relay-sdk-quickstart#parsing-the-claim-payload). ```bash POST /relays/:relay-token/redeem Persona-Relay-Secret: ``` ```json // Request { "privacy-pass-token": "" } ``` ```json // Response { "claim-payload": "", "token-consumed": true } ``` ## Full example ```bash # Step 1 — Create a Relay session curl -X POST https:///relays \ -H "Content-Type: application/json" \ -d '{ "claim-type": "live_human_presence", "encryption-key-pem": "", "sandbox": false }' # Step 2 — Issue a Privacy Pass curl -X POST https:///relays/privacy-passes \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{ "claim-type": "live_human_presence" }' # Step 3 — Redeem and retrieve the claim curl -X POST https:///relays//redeem \ -H "Content-Type: application/json" \ -H "Persona-Relay-Secret: " \ -d '{ "privacy-pass-token": "" }' ``` > Make HTTP requests to the Relay Gateway Service.