Browse documentationGetting started

Start here

Make the first request boring

Keep the API origin, credential, and workspace selection explicit. A small request helper makes authentication consistent without hiding status codes or response headers that callers need for errors, pagination, and streaming.

Configure the client

Store keys in a secret manager or local environment file outside source control. Duet accepts a Bearer credential; never place a key in a URL, query string, build artifact, or browser bundle.

export DUET_API_URL="https://ctl.duet.so"
export DUET_API_KEY="duet_sk_replace_with_your_key"
export async function duetRequest(path: `/v1/${string}`, init: RequestInit = {}) {
  const response = await fetch(`${process.env.DUET_API_URL}${path}`, {
    ...init,
    headers: {
      authorization: `Bearer ${process.env.DUET_API_KEY}`,
      ...init.headers,
    },
  })
 
  if (!response.ok) throw new Error(`Duet request failed: ${response.status}`)
  return response
}

Inspect the credential

Start with GET /v1/whoami. It returns the person, current workspace memberships and roles, and effective access without changing state. Human access follows those live memberships; it is not a fixed list of permissions saved on the key.

curl --fail-with-body \
  --header "Authorization: Bearer $DUET_API_KEY" \
  "$DUET_API_URL/v1/whoami"

Then open the endpoint reference and select an operation whose required scope is available to the caller in the selected workspace.

Preserve the response

Do not immediately flatten every response into application-specific data. Status, headers, cursor fields, and event identifiers are part of the protocol and often carry the information needed to recover after a failure.