Usage

The gateway exposes three endpoints that map directly to the Relay Server SDK methods. You can use any HTTP client in any language.

The URL paths below are relative — the base URL is wherever you’ve deployed your gateway instance.
Looking for full API documentation? See the Gateway Service Reference.

Step 1 — Create a Relay session

Call this endpoint before rendering the widget. The response includes a session access token to pass to your frontend, along with a relay-token and relay-secret that you must store securely on your server — never expose these to the 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.

$POST /relays
1// Request
2{
3 "claim-type": "age_over18_united_kingdom",
4 "encryption-key-pem": "<your_public_key_pem>" // pass null to opt out of encryption
5}
1// Response
2{
3 "relay-token": "<relay-token>",
4 "relay-secret": "<relay-secret>",
5 "relay-session-access-token": "<relay-session-access-token>"
6}

Store relay-token and relay-secret securely on your server. Return relay-session-access-token to your frontend to initialize the widget. See Widget usage.

Step 2 — Issue a Privacy Pass

A Privacy Pass is the billing unit for Relay — it is billed on creation and is what gets redeemed to fetch the claim result. Since issuance uses your API key, Persona knows your platform identity at this point for billing purposes. Redemption remains fully anonymous — Persona does not know who redeems the claim. Each Privacy Pass can only be redeemed once, so we recommend storing privacy-pass-token on your end and mapping it to the corresponding relay.

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.

A Privacy Pass expires 90 days after issuance, so avoid issuing too far ahead of when you expect to redeem it.

This step requires your Persona API key — you can find it in the Persona Dashboard under API Keys.

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.

$POST /relays/privacy-passes
$Authorization: Bearer <your_api_key>
1// Request
2{
3 "claim-type": "age_over18_united_kingdom"
4}
1// Response
2{
3 "privacy-pass-token": "<privacy-pass-token>"
4}

Step 3 — Redeem and retrieve the claim

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.

$POST /relays/:relay-token/redeem
$Persona-Relay-Secret: <relay-secret>
1// Request
2{
3 "privacy-pass-token": "<privacy-pass-token>"
4}
1// Response
2{
3 "claim-payload": "<encrypted_or_plaintext_claim>",
4 "token-consumed": true
5}

Full example

$# Step 1 — Create a Relay session
$curl -X POST https://<your-gateway>/relays \
> -H "Content-Type: application/json" \
> -d '{ "claim-type": "age_over18_united_kingdom", "encryption-key-pem": "<your_public_key_pem>" }'
$
$# ---- Widget handles user verification on the frontend ----
$
$# Step 2 — Issue a Privacy Pass
$curl -X POST https://<your-gateway>/relays/privacy-passes \
> -H "Content-Type: application/json" \
> -H "Authorization: Bearer <your_api_key>" \
> -d '{ "claim-type": "age_over18_united_kingdom" }'
$
$# Step 3 — Redeem and retrieve the claim
$curl -X POST https://<your-gateway>/relays/<relay-token>/redeem \
> -H "Content-Type: application/json" \
> -H "Persona-Relay-Secret: <relay-secret>" \
> -d '{ "privacy-pass-token": "<privacy-pass-token>" }'