# SDK keys

> List, issue and revoke public and secret SDK keys, and replace a public key's allowed origins, with a management key.

Last updated: 2026-09-17

Manage the public and secret keys your SDKs and servers use. Admin and developer management keys can do all of this. See [API keys and environments](https://docs.fingerly.io/docs/api-keys) for what each kind of key is for.

**Path parameter**

- `organization_id` (string, required): Your organization, from [Describe the key](https://docs.fingerly.io/reference/management/overview#describe-the-key). A path naming any other organization answers `404`.

## List SDK keys

```http
GET /api/v1/management/organizations/{organization_id}/sdk-keys
```

Authentication: Management key (`x-api-key: fly_mk_…`)

Every key in every environment, oldest first, revoked keys included.

**Response**

- `keys` (SDKKey[]): The keys.
  - `id` (string): The key's ID.
  - `name` (string): The key's name.
  - `kind` (string): `public` or `secret`.
  - `environment` (string): `production`, `staging` or `development`.
  - `region` (string): The data region whose API accepts the key.
  - `prefix` (string): The start of the secret, such as `fly_pk_us_production`.
  - `last4` (string): The last four characters of the secret.
  - `allowed_origins` (string[]): The origins a public key is accepted from in browsers. Always empty for a secret key.
  - `status` (string): `active` or `revoked`.
  - `last_used_at` (string): When the key last authenticated a request. Omitted if never.
  - `expires_at` (string): When the key stops working. Omitted if it does not expire.
  - `created_at` (string): When the key was issued.
  - `created_by` (string): The member who issued it. Omitted for a key issued with a management key.
  - `revoked_at` (string): When the key was revoked.
  - `revoked_by` (string): The member who revoked it. Omitted when a management key did.

## Issue an SDK key

```http
POST /api/v1/management/organizations/{organization_id}/sdk-keys
```

Authentication: Management key (`x-api-key: fly_mk_…`)

**Body**

- `name` (string, required): What the key is called.
- `kind` (string, required): `public` or `secret`.
- `environment` (string, required): `production`, `staging` or `development`.
- `allowed_origins` (string[]): Required, with at least one origin, for a public key. Refused on a secret key.
- `expires_at` (string): When the key stops working, RFC 3339. Omit for a key that lasts until revoked.

Answers `201` with `key`, an SDK key as above, and `secret`, the whole key. The secret is never returned again.

## Revoke an SDK key

```http
POST /api/v1/management/organizations/{organization_id}/sdk-keys/{sdk_key_id}/revoke
```

Authentication: Management key (`x-api-key: fly_mk_…`)

Refuses the key from the next request on, and answers with the revoked key. There is no undo. Revoking a key that is already revoked answers `409` with `key_revoked`.

## Replace allowed origins

```http
PUT /api/v1/management/organizations/{organization_id}/sdk-keys/{sdk_key_id}/origins
```

Authentication: Management key (`x-api-key: fly_mk_…`)

**Body**

- `allowed_origins` (string[], required): The complete new list. Each origin is a scheme, a host and an optional port, with no path. An empty list refuses every browser request.

Replaces the list rather than adding to it, and answers with the key. Refused with `422` on a secret key.

> **Note:** To give an SDK key its own risk weights, see [risk weights](https://docs.fingerly.io/reference/management/risk-weights#save-an-sdk-key-s-weights).

## Example request

```bash cURL
curl -X POST "https://us.api.fingerly.io/api/v1/management/organizations/01a0a7f2-3c18-7b40-8d2e-5f6a9b1c0d37/sdk-keys" \
  -H "x-api-key: $FINGERLY_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Checkout",
    "kind": "public",
    "environment": "production",
    "allowed_origins": [
      "https://shop.example.com"
    ]
  }'
```

```ts Node.js script
const api = (path: string, init: RequestInit = {}) =>
  fetch('https://us.api.fingerly.io/api/v1/management' + path, {
    ...init,
    headers: { 'x-api-key': process.env.FINGERLY_MANAGEMENT_KEY!, 'Content-Type': 'application/json' },
  })

const { organization_id } = await (await api('/key')).json()
const { keys } = await (await api('/organizations/' + organization_id + '/sdk-keys')).json()

const active = (key: { name: string; status: string }) => key.name === 'Checkout' && key.status === 'active'
if (!keys.some(active)) {
  const created = await api('/organizations/' + organization_id + '/sdk-keys', {
    method: 'POST',
    body: JSON.stringify({ name: 'Checkout', kind: 'public', environment: 'production', allowed_origins: ['https://shop.example.com'] }),
  })
  const { secret } = await created.json()
  await secrets.put('FINGERLY_PUBLIC_KEY', secret)
}
```

## Example response

```json 201
{
  "key": {
    "id": "01a0a7f3-9e05-7a61-b4c7-2d8e0f3a6b19",
    "name": "Checkout",
    "kind": "public",
    "environment": "production",
    "region": "us",
    "prefix": "fly_pk_us_production",
    "last4": "q7Rk",
    "allowed_origins": [
      "https://shop.example.com"
    ],
    "status": "active",
    "created_at": "2026-09-16T09:12:40Z"
  },
  "secret": "fly_pk_us_production_…"
}
```

```json 422
{
  "error": {
    "code": "key_rejected",
    "message": "services: the SDK key cannot be issued as described: a public key has to name the origins it may be used from",
    "status": 422
  },
  "request_id": "01a0a84c-0f11-7a3e-9c2d-4b5e6f708192"
}
```
