---
title: "Issue an API key"
method: POST
path: "/v1/keys"
tags: ["API keys"]
---

# Issue an API key

`POST /v1/keys`

## Request

- Base URL: `https://api.cadencercs.com`
- URL: `https://api.cadencercs.com/v1/keys`
- Auth: HTTP bearer

A **live** key must say what it is for: `brandId` scopes it to one brand, `scope: "account"` makes it account-wide. There is no default, because the previous behaviour silently bound the key to whichever brand happened to have an agent first.

A live key needs a brand with an RBM agent behind it — not a carrier-verified one. An unlaunched agent sends real RCS to its accepted test devices, which is exactly what you need before launch.

## Request body

- object
  - `kind` 'sandbox' | 'live'
  - `brandId` string: Scopes the key to one brand. Required for a live key unless `scope` is `account`.
  - `scope` 'account': Account-wide. A leak reaches every brand you own, so prefer `brandId`.
  - `label` string

## Response `200`

The key, shown once.

- object
  - `api_key` string, required
  - `kind` 'sandbox' | 'live', required
  - `key_prefix` string, required
  - `brandId` string, nullable
  - `scope` 'brand' | 'account', required
  - `reach` 'test_devices_only' | 'all_recipients': Live keys only. How far this key actually reaches today.
  - `reach_note` string
  - `note` string

## Other responses

- `400`: A live key was requested with no scope.
- `401`: Not signed in, and no account-linked API key was sent.
- `403`: A brand-scoped key tried to issue a key beyond its own scope.
- `404`: No such brand on this account.
- `409`: No brand on this account has an RBM agent yet, so a live key would have nothing to send through.
- `500`: Unexpected server error. The body is always JSON.

---

[API](https://skmtc.dev/cadencercs/apis/cadence-api.md) · [All operations](https://skmtc.dev/cadencercs/apis/cadence-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cadencercs/apis/cadence-api/revisions/9438443c2081?raw)
