---
title: "Exchange a CLI authorization code for a key"
method: POST
path: "/api/v1/cli/token"
tags: ["authentication"]
---

# Exchange a CLI authorization code for a key

`POST /api/v1/cli/token`

## Request

- Base URL: `https://index365.co`
- URL: `https://index365.co/api/v1/cli/token`
- Auth: none required

Keyless second leg of `index365 login --web`. Swaps the single-use PKCE authorization code (minted on the dashboard consent screen) plus the PKCE code_verifier for a freshly minted, scoped API key. Unauthenticated by design (the client has no key yet); the code is single-use, short-lived, loopback-bound, and PKCE-S256-bound. Not for manual use - the dashboard API Keys page is how humans create keys.

## Request body

- object
  - `code` string, required: Single-use authorization code from the loopback callback.
  - `code_verifier` string, required: PKCE verifier whose S256 hash is the stored code_challenge.
  - `redirect_uri` string, required: The exact loopback redirect_uri the CLI registered.

## Response `201`

Credential issued. The secret is returned exactly once.

## Other responses

- `400`: invalid_request (missing fields) | invalid_grant (unknown/expired/used/mismatched code).
- `500`: internal_error: the credential could not be issued.
- `503`: key_encryption_unavailable | service_unavailable.

---

[API](https://skmtc.dev/index365/apis/index365-api.md) · [All operations](https://skmtc.dev/index365/apis/index365-api/llms.txt) · [OpenAPI document](https://skmtc.dev/index365/apis/index365-api/revisions/87dd7b85edcb?raw)
