> For the complete documentation index, see [llms.txt](https://relayer-tech.gitbook.io/relayer-knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://relayer-tech.gitbook.io/relayer-knowledge-base/integration-documentation/api.md).

# API

Version: `v1`

## Authentication

Set of endpoints for authenticating against Relayer's API and to request permissioned access for other endpoint scopes.&#x20;

### Get a unique nonce

<mark style="color:green;">`GET`</mark> `/v1/auth/nonce`

Retrieve a unique nonce to include in a SIWx (“Sign-In with X”) message for authenticating on-chain accounts via the `"siwx"` grant type.

**Response**

{% tabs %}
{% tab title="200" %}
A unique alphanumeric nonce (**string**)\
Example response:

`"8og0j9nt5vp74my1"`
{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Get an app access token using the "Client Credentials" grant type

<mark style="color:green;">`POST`</mark> `/v1/auth/token`

Retrieve an application access token via the “Client Credentials” grant type. This authentication method is intended for server-to-server interaction with a confidential client.

**Headers**

| Name          | Value                                              |
| ------------- | -------------------------------------------------- |
| Content-Type  | `application/x-www-form-urlencoded`                |
| Authorization | `Basic <base64 encoded "client_id:client_secret">` |

**Request**

Data `application/x-www-form-urlencoded`

* `grant_type` (**string**) <mark style="color:red;">required</mark>\
  Method of authentication.\
  Value: `"client_credentials"`
* `scope` (**string)**\
  String listing requested scopes that are separated by spaces. See [#scopes](#scopes "mention") for the list of scopes. If no scope if provided, the default scope will be authorized.\
  Example value:\
  `"users users.accounts users.accounts.attestation users.enrollment rewards"`

**Response**

Error responses for the `/v1/auth/token` endpoint differ from Relayer defined error responses and conform to the response defined by [RFC-6749 (section 5.2)](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).

{% tabs %}
{% tab title="200" %}
The application access token (**object**)

* `access_token` (**string**) <mark style="color:red;">required</mark>\
  Example:\
  `”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c”`
* `token_type` (**string)** <mark style="color:red;">required</mark>\
  The type of token used in the `Authorization` header.\
  Example:\
  `"Bearer"`
* `expires_in` (**integer**) <mark style="color:red;">required</mark>\
  Number of seconds until the access token expires and a new access token will need to be requested.\
  Example:\
  `3600`
* `scope` **(string)**\
  String listing authorized scopes that were requested. Scopes are separated by spaces.\
  Example:\
  `"users users.accounts users.accounts.attestation users.enrollment rewards"`

Example response:

```json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "users users.accounts users.accounts.attestation users.enrollment rewards"
}
```

{% endtab %}

{% tab title="400" %}
RFC-6749 (section 5.2) defined error (**object**)

* `error` (**string**)\
  The code for the error.\
  Values:&#x20;
  * `"invalid_request"`\
    The request does not have the expected parameters (e.g. missing required parameters, unsupported parameters are included, etc.).
  * `"invalid_client"`\
    Client authentication failed due to an unknown client, no client authentication included, or an unsupported authentication method.
  * `"unauthorized_client"`\
    The authenticated client is not authorized to use this authorization grant type.
  * `"unsupported_grant_type"`\
    The authorization grant type is not supported by the authorization server.
  * `"invalid_scope"`\
    The requested scope is invalid, unknown, or malformed.
* `error_description` (**string**)\
  Human-readable ASCII text providing additional information on the error.

Example response:

```json
{
    "type": "invalid_request",
    "error_description": "The request is missing the required parameter, 'grant_type'."
}
```

{% endtab %}
{% endtabs %}

### Get a user access token using the "Sign-In With X" grant type

<mark style="color:green;">`POST`</mark> `/v1/auth/token`

Retrieve an application access token either via the “SIWX (Sign-In With X)” grant type. This authentication method is intended for communication between a public client and server.

**Headers**

| Name          | Value                                              |
| ------------- | -------------------------------------------------- |
| Content-Type  | `application/x-www-form-urlencoded`                |
| Authorization | `Basic <base64 encoded "client_id:client_secret">` |

**Request**

Data `application/x-www-form-urlencoded`

* `grant_type` (**string**) <mark style="color:red;">required</mark>\
  Method of authentication.\
  Value: `"siwx"`
* `cacao` **(string)** <mark style="color:red;">required</mark>\
  Base64URL encoded Chain Agnostic Capability Object ([CAIP-74: CACAO](https://chainagnostic.org/CAIPs/caip-74)) that contains the signing payload and signature of the authenticating account. See [#cacao-chain-agnostic-capability-object](#cacao-chain-agnostic-capability-object "mention") for more information.
* `scope` (**string)**\
  String listing requested scopes that are separated by spaces. See [#scopes](#scopes "mention") for the list of scopes. If no scope if provided, the default scope will be authorized.\
  Example value:\
  `"users.me rewards users users.enrollment users.accounts"`

**Response**

Error responses for the `/v1/auth/token` endpoint differ from Relayer defined error responses and conform to the response defined by [RFC-6749 (section 5.2)](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).

{% tabs %}
{% tab title="200" %}
The application access token (**object**)

* `access_token` (**string**) <mark style="color:red;">required</mark>\
  The issued access to be used in further requests.\
  Example:\
  `”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c”`
* `token_type` (**string)** <mark style="color:red;">required</mark>\
  The type of token used in the `Authorization` header for the authorization scheme.\
  Example:\
  `"Bearer"`
* `expires_in` (**integer**) <mark style="color:red;">required</mark>\
  Number of seconds until the access token expires and a new access token will need to be requested.\
  Example:\
  `3600`
* `refresh_token` (**string**) <mark style="color:red;">required</mark>\
  Token used to retrieve a new access token using the "Refresh Token" grant type, once an access token has expired.\
  Example:\
  `”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c”`
* `scope` **(string)** <mark style="color:red;">required</mark>\
  String listing authorized scopes that were requested. Scopes are separated by spaces.\
  Example:\
  `"users.me rewards users users.enrollment users.accounts"`
* `user_id` (**string)** <mark style="color:red;">required</mark>\
  The generated ID of the authenticated user. The user ID is under the namespace of the partner making the request.\
  Example:\
  `"de1f1af2-82c8-4648-ae05-abd1098c1596"`

Example response:

```json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
    "scope": "users.me rewards users users.enrollment users.accounts",
    "user_id": "de1f1af2-82c8-4648-ae05-abd1098c1596"
}
```

{% endtab %}

{% tab title="400" %}
RFC-6749 (section 5.2) defined error (**object**)

* `error` (**string**)\
  The code for the error.\
  Values:&#x20;
  * `"invalid_request"`\
    The request does not have the expected parameters (e.g. missing required parameters, unsupported parameters are included, etc.).
  * `"invalid_client"`\
    Client authentication failed due to an unknown client, no client authentication included, or an unsupported authentication method.
  * `"unauthorized_client"`\
    The authenticated client is not authorized to use this authorization grant type.
  * `"unsupported_grant_type"`\
    The authorization grant type is not supported by the authorization server.
  * `"invalid_scope"`\
    The requested scope is invalid, unknown, or malformed.
* `error_description` (**string**)\
  Human-readable ASCII text providing additional information on the error.

Example response:

```json
{
    "type": "invalid_request",
    "error_description": "The request is missing the required parameter, 'grant_type'."
}
```

{% endtab %}
{% endtabs %}

### Get a user access token using the "Refresh Token" grant type

<mark style="color:green;">`POST`</mark> `/v1/auth/token`

Retrieve a new access token via the ”refresh\_token” grant type and using the refresh token received from the “SIWX (Sign-In With X)” grant type.

**Headers**

| Name          | Value                                              |
| ------------- | -------------------------------------------------- |
| Content-Type  | `application/x-www-form-urlencoded`                |
| Authorization | `Basic <base64 encoded "client_id:client_secret">` |

**Request**

Data `application/x-www-form-urlencoded`

* `grant_type` (**string**) <mark style="color:red;">required</mark>\
  Method of authentication.\
  Value: `"refresh_token"`
* `refresh_token` (**string**) <mark style="color:red;">required</mark>\
  The refresh token returned in response from the "Get a user access token using the "Sign-In With X" grant type.\
  Example value:\
  `”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c”`

**Response**

Error responses for the `/v1/auth/token` endpoint differ from Relayer defined error responses and conform to the response defined by [RFC-6749 (section 5.2)](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).

{% tabs %}
{% tab title="200" %}
The application access token (**object**)

* `access_token` (**string**) <mark style="color:red;">required</mark>\
  Example:\
  `”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c”`
* `token_type` (**string)** <mark style="color:red;">required</mark>\
  The type of token used in the `Authorization` header.\
  Example:\
  `"Bearer"`
* `expires_in` (**integer**) <mark style="color:red;">required</mark>\
  Number of seconds until the access token expires and a new access token will need to be requested.\
  Example:\
  `3600`
* `scope` **(string)** <mark style="color:red;">required</mark>\
  String listing authorized scopes that were requested. Scopes are separated by spaces.\
  Example:\
  `"users.me rewards users users.enrollment users.accounts"`

Example response:

```json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "users.me rewards users users.enrollment users.accounts"
}
```

{% endtab %}

{% tab title="400" %}
RFC-6749 (section 5.2) defined error (**object**)

* `error` (**string**)\
  The code for the error.\
  Values:&#x20;
  * `"invalid_request"`\
    The request does not have the expected parameters (e.g. missing required parameters, unsupported parameters are included, etc.).
  * `"invalid_client"`\
    Client authentication failed due to an unknown client, no client authentication included, or an unsupported authentication method.
  * `"unauthorized_client"`\
    The authenticated client is not authorized to use this authorization grant type.
  * `"unsupported_grant_type"`\
    The authorization grant type is not supported by the authorization server.
  * `"invalid_scope"`\
    The requested scope is invalid, unknown, or malformed.
* `error_description` (**string**)\
  Human-readable ASCII text providing additional information on the error.

Example response:

```json
{
    "type": "invalid_request",
    "error_description": "The request is missing the required parameter, 'grant_type'."
}
```

{% endtab %}
{% endtabs %}

## Users

### Create a new user

<mark style="color:green;">`POST`</mark> `/v1/users`

Create a new Relayer user based on the integrating partner's user ID.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Content-Type  | `application/json`      |
| Authorization | `Bearer <access token>` |

**Request**

Body `application/json`

* `id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:
  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`
* `auto_enroll` (**boolean**)\
  Whether to automatically enroll the user for rewards. If `true` the user will be enrolled once created, if `false` the user will not be enrolled. Defaults to `false`.\
  Example value: `false`

**Response**

{% tabs %}
{% tab title="201" %}
The Relayer profile of the user (**object**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the user used by the integrating partner. This is the same as the id included in the request body.\
  Example value: `”67e46f52-8fc9-4224-a8b7-bd9817bc4368”`
* `onchain_accounts` (**list\[object]**) <mark style="color:red;">required</mark>\
  List of on-chain accounts connected to the user.\
  Value: `[]`
  * `id` (**string**) <mark style="color:red;">required</mark>\
    The ID of the account assigned by Relayer.\
    Example value: `"67e46f52-8fc9-4224-a8b7-bd9817bc4368"`
  * `caip2_namespace` (**string**) <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.\
    Example value: `"eip155"`
  * `namespace` (**string**) <mark style="color:red;">required</mark>\
    The colloquial name of blockchain class/ecosystem the account is on.\
    Example value: `"Ethereum Ecosystem"`
  * `account_address` (**string**) <mark style="color:red;">required</mark>\
    The address of the account.\
    Example value: `"0x25963d25e2fd2287aeD51009B73db4619051DA3f"`
  * `account_origin` (**string**) <mark style="color:red;">required</mark>\
    Whether the account is external or internal to the integrating partner application. This is to distinguish accounts that were created by the client itself and accounts that connected to the client (such as through a wallet extension).\
    Example values:&#x20;
    * `"external"`
    * `"internal"`
* `enrolled` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the user is currently enrolled for personalized rewards.\
  Value: `false`

Example response:

```json
{
    "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
    "enrolled": false,
    "onchain_accounts": []
}
```

{% endtab %}

{% tab title="400" %}
**User already exists**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `400`
* `message` (**string**)\
  A short description that provides a more robust explanation than the error's `type`.\
  Value: `"A user already exists with this ID ('id'='{id}')."`

Example response:

```json
{
    "http_status_code": 400,
    "message": "A user already exists with this ID."
}
```

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description that provides a more robust explanation than the error's `type`.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is bad (likely malformed)."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description that provides a more robust explanation than the error's `type`.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description that provides a more robust explanation than the error's `type`.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Get a user

<mark style="color:green;">`GET`</mark> `/v1/users/id/{id}`

Retrieve a Relayer user by the integrating partner's user ID.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:
  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="200" %}
The Relayer profile of the user (**object**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the user used by the integrating partner. This is the same as the id included in the request body.\
  Example value: `”67e46f52-8fc9-4224-a8b7-bd9817bc4368”`
* `onchain_accounts` (**list\[object]**) <mark style="color:red;">required</mark>\
  List of on-chain accounts connected to the user.\
  Value: `[]`
  * `id` (**string**) <mark style="color:red;">required</mark>\
    The ID of the account assigned by Relayer.\
    Example value: `"67e46f52-8fc9-4224-a8b7-bd9817bc4368"`
  * `caip2_namespace` (**string**) <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.\
    Example value: `"eip155"`
  * `namespace` (**string**) <mark style="color:red;">required</mark>\
    The colloquial name of blockchain class/ecosystem the account is on.\
    Example value: `"Ethereum Ecosystem"`
  * `account_address` (**string**) <mark style="color:red;">required</mark>\
    The address of the account.\
    Example value: `"0x25963d25e2fd2287aeD51009B73db4619051DA3f"`
  * `account_origin` (**string**) <mark style="color:red;">required</mark>\
    Whether the account is external or internal to the integrating partner application. This is to distinguish accounts that were created by the client itself and accounts that connected to the client (such as through a wallet extension).\
    Example values:&#x20;
    * `"external"`
    * `"internal"`
* `enrolled` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the user is currently enrolled for personalized rewards.\
  Example value: `false`

Example response:

```json
{
    "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
    "enrolled": false,
    "onchain_accounts": [
        {
            "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
            "caip2_namespace": "eip155",
            "namespace": "Ethereum Ecosystem",
            "account_address": "0x25963d25e2fd2287aeD51009B73db4619051DA3f",
            "account_origin": "external"
        }
    ]
}
```

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Get users

<mark style="color:green;">`GET`</mark> `/v1/users`

Retrieve a paginated list of Relayer users created by the integrating partner.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Query

* `continuation` (**string**)\
  Continuation token from a previous response for use in requesting the next page of users.
* `size` (**integer**)\
  The number of users to return in the page response. `size` can not exceed 10,000.\
  Example value: `10000`

**Response**

{% tabs %}
{% tab title="200" %}

* `continuation` (**string | null**)\
  Continuation token to paginate the results of users. The token is `null` if no next page exists.
* `users` (**list\[object]**) <mark style="color:red;">required</mark>\
  The Relayer profile of the user.
  * `id` (**string**) <mark style="color:red;">required</mark>\
    The ID of the user used by the integrating partner. This is the same as the id included in the request body.\
    Example value: `”67e46f52-8fc9-4224-a8b7-bd9817bc4368”`
  * `onchain_accounts` (**list\[object]**) <mark style="color:red;">required</mark>\
    List of on-chain accounts connected to the user.\
    Value: `[]`
    * `id` (**string**) <mark style="color:red;">required</mark>\
      The ID of the account assigned by Relayer.\
      Example value: `"67e46f52-8fc9-4224-a8b7-bd9817bc4368"`
    * `caip2_namespace` (**string**) <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.\
      Example value: `"eip155"`
    * `namespace` (**string**) <mark style="color:red;">required</mark>\
      The colloquial name of blockchain class/ecosystem the account is on.\
      Example value: `"Ethereum Ecosystem"`
    * `account_address` (**string**) <mark style="color:red;">required</mark>\
      The address of the account.\
      Example value: `"0x25963d25e2fd2287aeD51009B73db4619051DA3f"`
    * `account_origin` (**string**) <mark style="color:red;">required</mark>\
      Whether the account is external or internal to the integrating partner application. This is to distinguish accounts that were created by the client itself and accounts that connected to the client (such as through a wallet extension).\
      Example values:&#x20;
      * `"external"`
      * `"internal"`
  * `enrolled` (**boolean**) <mark style="color:red;">required</mark>\
    Whether the user is currently enrolled for personalized rewards.\
    Example value: `false`

Example response:

<pre class="language-json"><code class="lang-json"><strong>{
</strong>    "continuation": "
    "users": [
        {
            "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
            "enrolled": false,
            "onchain_accounts": [
                {
                    "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
                    "caip2_namespace": "eip155",
                    "namespace": "Ethereum Ecosystem",
                    "account_address": "0x25963d25e2fd2287aeD51009B73db4619051DA3f",
                    "account_origin": "external"
                }
            ]
        }
    ]
}
</code></pre>

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Delete a user

<mark style="color:red;">`DEL`</mark> `/v1/users/id/{id}`

Delete a Relayer user by the integrating partner’s user ID. This includes deleting any accounts added and/or enrolled by the integrating partner.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="204" %}
No content -- the user was successfully deleted.
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden ('scope'='users enrollment', 'required_scope'='attestation')."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Get the current user

<mark style="color:green;">`GET`</mark> `/v1/users/me`

Retrieve the currently authenticated Relayer user. This is useful for users that have directly authenticated with Relayer.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Response**

{% tabs %}
{% tab title="200" %}
The Relayer profile of the user (**object**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the user used by the integrating partner. This is the same as the id included in the request body.\
  Example value: `”67e46f52-8fc9-4224-a8b7-bd9817bc4368”`
* `onchain_accounts` (**list\[object]**) <mark style="color:red;">required</mark>\
  List of on-chain accounts connected to the user.\
  Value: `[]`
  * `id` (**string**) <mark style="color:red;">required</mark>\
    The ID of the account assigned by Relayer.\
    Example value: `"67e46f52-8fc9-4224-a8b7-bd9817bc4368"`
  * `caip2_namespace` (**string**) <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.\
    Example value: `"eip155"`
  * `namespace` (**string**) <mark style="color:red;">required</mark>\
    The colloquial name of blockchain class/ecosystem the account is on.\
    Example value: `"Ethereum Ecosystem"`
  * `account_address` (**string**) <mark style="color:red;">required</mark>\
    The address of the account.\
    Example value: `"0x25963d25e2fd2287aeD51009B73db4619051DA3f"`
  * `account_origin` (**string**) <mark style="color:red;">required</mark>\
    Whether the account is external or internal to the integrating partner application. This is to distinguish accounts that were created by the client itself and accounts that connected to the client (such as through a wallet extension).\
    Example values:&#x20;
    * `"external"`
    * `"internal"`
* `enrolled` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the user is currently enrolled for personalized rewards.\
  Example value: `false`

Example response:

```json
{
    "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
    "enrolled": false,
    "onchain_accounts": [
        {
            "id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
            "caip2_namespace": "eip155",
            "namespace": "Ethereum Ecosystem",
            "account_address": "0x25963d25e2fd2287aeD51009B73db4619051DA3f",
            "account_origin": "external"    
        }
    ]
}
```

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

## Accounts

### Attest an on-chain account for a user

<mark style="color:green;">`POST`</mark> `/v1/users/id/{id}/accounts/onchain/attestation`

Attest that an account should be added to a specific user. The account origin will be "internal" to the integrating partner.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Content-Type  | `application/json`      |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

Body `application/json`

* `caip2_namespace` (**string**) <mark style="color:red;">required</mark>\
  The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.\
  Example value: \
  `"eip155"`
* `account_address` (**string**) <mark style="color:red;">required</mark>\
  The address of the account.\
  Example value: \
  `"0x25963d25e2fd2287aeD51009B73db4619051DA3f"`

**Response**

{% tabs %}
{% tab title="204" %}
No content -- the account was successfully added.
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Connect an on-chain account to a user

<mark style="color:green;">`POST`</mark> `/v1/users/id/{id}/accounts/onchain`

Add a new account to a specific user.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Content-Type  | `application/json`      |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

Body `application/json`

* `account_origin` (**string**) <mark style="color:red;">required</mark>\
  Whether the account is external or internal to the integrating partner application. This is to distinguish accounts that were created by the application itself and accounts that connected to the application (such as through a wallet extension).\
  Example values:&#x20;
  * `"external"`
  * `"internal"`
* `cacao` **(object)** <mark style="color:red;">required</mark>\
  Chain Agnostic Capability Object ([CAIP-74: CACAO](https://chainagnostic.org/CAIPs/caip-74)) that contains the signing payload and signature of the authenticating account. See [#cacao-chain-agnostic-capability-object](#cacao-chain-agnostic-capability-object "mention") for more information.

**Response**

{% tabs %}
{% tab title="204" %}
No content -- the account was successfully added.
{% endtab %}

{% tab title="400" %}
**Account already added**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `400`
* `message` (**string**)\
  A short description of the error.\
  Value: `"This account is already added to this user."`

Example response:

```json
{
    "http_status_code": 400,
    "message": "This acount is already added to this user."
}
```

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description that provides a more robust explanation than the error's `type`.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Disconnect an account from a user

<mark style="color:red;">`DEL`</mark> `/v1/users/id/{id}/accounts/{account_id}`

Remove an existing account from a specific user.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Content-Type  | `application/json`      |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`
* `account_id` (**string**) <mark style="color:red;">required</mark>\
  The identifier of the account used by Relayer.\
  Example value: `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="204" %}
No content -- the account was successfully removed.
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="404" %}
**Account does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `400`
* `message` (**string**)\
  A short description of the error.\
  Value: `"This account does not exist for the user."`

Example response:

```json
{
    "http_status_code": 400,
    "message": "This account does not exist for the user."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Get connected accounts for a user

<mark style="color:green;">`GET`</mark> `/v1/users/id/{id}/accounts`

Remove an existing account from a specific user.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Content-Type  | `application/json`      |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="200" %}
The accounts added to the user (**list\[object]**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the account assigned by Relayer.\
  Example value: `"67e46f52-8fc9-4224-a8b7-bd9817bc4368"`
* `caip2_namespace` (**string**) <mark style="color:red;">required</mark>\
  The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.\
  Example value: `"eip155"`
* `namespace` (**string**) <mark style="color:red;">required</mark>\
  The colloquial name of blockchain class/ecosystem the account is on.\
  Example value: `"Ethereum Ecosystem"`
* `account_address` (**string**) <mark style="color:red;">required</mark>\
  The address of the account.\
  Example value: `"0x25963d25e2fd2287aeD51009B73db4619051DA3f"`
* `account_origin` (**string**) <mark style="color:red;">required</mark>\
  Whether the account is external or internal to the integrating partner application. This is to distinguish accounts that were created by the client itself and accounts that connected to the client (such as through a wallet extension).\
  Example values:&#x20;
  * `"external"`
  * `"internal"`

Example response:

```json
[
    {
        "account_id": "67e46f52-8fc9-4224-a8b7-bd9817bc4368",
        "chain_id": "0x1",
        "chain_name": "ethereum",
        "address": "0x25963d25e2fd2287aeD51009B73db4619051DA3f",
        "account_origin": "external"
    }
]
```

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the errorr.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

## Enrollment

### Enroll a user

<mark style="color:green;">`POST`</mark> `/v1/users/id/{id}/enrollment`

Enroll a user by integrating partner ID for personalized rewards.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="204" %}
The user was successfully enrolled
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is bad (likely malformed)."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Unenroll a user

<mark style="color:red;">`DEL`</mark> `/v1/users/id/{id}/enrollment`

Unenroll a user by integrating partner ID from personalized rewards.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="204" %}
The user was successfully unenrolled
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{,
    "http_status_code": 401,,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{,
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Get enrollment status for user

<mark style="color:green;">`GET`</mark> `/v1/users/id/{id}/enrollment`

Retrieve the enrollment status for a user.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="200" %}
The enrollment status for the user (**object**)

* `enrolled` (**boolean**)\
  Whether the user is currently enrolled in personalized rewards.

Example response:

```json
{
    "enrolled": true
}
```

{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

## Reward Feeds

### Get promotional rewards

<mark style="color:green;">`GET`</mark> `/v1/rewards`

Retrieve non-curated rewards for promotional use by the integrating partner.

**Headers**

| Name          | Value                                              |
| ------------- | -------------------------------------------------- |
| Authorization | `Basic <base64 encoded "client_id:client_secret">` |

**Response**

{% tabs %}
{% tab title="200" %}
The rewards feed for promotion (**list\[object]**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  ID of the reward.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`
* `placement` (**integer**) <mark style="color:red;">required</mark>\
  The placement index for the reward in the feed.\
  Example value: `0`
* `single_use` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer is usable more than once.\
  Example  value: `true`
* `number_of_uses` (**integer**) <mark style="color:red;">required</mark>\
  Number of times the reward can be used.\
  Example value: `1`
* `type` (**string**) <mark style="color:red;">required</mark>\
  The type of the reward.\
  Example values (non-extensive):
  * `"eCommerce"`
  * `"DEX"`
  * `"Bridge"`
* `short_description` (**string**) <mark style="color:red;">required</mark>\
  Short description for the reward.
* `full_description` (**string**) <mark style="color:red;">required</mark>\
  Full description for the reward.
* `min_reward_amount` (**number**) <mark style="color:red;">required</mark>\
  Minimum reward amount.
* `max_reward_amount` (**number**) <mark style="color:red;">required</mark>\
  Maximum reward amount.
* `reward_asset` (**object**) <mark style="color:red;">required</mark>\
  Currency/token that the reward is paid out in.
  * `name` **(string)** <mark style="color:red;">required</mark>\
    Name of the currency/token.
  * `symbol` **(string)** <mark style="color:red;">required</mark>\
    Symbol of the currency/token.
  * `contract_address` **(string | null)** <mark style="color:red;">required</mark>\
    The address of the token or `null` if the token is native.
  * `chain` **(object)** <mark style="color:red;">required</mark>\
    The chain information of the token.
    * `name` **(string)** <mark style="color:red;">required</mark>\
      Name of the chain.
    * `namespace` **(string)** <mark style="color:red;">required</mark>\
      The colloquial name of blockchain class/ecosystem the chain is a part of.
    * `chain_id` **(string)** <mark style="color:red;">required</mark>\
      The colloquial chain ID of the blockchain.
    * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
    * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
    * `image_url` **(string)** <mark style="color:red;">required</mark>\
      URL of the chain's logo.
* `brand` (**object**) <mark style="color:red;">required</mark>\
  Brand offering the reward.
  * `name` (**string**) <mark style="color:red;">required</mark>\
    Name of the brand.
  * `image_url` (**string**) <mark style="color:red;">required</mark>\
    URL for the brand’s logo.
  * `categories` (**list\[string]**) <mark style="color:red;">required</mark>\
    Categories the brand is part of.
  * `website_url` (**string**) <mark style="color:red;">required</mark>\
    Website of the brand.
  * `terms_and_conditions` (**string)** <mark style="color:red;">required</mark>\
    Reward’s terms and conditions.
* `supported_chains` (**list\[object]**) <mark style="color:red;">required</mark>\
  Chains that the offer is supported on.
  * `name` **(string)** <mark style="color:red;">required</mark>\
    Name of the chain.
  * `namespace` **(string)** <mark style="color:red;">required</mark>\
    The colloquial name of blockchain class/ecosystem the chain is a part of.
  * `chain_id` **(string)** <mark style="color:red;">required</mark>\
    The colloquial chain ID of the blockchain.
  * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
  * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
  * `image_url` **(string)** <mark style="color:red;">required</mark>\
    URL of the chain's logo.
    {% endtab %}

{% tab title="401" %}
**Authentication Error**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Failed to authenticate client."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Failed to authenticate client."
}
```

{% endtab %}
{% endtabs %}

### Submit an engagement event for a non-curated reward

<mark style="color:green;">`POST`</mark> `/v1/rewards/{reward_id}/engage`

Submit an engagement event for a non-curated reward.

**Headers**

| Name          | Value                                              |
| ------------- | -------------------------------------------------- |
| Authorization | `Basic <base64 encoded "client_id:client_secret">` |

**Request**

Path

* `reward_id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the reward to trigger. Triggering the reward allows the reward to be successfully matched against and be paid out to the user.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`

Body `application/json`

* `event_id` (**string**) <mark style="color:red;">required</mark>\
  The ID of event (such as a custom event)\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`

{% tabs %}
{% tab title="201" %}
The event was successfully submitted.
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**) HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599. Value: `401`
* `message` (**string**) A short description of the error. Value: `"Access token is invalid"`

Example response:

```
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**) HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599. Value: `403`
* `message` (**string**) A short description of the error. Value: `"Access to the scoped resource is forbidden."`

Example response:

```
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**Reward does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**) HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599. Value: `404`
* `message` (**string**) A short description of the error. Value: `"A reward does not exist with this ID."`

Example response:

```
{
    "http_status_code": 404,
    "message": "A reward does not exist with this ID."
}
```

{% endtab %}

{% tab title="404" %}
**Event does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**) HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599. Value: `404`
* `message` (**string**) A short description of the error. Value: `"An event does not exist with this ID."`

Example response:

```
{
    "http_status_code": 404,
    "message": "An event does not exist with this ID ('id'='de1f1af2-82c8-4648-ae05-abd1098c1596')."
}
```

{% endtab %}
{% endtabs %}

### Get rewards for a user

<mark style="color:green;">`GET`</mark> `/v1/users/id/{id}/rewards`

Retrieve a personalized rewards feed for a specific user.&#x20;

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`

**Response**

{% tabs %}
{% tab title="200" %}
The rewards feed for the user (**list\[object]**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  ID of the reward.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`
* `placement` (**integer**) <mark style="color:red;">required</mark>\
  The placement index for the reward in the feed.\
  Example value: `0`
* `single_use` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer is usable more than once.\
  Example  value: `true`
* `number_of_uses` (**integer**) <mark style="color:red;">required</mark>\
  Number of times the reward can be used.\
  Example value: `1`
* `type` (**string**) <mark style="color:red;">required</mark>\
  The type of the reward.\
  Example values (non-extensive):
  * `"eCommerce"`
  * `"DEX"`
  * `"Bridge"`
* `short_description` (**string**) <mark style="color:red;">required</mark>\
  Short description for the reward.
* `full_description` (**string**) <mark style="color:red;">required</mark>\
  Full description for the reward.
* `min_reward_amount` (**number**) <mark style="color:red;">required</mark>\
  Minimum reward amount.
* `max_reward_amount` (**number**) <mark style="color:red;">required</mark>\
  Maximum reward amount.
* `reward_asset` (**object**) <mark style="color:red;">required</mark>\
  Currency/token that the reward is paid out in.
  * `name` **(string)** <mark style="color:red;">required</mark>\
    Name of the currency/token.
  * `symbol` **(string)** <mark style="color:red;">required</mark>\
    Symbol of the currency/token.
  * `contract_address` **(string | null)** <mark style="color:red;">required</mark>\
    The address of the token or `null` if the token is native.
  * `chain` **(object)** <mark style="color:red;">required</mark>\
    The chain information of the token.
    * `name` **(string)** <mark style="color:red;">required</mark>\
      Name of the chain.
    * `namespace` **(string)** <mark style="color:red;">required</mark>\
      The colloquial name of blockchain class/ecosystem the chain is a part of.
    * `chain_id` **(string)** <mark style="color:red;">required</mark>\
      The colloquial chain ID of the blockchain.
    * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
    * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
    * `image_url` **(string)** <mark style="color:red;">required</mark>\
      URL of the chain's logo.
* `brand` (**object**) <mark style="color:red;">required</mark>\
  Brand offering the reward.
  * `name` (**string**) <mark style="color:red;">required</mark>\
    Name of the brand.
  * `image_url` (**string**) <mark style="color:red;">required</mark>\
    URL for the brand’s logo.
  * `categories` (**list\[string]**) <mark style="color:red;">required</mark>\
    Categories the brand is part of.
  * `website_url` (**string**) <mark style="color:red;">required</mark>\
    Website of the brand.
  * `terms_and_conditions` (**string)** <mark style="color:red;">required</mark>\
    Reward’s terms and conditions.
* `supported_chains` (**list\[object]**) <mark style="color:red;">required</mark>\
  Chains that the offer is supported on.
  * `name` **(string)** <mark style="color:red;">required</mark>\
    Name of the chain.
  * `namespace` **(string)** <mark style="color:red;">required</mark>\
    The colloquial name of blockchain class/ecosystem the chain is a part of.
  * `chain_id` **(string)** <mark style="color:red;">required</mark>\
    The colloquial chain ID of the blockchain.
  * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
  * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
  * `image_url` **(string)** <mark style="color:red;">required</mark>\
    URL of the chain's logo.
* `triggered` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer is currently activated.
* `redeemed` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer was completed.
  {% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="404" %}
**Feed does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A feed does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A feed does not exist with this ID."
}
```

{% endtab %}

{% tab title="429" %}
**Rate limit exceeded.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `429`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Rate limit exceeded. Please try again in a couple of seconds."`

Example response:

```json
{
    "http_status_code": 429,
    "message": "Rate limit exceeded. Please try again in a couple of seconds."
}
```

{% endtab %}
{% endtabs %}

### Trigger a reward for redemption by a user

<mark style="color:green;">`POST`</mark> `/v1/users/id/{id}/rewards/{reward_id}/trigger`

Trigger a reward for redemption by a user using a specified trigger method. Triggering a reward allows the reward to be successfully matched and paid out to the user. A reward may be triggered in multiple ways across an application. The trigger ID is used to differentiate these trigger types.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`
* `reward_id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the reward to trigger. Triggering the reward allows the reward to be successfully matched against and be paid out to the user.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`

Body `application/json`

* `trigger_id` (**string**) <mark style="color:red;">required</mark>\
  ID of the trigger event.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`

**Response**

{% tabs %}
{% tab title="200" %}
The reward that was triggered (**object**)

* `id` (**string**) <mark style="color:red;">required</mark>\
  ID of the reward.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`
* `placement` (**integer**) <mark style="color:red;">required</mark>\
  The placement index for the reward in the feed.\
  Example value: `0`
* `single_use` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer is usable more than once.\
  Example  value: `true`
* `number_of_uses` (**integer**) <mark style="color:red;">required</mark>\
  Number of times the reward can be used.\
  Example value: `1`
* `type` (**string**) <mark style="color:red;">required</mark>\
  The type of the reward.\
  Example values (non-extensive):
  * `"eCommerce"`
  * `"DEX"`
  * `"Bridge"`
* `short_description` (**string**) <mark style="color:red;">required</mark>\
  Short description for the reward.
* `full_description` (**string**) <mark style="color:red;">required</mark>\
  Full description for the reward.
* `min_reward_amount` (**number**) <mark style="color:red;">required</mark>\
  Minimum reward amount.
* `max_reward_amount` (**number**) <mark style="color:red;">required</mark>\
  Maximum reward amount.
* `reward_asset` (**object**) <mark style="color:red;">required</mark>\
  Currency/token that the reward is paid out in.
  * `name` **(string)** <mark style="color:red;">required</mark>\
    Name of the currency/token.
  * `symbol` **(string)** <mark style="color:red;">required</mark>\
    Symbol of the currency/token.
  * `contract_address` **(string | null)** <mark style="color:red;">required</mark>\
    The address of the token or `null` if the token is native.
  * `chain` **(object)** <mark style="color:red;">required</mark>\
    The chain information of the token.
    * `name` **(string)** <mark style="color:red;">required</mark>\
      Name of the chain.
    * `namespace` **(string)** <mark style="color:red;">required</mark>\
      The colloquial name of blockchain class/ecosystem the chain is a part of.
    * `chain_id` **(string)** <mark style="color:red;">required</mark>\
      The colloquial chain ID of the blockchain.
    * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
    * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
    * `image_url` **(string)** <mark style="color:red;">required</mark>\
      URL of the chain's logo.
* `brand` (**object**) <mark style="color:red;">required</mark>\
  Brand offering the reward.
  * `name` (**string**) <mark style="color:red;">required</mark>\
    Name of the brand.
  * `image_url` (**string**) <mark style="color:red;">required</mark>\
    URL for the brand’s logo.
  * `categories` (**list\[string]**) <mark style="color:red;">required</mark>\
    Categories the brand is part of.
  * `website_url` (**string**) <mark style="color:red;">required</mark>\
    Website of the brand.
  * `terms_and_conditions` (**string)** <mark style="color:red;">required</mark>\
    Reward’s terms and conditions.
* `supported_chains` (**list\[object]**) <mark style="color:red;">required</mark>\
  Chains that the offer is supported on.
  * `name` **(string)** <mark style="color:red;">required</mark>\
    Name of the chain.
  * `namespace` **(string)** <mark style="color:red;">required</mark>\
    The colloquial name of blockchain class/ecosystem the chain is a part of.
  * `chain_id` **(string)** <mark style="color:red;">required</mark>\
    The colloquial chain ID of the blockchain.
  * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
  * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
    The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
  * `image_url` **(string)** <mark style="color:red;">required</mark>\
    URL of the chain's logo.
* `triggered` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer is currently activated.\
  Value: `true`
* `redeemed` (**boolean**) <mark style="color:red;">required</mark>\
  Whether the offer was completed.
  {% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example response:

```json
{
    "http_status_code": 401
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json

    "http_status_code": 404,
    "message": "A user does not exist with this ID."
}
```

{% endtab %}

{% tab title="404" %}
**Reward does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A reward does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A reward does not exist with this ID."
}
```

{% endtab %}

{% tab title="404" %}
**Trigger does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of ther error.\
  Value: `"A trigger does not exist with this ID ('id'='{id}')."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A feed does not exist with this ID."
}
```

{% endtab %}
{% endtabs %}

### Submit a reward engagement event for a user

<mark style="color:green;">`POST`</mark> `/v1/users/id/{id}/rewards/{reward_id}/engage`

Submit a reward engagement event for a specific user.

**Headers**

| Name          | Value                   |
| ------------- | ----------------------- |
| Content-Type  | `application/json`      |
| Authorization | `Bearer <access token>` |

**Request**

Path

* `id` (**string**) <mark style="color:red;">required</mark>

  The ID of the user used by the integrating partner. This user ID is under the namespace of the partner making the request.\
  Example values:

  * `"john@doc.com"`
  * `"42"`
  * `"468c6a73-9e25-479d-8cc6-9a837536f260"`
* `reward_id` (**string**) <mark style="color:red;">required</mark>\
  The ID of the reward to trigger. Triggering the reward allows the reward to be successfully matched against and be paid out to the user.\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`

Body `application/json`

* `event_id` (**string**) <mark style="color:red;">required</mark>\
  The ID of event (such as a custom event)\
  Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`

**Response**

{% tabs %}
{% tab title="201" %}
The event was successfully submitted.
{% endtab %}

{% tab title="401" %}
**Bad token**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid"`

Example response:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="403" %}
**Resource forbidden.**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access to the scoped resource is forbidden."`

Example response:

```json
{
    "http_status_code": 403,
    "message": "Access to the scoped resource is forbidden."
}
```

{% endtab %}

{% tab title="404" %}
**User does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A user does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A user does not exist with this ID ('id'='de1f1af2-82c8-4648-ae05-abd1098c1596')."
}
```

{% endtab %}

{% tab title="404" %}
**Reward does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"A reward does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "A reward does not exist with this ID."
}
```

{% endtab %}

{% tab title="404" %}
**Event does not exist**

Relayer defined error (**object**)

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"An event does not exist with this ID."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "An event does not exist with this ID ('id'='de1f1af2-82c8-4648-ae05-abd1098c1596')."
}
```

{% endtab %}
{% endtabs %}

### Rewards

<mark style="color:blue;">`CHANNEL`</mark> `/v1/ws` *rewards*

The `rewards` channel streams reward status events for a user, such as when a reward has been triggered or redeemed.

**Subscribe Request**

Message Body `application/json`

* `method` (**string**) <mark style="color:red;">required</mark>\
  The request's method.\
  Value: `"subscribe"`
* `params` (**object**) <mark style="color:red;">required</mark>\
  Parameters associated with the method call.
  * `channel` (**string**) <mark style="color:red;">required</mark>\
    The channel to subscribe to.\
    Value: `"rewards"`
  * `user_id` (**string**) <mark style="color:red;">required</mark>\
    The ID of the user to listen to reward status events for.\
    Value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`
  * `access_token` (**string**) <mark style="color:red;">required</mark>\
    Access token received from authenticating.
* `request_id` (**string**)\
  Optional client originating request ID sent as an acknowledgement in response.

**Subscribe Request Acknowledgement Response**

Object sent in response to acknowledge the subscribe request.

Message Body `application/json`

* `method` (**string**) <mark style="color:red;">required</mark>\
  The request's method.\
  Value: `"subscribe"`
* `result` (**object**)\
  Parameters associated with the method call.
  * `channel` (**string**) <mark style="color:red;">required</mark>\
    The channel to subscribe to.\
    Value: `"rewards"`
* `request_id` (**string**)\
  Optional client originating request ID sent as an acknowledgement in response.

**Subscription Response**

Subscription events sent across the channel.

Message Body `application/json`

* `channel` (**string**) <mark style="color:red;">required</mark>\
  The subscription channel.\
  Value: `"rewards"`
* `data` (**object**) <mark style="color:red;">required</mark>\
  Data included in the event -- the reward that object which reflects the status change.
  * `id` (**string**) <mark style="color:red;">required</mark>\
    ID of the reward.\
    Example value: `"603d000a-f635-4cae-902c-ce3c077dcb9f"`
  * `placement` (**integer**) <mark style="color:red;">required</mark>\
    The placement index for the reward in the feed.\
    Example value: `0`
  * `single_use` (**boolean**) <mark style="color:red;">required</mark>\
    Whether the offer is usable more than once.\
    Example  value: `true`
  * `number_of_uses` (**integer**) <mark style="color:red;">required</mark>\
    Number of times the reward can be used.\
    Example value: `1`
  * `type` (**string**) <mark style="color:red;">required</mark>\
    The type of the reward.\
    Example values (non-extensive):
    * `"eCommerce"`
    * `"DEX"`
    * `"Bridge"`
  * `short_description` (**string**) <mark style="color:red;">required</mark>\
    Short description for the reward.
  * `full_description` (**string**) <mark style="color:red;">required</mark>\
    Full description for the reward.
  * `min_reward_amount` (**number**) <mark style="color:red;">required</mark>\
    Minimum reward amount.
  * `max_reward_amount` (**number**) <mark style="color:red;">required</mark>\
    Maximum reward amount.
  * `reward_asset` (**object**) <mark style="color:red;">required</mark>\
    Currency/token that the reward is paid out in.
    * `name` **(string)** <mark style="color:red;">required</mark>\
      Name of the currency/token.
      * `symbol` **(string)** <mark style="color:red;">required</mark>\
        Symbol of the currency/token.
      * `contract_address` **(string | null)** <mark style="color:red;">required</mark>\
        The address of the token or `null` if the token is native.
      * `chain` **(object)** <mark style="color:red;">required</mark>\
        The chain information of the token.
        * `name` **(string)** <mark style="color:red;">required</mark>\
          Name of the chain.
        * `namespace` **(string)** <mark style="color:red;">required</mark>\
          The colloquial name of blockchain class/ecosystem the chain is a part of.
        * `chain_id` **(string)** <mark style="color:red;">required</mark>\
          The colloquial chain ID of the blockchain.
        * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
          The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
        * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
          The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
        * `image_url` **(string)** <mark style="color:red;">required</mark>\
          URL of the chain's logo.
  * `brand` (**object**) <mark style="color:red;">required</mark>\
    Brand offering the reward.
    * `name` (**string**) <mark style="color:red;">required</mark>\
      Name of the brand.
    * `image_url` (**string**) <mark style="color:red;">required</mark>\
      URL for the brand’s logo.
    * `categories` (**list\[string]**) <mark style="color:red;">required</mark>\
      Categories the brand is part of.
    * `website_url` (**string**) <mark style="color:red;">required</mark>\
      Website of the brand.
    * `terms_and_conditions` (**string)** <mark style="color:red;">required</mark>\
      Reward’s terms and conditions.
  * `supported_chains` (**list\[object]**) <mark style="color:red;">required</mark>\
    Chains that the offer is supported on.
    * `name` **(string)** <mark style="color:red;">required</mark>\
      Name of the chain.
    * `namespace` **(string)** <mark style="color:red;">required</mark>\
      The colloquial name of blockchain class/ecosystem the chain is a part of.
    * `chain_id` **(string)** <mark style="color:red;">required</mark>\
      The colloquial chain ID of the blockchain.
    * `caip2_namespace` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `namespace` of the blockchain standard/ecosystem the account is on.
    * `caip2_reference` **(string)** <mark style="color:red;">required</mark>\
      The [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) `reference` of the blockchain standard/ecosystem the account is on.
    * `image_url` **(string)** <mark style="color:red;">required</mark>\
      URL of the chain's logo.
  * `triggered` (**boolean**) <mark style="color:red;">required</mark>\
    Whether the offer is currently activated.
  * `redeemed` (**boolean**) <mark style="color:red;">required</mark>\
    Whether the offer was completed.

**Close Frame Response**

{% tabs %}
{% tab title="1000" %}
`code` (**integer**)\
The code of the websocket response.\
Value: `1000`

`reason` (**string**)\
The reason for the websocket closure.\
Value: `""`
{% endtab %}

{% tab title="1011" %}
**Bad token**

`code` (**integer**)\
The code of the websocket response.\
Value: `1011`

`reason` (**string**)\
The reason for the websocket closure. The `reason` is the serialized Relayer defined error object:

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `401`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Access token is invalid."`

Example deserialized reason:

```json
{
    "http_status_code": 401,
    "message": "Access token is invalid."
}
```

{% endtab %}

{% tab title="1011" %}
**Resource forbidden.**

`code` (**integer**)\
The code of the websocket response.\
Value: `1011`

`reason` (**string**)\
The reason for the websocket closure. The `reason` is the serialized Relayer defined error object:

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `403`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Not authorized to subscribe to rewards for user."`

Example deserialized reason:

```json
{
    "http_status_code": 403,
    "message": "Not authorized to subscribe to rewards for user."
}
```

{% endtab %}

{% tab title="1011" %}
**Channel does not exist**

`code` (**integer**)\
The code of the websocket response.\
Value: `1011`

`reason` (**string**)\
The reason for the websocket closure. The `reason` is the serialized Relayer defined error object:

* `http_status_code` (**integer**)\
  HTTP status code for the error. This is identical to the status code returned in the HTTP response header and covers the range of codes 400-599.\
  Value: `404`
* `message` (**string**)\
  A short description of the error.\
  Value: `"Channel does not exist."`

Example response:

```json
{
    "http_status_code": 404,
    "message": "Channel does not exist."
}
```

{% endtab %}
{% endtabs %}

## Operational

### Ping

<mark style="color:blue;">`REQUEST`</mark> `/v1/ws` *ping*

Ping the server to verify the connection is alive and the server will respond with pong.

**Request**

Message Body `application/json`

* `method` (**string**) <mark style="color:red;">required</mark>\
  The request's method.\
  Value: `"ping"`
* `request_id` (**string**)\
  Optional client originating request ID sent as an acknowledgement in response.

**Response**

Object sent in response to acknowledge the request.

Body `application/json`

* `method` (**string**) <mark style="color:red;">required</mark>\
  The request's method.\
  Value: `"pong"`
* `request_id` (**string**)\
  Optional client originating request ID sent as an acknowledgement in response.

**Close Frame Response**

{% tabs %}
{% tab title="1000" %}
`code` (**integer**)\
The code of the websocket response.\
Value: `1000`

`reason` (**string**)\
The reason for the websocket closure.\
Value: `""`
{% endtab %}
{% endtabs %}

### Heartbeat

<mark style="color:blue;">`CHANNEL`</mark> `/ws` *heartbeat*

The `heartbeat` verifies that the connection is alive. Heartbeat messages are sent approximately once every second in the absence of any other channel updates.

**Update Response**

Message Body `application/json`

* `channel` (**string**) <mark style="color:red;">required</mark>\
  The request's method.\
  Value: `"heartbeat"`

**Close Frame Response**

{% tabs %}
{% tab title="1000" %}
`code` (**integer**)\
The code of the websocket response.\
Value: `1000`

`reason` (**string**)\
The reason for the websocket closure.\
Value: `""`
{% endtab %}
{% endtabs %}

## Scopes

The following table outlines scopes and the endpoints that are authorized for usage when the scope is granted.

| Scope                                                                                                                                                                                               | Authorized Endpoints                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Authorized Token Types                                |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| <p><br><br><code>(no scope)</code><br><br><em>Grants available by default.</em></p>                                                                                                                 | <ul><li><a data-mention href="#get-a-unique-nonce">#get-a-unique-nonce</a></li><li><a data-mention href="#get-an-app-access-token-using-the-client-credentials-grant-type">#get-an-app-access-token-using-the-client-credentials-grant-type</a></li><li><a data-mention href="#get-a-user-access-token-using-the-sign-in-with-web3-grant-type">#get-a-user-access-token-using-the-sign-in-with-web3-grant-type</a></li><li><a data-mention href="#get-a-user-access-token-using-the-refresh-token-grant-type">#get-a-user-access-token-using-the-refresh-token-grant-type</a></li><li><a data-mention href="#get-promotional-rewards">#get-promotional-rewards</a></li></ul> |                                                       |
| <p><code>users</code><br><br><em>Grants read, write, and delete access to user profiles created by the integrating partner application. This scope does not include <code>users.me</code>.</em></p> | <ul><li><a data-mention href="#create-a-new-user">#create-a-new-user</a></li><li><a data-mention href="#get-a-user">#get-a-user</a></li><li><a data-mention href="#get-users">#get-users</a></li><li><a data-mention href="#delete-a-user">#delete-a-user</a></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                      | <ul><li>App token</li></ul>                           |
| <p><code>users.accounts</code><br><br><em>Grants read, write, and delete access to the connected accounts of a user.</em></p>                                                                       | <ul><li><a data-mention href="#connect-an-on-chain-account-to-a-user">#connect-an-on-chain-account-to-a-user</a></li><li><a data-mention href="#disconnect-an-account-from-a-user">#disconnect-an-account-from-a-user</a></li><li><a data-mention href="#get-connected-accounts-for-a-user">#get-connected-accounts-for-a-user</a></li></ul>                                                                                                                                                                                                                                                                                                                                 | <ul><li>App token</li><li>User token</li></ul>        |
| <p><code>users.accounts.attestation</code><br><br><em>Grants access to attest an on-chain account for a user.</em></p>                                                                              | <ul><li><a data-mention href="#attest-a-on-chain-account-for-a-user">#attest-a-on-chain-account-for-a-user</a></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | <ul><li>App token</li></ul>                           |
| <p><code>users.enrollment</code><br><br><em>Grants read, write, and delete access to a user's enrollment.</em></p>                                                                                  | <ul><li><a data-mention href="#enroll-a-user">#enroll-a-user</a></li><li><a data-mention href="#unenroll-a-user">#unenroll-a-user</a></li><li><a data-mention href="#get-enrollment-status-for-user">#get-enrollment-status-for-user</a></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                           | <ul><li>App token</li><li>User token</li></ul><p></p> |
| <p><code>users.me</code><br><br><em>Grants read access to the current user.</em></p>                                                                                                                | <ul><li><a data-mention href="#get-the-current-user">#get-the-current-user</a></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | <ul><li>User token</li></ul>                          |
| <p><code>rewards</code> <br><br><em>Grants access to retrieve and interact with rewards.</em></p>                                                                                                   | <ul><li><a data-mention href="#get-rewards-for-a-user">#get-rewards-for-a-user</a></li><li><a data-mention href="#trigger-a-reward-for-redemption-by-a-user">#trigger-a-reward-for-redemption-by-a-user</a></li><li><a data-mention href="#submit-a-reward-engagement-event-for-a-user">#submit-a-reward-engagement-event-for-a-user</a></li><li><a data-mention href="#rewards">#rewards</a></li></ul>                                                                                                                                                                                                                                                                      | <ul><li>App token</li><li>User token</li></ul>        |

## CACAO: Chain Agnostic Capability Object

For authenticating and authorizing on-chain accounts, Relayer utilizes [CAIP-74](https://chainagnostic.org/CAIPs/caip-74) and [CAIP-122](https://chainagnostic.org/CAIPs/caip-122) standards. CAIP-74 defines a chain-agnostic data model for authentication. This data model encompasses the signing algorithm, the signing payload, and the resulting signature into a single container. CAIP-122 expands on CAIP-74 by defining a specific payload format intended to generalize the message format of [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361). Relayer currently supports the `"eip4361"` and `"caip122"` payload types, but is working to support other payload formats, such as Web3Auth's [SIWW ("Signin with Web3")](https://siww.web3auth.io/) and it's package `"@web3auth/sign-in-with-web3"`. These payload formats are intended to be serializable into a message that can be presented and signed by the end user as needed.

For endpoints that require a CACAO, Relayer expects a JSON structure similar to the one below. The keys `"h"`, `"p"`, and `"s"` correspond to the "Header", "Payload", and "Signature" sub-structures. The CAIP-74 proposal provides more information on these specific structures and their fields, such as their expected data types, formats, and optionality. The payload used in this example is the `"eip4361"` type.

```
{
  "h": {
    "t": "eip4361"
  },
  "p": {
    "aud": "http://localhost:3000/login",
    "exp": "2022-03-10T18:09:21.481+03:00",
    "iat": "2022-03-10T17:09:21.481+03:00",
    "iss": "did:pkh:eip155:1:0xBAc675C310721717Cd4A37F6cbeA1F081b1C2a07",
    "nbf": "2022-03-10T17:09:21.481+03:00",
    "nonce": "328917",
    "domain": "localhost:3000",
    "version": "1",
    "requestId": "request-id-random",
    "resources": [
      "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq",
      "https://example.com/my-web2-claim.json"
    ],
    "statement": "I accept the ServiceOrg Terms of Service: https://service.org/tos"
  },
  "s": {
    "s": "5ccb134ad3d874cbb40a32b399549cd32c953dc5dc87dc64624a3e3dc0684d7d4833043dd7e9f4a6894853f8dc555f97bc7e3c7dd3fcc66409eb982bff3a44671b",
    "t": "eip191"
  }
}
```

For authenticating with the `"siwx"` grant type, a Base64 encoded CACAO is required. In JavaScript, this can be created using the following code:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const cacao = {
  "h": {
    "t": "eip4361"
  },
  "p": {
    "aud": "http://localhost:3000/login",
    "exp": "2022-03-10T18:09:21.481+03:00",
    "iat": "2022-03-10T17:09:21.481+03:00",
    "iss": "did:pkh:eip155:1:0xBAc675C310721717Cd4A37F6cbeA1F081b1C2a07",
    "nbf": "2022-03-10T17:09:21.481+03:00",
    "nonce": "328917",
    "domain": "localhost:3000",
    "version": "1",
    "requestId": "request-id-random",
    "resources": [
      "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq",
      "https://example.com/my-web2-claim.json"
    ],
    "statement": "I accept the ServiceOrg Terms of Service: https://service.org/tos"
  },
  "s": {
    "s": "0x5ccb134ad3d874cbb40a32b399549cd32c953dc5dc87dc64624a3e3dc0684d7d4833043dd7e9f4a6894853f8dc555f97bc7e3c7dd3fcc66409eb982bff3a44671b",
    "t": "eip191"
  }
};
const serializedCacao = JSON.stringify(cacao);
const base64Cacao = Buffer.from(serializedCacao).toString("base64");
```

{% endtab %}
{% endtabs %}

To produce the signature included as `cacao.s.s`, the payload of the CACAO should be used in formatting a message that can be signed by the account as part of authentication. Below is the full message format for the `"eip4361"` payload with the location of each field in the CACAO:

```
{cacao.p.domain} wants you to sign in with your Ethereum account:
{cacao.p.iss[address]}

{cacao.p.statement}

URI: {cacao.p.aud}
Version: {cacao.p.version}
Chain ID: {cacao.p.iss[chainId.reference]}
Nonce: {cacao.p.nonce}
Issued At: {cacao.p.iat}
Expiration Time: ${cacao.p.exp}
Not Before: ${cacao.p.nbf}
Request ID: ${cacao.p.requestId}
Resources:
- {cacao.p.resources[0]}
- {cacao.p.resources[1]}
...
- {cacao.p.resources[n]}
```

The `"eip4361"` allows for optional payload fields that don't need to be included in the CACAO or reflected in the formatted message. This is the IPLD schema for the "Payload" sub-structure (as outlined in the ["CAIP-74: CACAO - Chain Agnostic CApability Object"](https://chainagnostic.org/CAIPs/caip-74) specification:

```
type Payload struct {
  domain String // =domain
  iss String // = DID pkh
  aud String // =uri
  version String
  nonce String
  iat String // RFC3339 date-time =issued-at
  nbf optional String // RFC3339 date-time =not-before
  exp optional String // RFC3339 date-time = expiration-time
  statement optional String // =statement
  requestId optional String // =request-id
  resources optional [ String ] // =resources as URIs
}
```

Adjusting the format to exclude optional fields, below is the message format with only required fields:

```
{cacao.p.domain} wants you to sign in with your Ethereum account:
{cacao.p.iss[address]}

URI: {cacao.p.aud}
Version: {cacao.p.version}
Chain ID: {cacao.p.iss[chainId.reference]}
Nonce: {cacao.p.nonce}
Issued At: {cacao.p.iat}
```

The following is an example of a EIP-4361 message using the previous message format (a modification of the example provided by the [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) specification) that could be signed by the owner of `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` and included the CACAO as the signature:

```
example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
```

Piecing it all together to authenticate with the "SIWx" grant type, the full end-to-end flow can be accomplished with the example code below:

```javascript
const w3 = require('web3');

const apiBaseURL = 'https://api.relayer.tech';

// Construct a CACAO object and return a serialized Base64-encoded string
function createEncodedCacao(aud, iat, address, nonce, domain, signature) {
    const cacao = {
        "h": {
            "t": "eip4361"
        },
        // These fields are used to create `preparedMessage` below
        "p": {
            "aud": aud, // URI
            "iat": iat, // Issued At
            "iss": `did:pkh:eip155:1:${address}`, // Issuer
            "nonce": nonce,
            "domain": domain, // Domain
            "version": "1"
        },
        "s": {
            "s": signature,
            "t": "eip191"
        }
    }
    const serializedCacao = JSON.stringify(cacao)
    // Encode the string as Base64
    return Buffer.from(serializedCacao).toString('base64')
}

(async () => {
    // Client ID shared by Relayer
    const clientId = "<CLIENT ID>";
    // Address of the public/private key pair for message signing and authentication
    const address = "<SIGNING ADDRESS>";
    const privateKey = "<PRIVATE KEY>";
    const aud = "https://example.com";
    const iat = (new Date()).toISOString();
    const domain = "example.com";

    // Request a new unique nonce for signing
    let resp = await fetch(`${apiBaseURL}/v1/auth/nonce`)
    const nonce = await resp.text()

    // Prepare a message for signing using the data fields in the CACAO. 
    // The payload (`p`) of the CACAO represents this message and is used to prepare an identical 
    // one server-side to verify the signature
    //
    // EIP-4361 message format:
    // {cacao.p.domain} wants you to sign in with your Ethereum account:
    // {cacao.p.iss[address]}
    //
    // URI: {cacao.p.aud}
    // Version: {cacao.p.version}
    // Chain ID: {cacao.p.iss[chainId.reference]}
    // Nonce: {cacao.p.nonce}
    // Issued At: {cacao.p.iat}
    const preparedMessage = `${domain} wants you to sign in with your Ethereum account:
${address}

URI: ${aud}
Version: 1
Chain ID: 1
Nonce: ${nonce}
Issued At: ${iat}`;

    // Sign the formatted message using the private key associated with the address 
    // used in the `iss` field of the CACAO.
    // `preparedMessage` is wrapped as `"\x19Ethereum Signed Message:\n" + preparedMessage.length + preparedMessage`
    // as specified by EIP-191 (this is why "eip191" is used as the value for `cacao.s.t`).
    const signedData = w3.eth.accounts.sign(preparedMessage, privateKey);
    b64Cacao = createEncodedCacao(aud, iat, address, nonce, domain, signedData.signature);

    // Include `x-www-form-urlencoded` parameters for `grant_type` and `cacao` in the request.
    // "siwx" is the grant type used for authenticating on-chain accounts with Relayer.
    const params = new URLSearchParams();
    params.append('grant_type', 'siwx');
    params.append('cacao', b64Cacao);
    // Request an access token using the serialized CACAO
    resp = await fetch(`${apiBaseURL}/v1/auth/token`, {
        method: 'post',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': `Basic ${Buffer.from(`${clientId}:`).toString('base64')}`
        },
        body: params
    });
    const data = await resp.json();
    console.log(data);
})();
```
