Authorization
Approval signs the terminal in as you
Device flow lets a command-line tool show a short verification code and poll while the user approves or denies it in a signed-in browser. The tool receives a human identity key; it never receives the user's browser credentials.
Request a login
The request describes the client with client_name. It does not request scopes, select a
workspace or register a sync machine. The browser approves the person signing in. Current
workspace membership and role determine access after approval, just as they do in the app.
duet login
duet whoamiThe CLI saves the approved key in ~/.duet/config.json, preserving its existing workspace
preference and machine identity. Select a workspace for an operation afterwards; approval does
not bind the key to a single workspace. See workspace selection.
Sync uses that same login
duet sync install uses the saved human key and registers the Mac's separate, non-secret machine
identity. There is no additional sync login. Replacing a key keeps the Mac's certificate and
identity, while removing that Mac stops its mirrors without revoking your other logins.
See Mac sync and mirror devices for the transfer lifecycle.
Poll until a terminal result
Pending, approved, denied and expired are different states. Honor the returned polling interval and rate-limit response, and stop on denial or expiry. Save an approved credential before reporting success so the next command can use it.
Verification codes are temporary correlation values, not credentials. Keep the resulting key out of logs and transcripts, and do not reuse a code after a terminal result.
Device
11 operations /v1 /feedbackSubmit anonymous product feedback; accepted asynchronously and rate limited.
- Scope
public- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "content": { "type": "string", "minLength": 1 }, "source": { "type": "string", "maxLength": 128 } }, "required": [ "content" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": {}, "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /auth /email /startEmail a sign-in code to a human so an agent holding no credential can finish sign-in on their behalf.
- Scope
public- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "email": { "type": "string", "format": "email", "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" }, "client_name": { "type": "string", "minLength": 1, "maxLength": 64 } }, "required": [ "email" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "request_id": { "type": "string", "pattern": "^req_[a-f0-9]{32}$" }, "expires_in": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "request_id", "expires_in" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /auth /email /verifyExchange the emailed code for a workspace-scoped API key, registering the human if they are new.
- Scope
public- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "request_id": { "type": "string", "pattern": "^req_[a-f0-9]{32}$" }, "code": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" }, "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "workspace_name": { "type": "string", "minLength": 1, "maxLength": 100 }, "workspace_slug": { "type": "string" } }, "required": [ "request_id", "code" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "access_token": { "type": "string", "pattern": "^duet_sk_.*" }, "token_type": { "type": "string", "const": "bearer" }, "prefix": { "type": "string", "pattern": "^duet_sk_.*" }, "scopes": { "minItems": 1, "type": "array", "items": { "type": "string" } }, "workspace": { "type": "object", "properties": { "slug": { "type": "string" }, "name": { "type": "string" } }, "required": [ "slug", "name" ], "additionalProperties": false }, "created": { "type": "boolean" } }, "required": [ "access_token", "token_type", "prefix", "scopes", "workspace", "created" ], "additionalProperties": false }- Errors
Error body JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "type": "object", "properties": { "error": { "type": "string", "const": "invalid_code" }, "attempts_remaining": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "error", "attempts_remaining" ], "additionalProperties": false }, { "type": "object", "properties": { "error": { "type": "string", "const": "workspace_ambiguous" }, "workspaces": { "type": "array", "items": { "type": "object", "properties": { "slug": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string", "enum": [ "owner", "editor", "viewer" ] } }, "required": [ "slug", "name", "role" ], "additionalProperties": false } } }, "required": [ "error", "workspaces" ], "additionalProperties": false }, { "type": "object", "properties": { "error": { "type": "string", "const": "expired" } }, "required": [ "error" ], "additionalProperties": false }, { "type": "object", "properties": { "error": { "type": "string", "const": "forbidden" } }, "required": [ "error" ], "additionalProperties": false }, { "type": "object", "properties": { "error": { "type": "string", "const": "invalid_request" } }, "required": [ "error" ], "additionalProperties": false }, { "type": "object", "properties": { "error": { "type": "string", "const": "rate_limited" }, "retryAfterSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "error", "retryAfterSeconds" ], "additionalProperties": false } ] }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /device /codeBegin a first-party human login through device-code approval.
- Scope
public- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "client_name": { "type": "string", "minLength": 1 } }, "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "device_code": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "user_code": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" }, "verification_uri": { "type": "string", "format": "uri" }, "expires_in": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "interval": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "device_code", "user_code", "verification_uri", "expires_in", "interval" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /device /tokenPoll a CLI login and receive its human identity key once approved.
- Scope
public- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "device_code": { "type": "string", "pattern": "^[a-f0-9]{64}$" } }, "required": [ "device_code" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "pending" }, "interval": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "status", "interval" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "const": "slow_down" }, "interval": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "status", "interval" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "const": "denied" } }, "required": [ "status" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "const": "expired" } }, "required": [ "status" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "const": "consumed" } }, "required": [ "status" ], "additionalProperties": false }, { "type": "object", "properties": { "status": { "type": "string", "const": "approved" }, "access_token": { "type": "string", "pattern": "^duet_sk_.*" }, "token_type": { "type": "string", "const": "bearer" }, "prefix": { "type": "string", "pattern": "^duet_sk_.*" } }, "required": [ "status", "access_token", "token_type", "prefix" ], "additionalProperties": false } ] }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /device /inspectInspect a pending CLI login as the signed-in user.
- Scope
human- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "userCode": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" } }, "required": [ "userCode" ], "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "userCode": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "consumed", "expired" ] }, "expiresAt": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "clientName": { "type": "string" } }, "required": [ "userCode", "status", "expiresAt" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /device /approveApprove a pending CLI login as the signed-in user.
- Scope
human- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "userCode": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" } }, "required": [ "userCode" ], "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "userCode": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "consumed", "expired" ] }, "expiresAt": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "clientName": { "type": "string" } }, "required": [ "userCode", "status", "expiresAt" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /device /denyDeny a pending CLI login as the signed-in user.
- Scope
human- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "userCode": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" } }, "required": [ "userCode" ], "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "userCode": { "type": "string", "pattern": "^[A-Z2-9]{4}-[A-Z2-9]{4}$" }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "consumed", "expired" ] }, "expiresAt": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "clientName": { "type": "string" } }, "required": [ "userCode", "status", "expiresAt" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /oauth /authorization /{requestId}Inspect a trusted OAuth authorization snapshot as the signed-in user.
- Scope
human- Request
- No JSON request body
- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ] }, "client": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "name": { "type": "string" } }, "required": [ "id", "name" ], "additionalProperties": false }, "redirect": { "type": "object", "properties": { "hostname": { "type": "string", "minLength": 1 }, "localhost": { "type": "boolean" } }, "required": [ "hostname", "localhost" ], "additionalProperties": false }, "capabilities": { "minItems": 1, "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members", "admin" ] } }, "workspaces": { "type": "array", "items": { "type": "object", "properties": { "slug": { "type": "string" }, "name": { "type": "string", "minLength": 1 }, "role": { "type": "string", "enum": [ "owner", "editor", "viewer" ] } }, "required": [ "slug", "name", "role" ], "additionalProperties": false } }, "expiresAt": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "status", "client", "redirect", "capabilities", "workspaces", "expiresAt" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /oauth /authorization /{requestId} /approveBind an OAuth authorization to an eligible workspace.
- Scope
human- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "workspaceSlug": { "type": "string" } }, "required": [ "workspaceSlug" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "redirectUrl": { "type": "string", "format": "uri" } }, "required": [ "redirectUrl" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /oauth /authorization /{requestId} /denyDeny an OAuth authorization with a server-built completion redirect.
- Scope
human- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": {} }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "redirectUrl": { "type": "string", "format": "uri" } }, "required": [ "redirectUrl" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent