© 2026 dots.id
TermsPrivacyApps
← developerscreate client
# Getting a dots API key

A dots app is registered with an **OAuth client ID** (`client_id`). This public identifier is not a bearer API key and grants no access by itself. The published browser SDK takes it as `apiKey`; the core SDK calls it `clientId`.

Start with [the install guide](/install) to choose SDK or HTTP, client credentials, and scopes by app function. Agents should read [/install/llms.txt](/install/llms.txt).

## 1. Sign in to the dev portal

Go to your dots issuer's `/dev/clients` page. For local development, use the full HTTPS origin emitted by Portless, including its configured proxy port. Sign in with your dots account.

## 2. Create a client → **New client**

You'll set:

| Field | What to put |
|---|---|
| **Name** | your app's display name (shown on the consent screen) |
| **Client type** | **Public** for browser/SPA/mobile (PKCE, no secret). **Confidential** for server apps (issues a secret). |
| **Redirect URIs** | every callback URL, exact match — e.g. `https://yourapp.com/dots/callback`; locally use the full HTTPS Portless origin plus callback path |
| **Scopes** | `openid profile` to start; request `email` or `wallet` only if needed; add other scopes by app function |

On create you get:
- **`client_id`** → this is your `apiKey`.
- **`client_secret`** → shown **once**, only for confidential clients. Store it server-side (never ship it to the browser). Rotate via `/api/dashboard/clients/[id]/regenerate-secret`.

## 3. Use it

```ts
// Published @wrldbld/dots@0.1.0-alpha.0 browser SDK
const dots = createDots({ apiKey: "YOUR_PUBLIC_CLIENT_ID", issuer: "https://www.dots.id" });
```

Public client → the SDK runs PKCE in the browser; no secret needed.
Confidential client → keep the secret on your server and exchange the code there.
The browser SDK and dots-core client do not accept a client secret.
Use your server OIDC library for confidential clients. Installing an SDK never
replaces registration and the user's consent; protected APIs require the resulting access token.

Persist the signed-in account under a database-unique **`(issuer, sub)`** key.
The dots-owned `sub` is stable; email, wallet, username, and social handles are
claims and must never create or merge accounts.

## Scopes cheat-sheet

`openid` (required) · `profile` · `username:create` (first-time claim on `/oauth/claim`; enable per client) · `email` · `wallet` ·
`social:google|twitter|instagram` · `listen` (streaming sources + plays) ·
`data:read` `data:write` (per-app Turso) · `files:read` `files:write` `files:share` ·
`context:read` `context:write` (portable context + MCP `search`/`recent`/`remember`) ·
`pute:read` `pute:spend` `pute:topup` · `mcp:use` (call third-party MCPs connected to the dot) ·
`cosign` `delegate` `org:act` `org:admin` · `offline_access` (refresh tokens).

The canonical list is `scopes_supported` in `/.well-known/openid-configuration`.
Self-serve dynamic registration (`POST /api/oauth/register`) allows a narrower set;
sensitive scopes are enabled per client in the dev portal.

## No browser? Use the device flow

Bots, CLIs, and chat agents can't host a redirect URI. Register a **public** client,
call `POST /api/oauth/device`, show the `user_code` / `verification_uri_complete`, and
poll `POST /api/oauth/token` with `grant_type=urn:ietf:params:oauth:grant-type:device_code`.
The user approves at `https://www.dots.id/oauth/device`. Full details in the
[REST reference](/docs/api).

> The dev portal also issues per-app **redirect URIs** and lets you mark a client internal/verified. Only the client owner can manage their clients.


## Agent-first registration

Use `registerDotsApp({ name, redirectUris, scope })` from `@wrldbld/dots-core@0.2.0-alpha.0`, or `dots app register --name "My app" --redirect-uri https://my-app.example/dots/callback`.
For a headless agent, use `mode: 'device'` in the SDK or `--device` in the CLI.
Save the returned `clientId` once per app/environment and inspect `missingScopes`.
Do not repeat registration at startup. Dynamic registrations are unowned and
cannot be edited in your dashboard; use an owned client for restricted scopes or
ongoing management. [Core SDK and WebMCP setup](/docs/webmcp) covers package
availability, sign-in, all tools, and verification.