> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sequenzy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Request Key Handoff

> Get an owner-confirmed dashboard link for creating or rotating an API key

Build a link that opens the dashboard's create-key form with a name and
permissions already filled in. Use this when key management is blocked because
the calling key does not have `api_keys:manage`.

Every other `/api/v1/api-keys` route requires `api_keys:manage`, and that scope
cannot be granted through the API by a key that is missing it - otherwise any
leaked key could mint a full-access successor for itself. This endpoint needs
only `account:read` because it creates nothing, changes nothing, and returns no
secret. The new key is issued in the browser, under the owner's own
authenticated session, after they review the form and click Create.

When the caller is an account-scoped `seq_user_` key, select the company with
the `x-company-id` header. Personal keys are routed to Account → API Keys;
company keys to workspace Settings → API Keys.

## Request

<ParamField body="name" type="string">
  Suggested name for the new key. Trimmed to 80 characters in the link.
</ParamField>

<ParamField body="preset" type="string">
  Suggested permission preset. Supported presets: `full_access`, `read_only`,
  `agent_safe`, `ai_drafting`, `data_ingest_safe`, `data_ingest_automations`,
  `transactional_sender`, `marketing_sender`.
</ParamField>

<ParamField body="scopes" type="string[]">
  Suggested explicit permission scopes. Overrides `preset`. An unsupported scope
  is rejected here rather than silently dropped from the owner's form.
</ParamField>

<ParamField body="replaceApiKeyId" type="string">
  ID of the key this one replaces. Pass the literal string `current` for the key
  the request is authenticated with. The dashboard offers to revoke the
  predecessor once the replacement exists, which finishes a rotation in a single
  visit.
</ParamField>

```bash theme={null}
curl -X POST "https://api.sequenzy.com/api/v1/api-key-handoff" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-company-id: company_abc123" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production sync (rotated)", "preset": "agent_safe", "replaceApiKeyId": "current"}'
```

## Responses

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true,
    "handoff": {
      "url": "https://sequenzy.com/dashboard/company/company_abc123/settings?tab=api-keys&action=create-api-key&keyName=Production+sync+%28rotated%29&keyPreset=agent_safe&replaces=key_abc123",
      "manageUrl": "https://sequenzy.com/dashboard/company/company_abc123/settings?tab=api-keys",
      "keyType": "company",
      "name": "Production sync (rotated)",
      "preset": "agent_safe",
      "scopes": null,
      "permissions": {
        "preset": "agent_safe",
        "fullAccess": false,
        "selectedScopeCount": 24,
        "currentScopeCount": 63,
        "description": "24 of 63 current permissions are enabled."
      },
      "replaces": {
        "id": "key_abc123",
        "name": "Production sync",
        "prefix": "seq_live_abcd",
        "isCurrentKey": true
      },
      "canSelfServe": false,
      "deliversKeyToCaller": false
    },
    "message": "Give this link to the workspace owner. It opens the dashboard create-key form with the requested name and permissions prefilled. The new key is shown in the browser and is never returned here.",
    "nextSteps": [
      "Send the URL to the workspace owner and stop. Nothing is created until they review the form and click Create.",
      "The owner copies the new key from the browser and puts it in your secret store. It is shown once and is never returned through the API.",
      "Verify the replacement by calling the account endpoint with the new key before retiring anything.",
      "Revoke the previous key: the dashboard offers it after the replacement is created, or the replacement can revoke it through the API when the owner grants it api_keys:manage."
    ]
  }
  ```

  `deliversKeyToCaller` is always `false`. `canSelfServe` is `true` when the
  calling key already holds `api_keys:manage` and could create the replacement
  directly with [Create API Key](/api-reference/api-keys/create); the link is then
  only needed when policy requires a human to confirm.

  `permissions` is the receipt for the suggested selection, and `scopes` is the
  expanded list. Both are `null` when the request suggested no preset and no
  scopes, because the form then opens on the dashboard's own default rather than
  on full access.

  `replaces.name` and `replaces.prefix` are populated only when the replaced key
  is the one making the request. Reading metadata for any other key requires
  `api_keys:manage`, so the dashboard resolves it under the owner's session.

  ```json 400 theme={null}
  {
    "error": "Unsupported API key scope: not:a:scope"
  }
  ```

  ```json 400 theme={null}
  {
    "error": "replaceApiKeyId is not a valid API key ID"
  }
  ```

  ```json 401 theme={null}
  {
    "error": "Invalid API key"
  }
  ```

  ```json 403 theme={null}
  {
    "error": "API key is missing required scope: account:read"
  }
  ```
</ResponseExample>

## Rotating a key you cannot manage

1. Call this endpoint with `replaceApiKeyId: "current"` and the permissions the
   replacement needs.
2. Hand the URL to the workspace owner and stop. Do not poll: the key never
   comes back through the API.
3. The owner reviews the prefilled form, creates the key, and stores it in your
   secret store.
4. Verify the replacement with [Get Account](/api-reference/account/get) before
   retiring anything.
5. Revoke the predecessor from the dashboard prompt, or with
   [Revoke API Key](/api-reference/api-keys/revoke) if the owner granted the new
   key `api_keys:manage`.
