Browse documentationDevice flow

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 whoami

The 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
POST/v1/feedback

Submit 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
POST/v1/auth/email/start

Email 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
POST/v1/auth/email/verify

Exchange 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
POST/v1/device/code

Begin 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
POST/v1/device/token

Poll 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
POST/v1/device/inspect

Inspect 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
POST/v1/device/approve

Approve 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
POST/v1/device/deny

Deny 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
GET/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
POST/v1/oauth/authorization/{requestId}/approve

Bind 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
POST/v1/oauth/authorization/{requestId}/deny

Deny 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