> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.withpersona.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.withpersona.com/_mcp/server.

# Gateway Service Reference

> Full API reference for the Relay Gateway Service endpoints.

This page documents the full HTTP API for the Persona Relay Gateway Service.

## Endpoints

### `POST /relays`

Creates a Relay session. No authentication required.

**Request headers**

| Header         | Required | Description        |
| -------------- | -------- | ------------------ |
| `Content-Type` | true     | `application/json` |

**Request body**

| Field                | Type             | Required | Default | Description                                                                                                                      |
| -------------------- | ---------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `claim-type`         | `string`         | true     | —       | The claim type to evaluate. See [Claim types](/relay-schemas#claim-types)                                                        |
| `encryption-key-pem` | `string \| null` | true     | —       | PEM-encoded RSA public key. If provided, Persona encrypts the claim payload on redemption. Pass `null` to receive plaintext JSON |
| `sandbox`            | `boolean`        | false    | `false` | Creates the relay in the [sandbox environment](/relay-sandbox). Requires gateway `v0.1.2` or later                               |

**Response**

| Field                        | Type     | Description                                                                                                            |
| ---------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `relay-token`                | `string` | Identifies the relay session. Pass to subsequent privacy pass and redeem calls                                         |
| `relay-secret`               | `string` | Authenticates your server's calls on this session. Keep server-side — never expose to the client                       |
| `relay-session-access-token` | `string` | Short-lived token that your server returns to the client for the Embedded Widget, Hosted Flow, iOS SDK, or Android SDK |

### `POST /relays/privacy-passes`

Issues a Privacy Pass token. Handles the full blind RSA protocol internally. Requires your API key — this is the billing point for Relay, and it determines the environment, so it must match the environment of the relay you'll redeem against. See [Sandbox](/relay-sandbox).

> **How does this work?**
>
> Curious how the Privacy Pass protocol works under the hood? See [Privacy Pass Protocol](/relay-privacy-pass-challenge) for a full walkthrough — relevant if you're implementing this yourself without the gateway.

> **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.

**Request headers**

| Header          | Required | Description             |
| --------------- | -------- | ----------------------- |
| `Content-Type`  | true     | `application/json`      |
| `Authorization` | true     | `Bearer <your_api_key>` |

**Request body**

| Field        | Type     | Required | Description                                                                                                                                             |
| ------------ | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `claim-type` | `string` | true     | The claim type to issue a Privacy Pass for. Must match the claim type of the relay you'll redeem against. See [Claim types](/relay-schemas#claim-types) |

**Response**

| Field                | Type     | Description                                                                                                                  |
| -------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `privacy-pass-token` | `string` | The issued Privacy Pass token. Hold this server-side until the user completes verification, then pass to the redeem endpoint |

### `POST /relays/:relay-token/redeem`

Redeems a Privacy Pass token and returns the claim result.

**Path parameters**

| Parameter     | Type     | Required | Description                                  |
| ------------- | -------- | -------- | -------------------------------------------- |
| `relay-token` | `string` | true     | The relay token returned from `POST /relays` |

**Request headers**

| Header                 | Required | Description                                     |
| ---------------------- | -------- | ----------------------------------------------- |
| `Content-Type`         | true     | `application/json`                              |
| `Persona-Relay-Secret` | true     | The `relay-secret` returned from `POST /relays` |

**Request body**

| Field                | Type     | Required | Description                                           |
| -------------------- | -------- | -------- | ----------------------------------------------------- |
| `privacy-pass-token` | `string` | true     | The token returned from `POST /relays/privacy-passes` |

**Response**

| Field            | Type      | Description                                                                                                                                                                      |
| ---------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `claim-payload`  | `string`  | Plaintext JSON claim result, or base64-encoded RSA-OAEP ciphertext if `encryption-key-pem` was set on session creation. See [Claim payload schema](/relay-schemas#claim-payload) |
| `token-consumed` | `boolean` | Whether the Privacy Pass token was consumed by this redemption. A consumed token cannot be redeemed again                                                                        |