---
search:
  tags:
    - Merchant Registry
    - POST
seo:
  description: >-
    Returns the asm_... secret exactly once with Cache-Control:… Reference for
    the POST /v1/merchants/{id}/api-keys endpoint in the agentsub Gateway API.
sidebar:
  label: Issue a scoped merchant API key
  badge: POST
title: Issue a scoped merchant API key
type: openapi-operation
---
Returns the `asm_...` secret exactly once with `Cache-Control: no-store`; replays of the same Idempotency-Key return metadata without the secret and an explanatory `notice`. Scopes come from the request body (e.g. `offers:read`, `redemptions:capture`, `redemptions:release`, `vouchers:introspect`).

`POST /v1/merchants/{id}/api-keys`

**Request body** (`application/json`, required)

- `name` (string)
- `scopes` (string[], required)

Request body example:

```json
{
  "name": "string",
  "scopes": [
    "offers:read"
  ]
}
```

**Responses**

- `201` — Key issued (secret shown once)
- `400` — \`invalid\_input\` problem
- `401` — \`unauthorized\` problem; live 401s advertise \`WWW-Authenticate: Bearer resource\_metadata=...\`
- `403` — Identity, ownership, scope or policy denied (\`human\_required\`, \`owner\_claim\_required\`, \`scope\_required\`, \`FROZEN\`, \`CAP\_EXCEEDED\`, \`SCOPE\_FORBIDDEN\`)
- `503` — Runtime or provider configuration unavailable (\`runtime\_configuration\_required\`, \`signing\_configuration\_required\`, \`runtime\_unavailable\`, \`workspace\_unavailable\`, \`provider\_configuration\_required\`)

Response example, 201:

```json
{
  "apiKey": "string",
  "metadata": {
    "keyId": "string",
    "merchantId": "string",
    "ownerId": "string",
    "name": "string",
    "scopes": [
      "string"
    ],
    "createdAt": 0,
    "revokedAt": 0
  },
  "notice": "string"
}
```
