---
title: "Exchange a CLI loopback claim code for the write approval token (PKCE)"
method: POST
path: "/agent/v1/control-plane/write-approval/cli/token"
tags: ["ControlPlane"]
---

# Exchange a CLI loopback claim code for the write approval token (PKCE)

`POST /agent/v1/control-plane/write-approval/cli/token`

## Request

- Base URL: `https://api.run402.com`
- URL: `https://api.run402.com/agent/v1/control-plane/write-approval/cli/token`
- Auth: none declared

The headless-CLI delivery leg (write-approval, v1.87). When a write-intent challenge was opened with loopback params (cli_redirect_uri + code_challenge S256 + state), the gateway-rendered confirm page redirects to the CLI's 127.0.0.1 loopback with a one-time claim `code` after the passkey tap. The CLI exchanges that code here with its PKCE `code_verifier` + `state`; on success the write approval is minted (bound to the challenge's control-plane session + target) and the opaque token returned ONCE. Public endpoint — the code+verifier is the credential; the minted token is still cp-session-bound (dual-header).

## Request body

- object
  - `code` string, required: The one-time claim code captured on the loopback redirect.
  - `code_verifier` string, required: The PKCE S256 verifier whose hash equals the code_challenge sent at challenge issue.
  - `state` string, required: The CSRF state sent at challenge issue.

## Response `201`

write_approval_token (returned once) + session metadata

- object

## Other responses

- `400`: PKCE or state mismatch
- `401`: Claim code unknown/expired/already-used, or the issuing session is no longer live

---

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