---
title: "Request API key handoff"
method: POST
path: "/api-key-handoff"
tags: ["Account"]
---

# Request API key handoff

`POST /api-key-handoff`

Builds a dashboard link that opens the create-key form prefilled with a suggested name and permissions. Requires only `account:read`, because it creates nothing, changes nothing, and returns no secret - the new key is issued in the owner's authenticated browser session. Use it when key management is blocked because the calling key lacks `api_keys:manage`, which cannot be granted through the API by the key that is missing it. Pass replaceApiKeyId to rotate; the dashboard then offers to revoke the predecessor once the replacement exists.

## Request body

- object
  - `name` string — Suggested name for the new key. Trimmed to 80 characters in the link.
  - `preset` 'full_access' | 'read_only' | 'agent_safe' | 'ai_drafting' | 'data_ingest_safe' | 'data_ingest_automations' | 'transactional_sender' | 'marketing_sender' — Suggested permission preset.
  - `scopes` string[] — Suggested explicit permission scopes. Overrides preset when provided.
  - `replaceApiKeyId` string — ID of the key the new one replaces. Pass the literal string "current" for the key making the request.

## Response `200`

Handoff link prepared

- object
  - `success` boolean, required
  - `handoff` object, required
    - `url` string — Dashboard URL that opens the create-key form prefilled with the request.
    - `manageUrl` string — The plain API Keys settings URL, without the prefill.
    - `keyType` 'company' | 'personal' — Whether the link targets workspace or account API key settings.
    - `name` string, nullable
    - `preset` string, nullable
    - `scopes` string[], nullable
    - `permissions` object, nullable — Permission receipt for the suggested selection. Null when the request suggested no preset and no scopes, because the form then opens on the dashboard default.
    - `replaces` object, nullable — The key being replaced. name and prefix are populated only when it is the key making the request.
      - `id` string
      - `name` string, nullable
      - `prefix` string, nullable
      - `isCurrentKey` boolean
    - `canSelfServe` boolean — True when the calling key already holds api_keys:manage and could create the replacement directly.
    - `deliversKeyToCaller` boolean — Always false. The new key is shown in the browser and never returned through this endpoint.
  - `message` string
  - `nextSteps` string[]

## Other responses

- `400` — Invalid permission preset, scope list, or replaceApiKeyId
- `401` — Unauthorized
- `403` — Missing required account read permission

---

[API](https://skmtc.net/sequenzy/apis/sequenzy-api.md) · [All operations](https://skmtc.net/sequenzy/apis/sequenzy-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/sequenzy/sequenzy-api/revisions/fc5624c7d57a/schema)
