> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywithlocus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent-native onboarding

> Verify an agent through AgentID, activate a restricted Locus Pro account, fund it, and connect through MCP OAuth.

An agent can create a restricted Locus Pro account without a Locus dashboard identity, invitation, or existing workspace. Before Locus creates a durable account, the agent must prove a stable AgentID subject and live verified agent inbox through an authorization-code flow. The activated account starts at exactly **\$0**, receives no free or bonus credits, and can manage only its own credential, catalog enablement, funding handoffs, balance, and metered calls.

<Info>
  Start with `GET /api/credits/agent/onboarding`. It is public and returns the current machine-readable flow, URLs, and security boundaries. Treat that response and the [API reference](/api-reference/introduction) as authoritative.
</Info>

## 1. Generate a recovery token

Generate exactly 24 cryptographically random bytes and encode them as unpadded base64url. The result is 32 characters:

```javascript theme={null}
import { randomBytes } from "node:crypto";

const registrationToken = randomBytes(24).toString("base64url");
```

For the shell examples below, generate and retain one token:

```bash theme={null}
export LOCUS_REGISTRATION_TOKEN="$(node -e 'console.log(require("node:crypto").randomBytes(24).toString("base64url"))')"
```

Store this token like a recovery secret. Locus stores only its digest. Reusing the same account name and token is replay-safe; using the token with different account details returns `409`.

## 2. Begin registration

```bash theme={null}
curl -X POST "https://api.paywithlocus.com/api/credits/agent/register" \
  -H "Content-Type: application/json" \
  -d "{\"name\":\"research-agent\",\"registrationToken\":\"$LOCUS_REGISTRATION_TOKEN\"}"
```

You can also send `agentEmail` as an optional AgentID login hint. The verified AgentID token claim remains authoritative.

The response envelope is `{ "success": true, "account": { … } }`. The first
request returns HTTP `202` with `account.onboardingState` set to
`"identity_required"`, a 15-minute pending registration, and
`account.registration.authorizationUrl`. No account or Locus credential exists
yet.

## 3. Verify with AgentID and replay

Open `account.registration.authorizationUrl` and approve it with the agent's AgentID credential. A browserless agent can complete this entirely over HTTP: retain the cookie from the AgentID authorization request, sign the exact 22-character request ID with the inbox's P-256 key, submit the approval, then call AgentID's `/v0/authorize/continue` with the same cookie and follow every redirect. Preserve the final `code`, `state`, and `iss` parameters exactly. The canonical [`agent/auth.md`](https://paywithlocus.com/agent/auth.md) reference defines the signing payload, approval endpoint, and cookie handling; do not infer them from a search result.

The Locus callback validates the issuer, audience, nonce, PKCE exchange, stable subject, and live inbox, then displays a static result page. The callback never returns a Locus credential.

Before the pending registration expires, replay the **exact same** name and registration token:

```bash theme={null}
curl -X POST "https://api.paywithlocus.com/api/credits/agent/register" \
  -H "Content-Type: application/json" \
  -d "{\"name\":\"research-agent\",\"registrationToken\":\"$LOCUS_REGISTRATION_TOKEN\"}"
```

Activation returns `201` for a new account or `200` for an existing, renewed, or recovered account. Store `account.connection.credential` immediately. It is an `lcac_…` compatibility credential for the authenticated account-management REST calls on this page; Locus reveals it only on registration replay and rotation.

```bash theme={null}
export LOCUS_AGENT_CREDENTIAL="lcac_..."
```

Read the account at any time:

```bash theme={null}
curl "https://api.paywithlocus.com/api/credits/agent/account" \
  -H "Authorization: Bearer $LOCUS_AGENT_CREDENTIAL"
```

The response reports the exact decimal-string balance, credential expiry, useful links, and `onboardingState`: `funding_required` or `ready`.

## 4. Connect the agent through MCP OAuth

Configure this Streamable HTTP MCP URL in a client with native OAuth:

```text theme={null}
https://api.paywithlocus.com/api/credits/mcp
```

At the Locus authorization screen, choose AgentID and approve with the same identity used during registration. The MCP client stores and refreshes its own OAuth tokens. Use this OAuth connection for tools; do not paste the `lcac_…` compatibility credential into an interactive MCP client.

On a headless host, keep the MCP client's login process and loopback listener alive. Follow its authorization URL, retain the `request=lmo_req_…` handle from the Locus consent URL, and read the signed-out context:

```bash theme={null}
curl "https://api.paywithlocus.com/api/credits/mcp/oauth/authorize/public-context?request=$LOCUS_MCP_REQUEST"
```

Follow `data.agentIdAuthorizationUrl` with a cookie jar, complete the same browserless AgentID approval used for registration, and follow the redirects back to the MCP client's exact callback URI. Supply a final callback URL or code manually only when that client explicitly supports it. See [Connect agents](/locus-pro/connect-agents#agent-owned-headless-oauth) for the complete handoff.

## 5. Find and enable capabilities

Search includes disabled entries so an agent can discover an exact slug before enabling it:

```bash theme={null}
curl -X POST "https://api.paywithlocus.com/api/credits/agent/catalog/search" \
  -H "Authorization: Bearer $LOCUS_AGENT_CREDENTIAL" \
  -H "Content-Type: application/json" \
  -d '{ "query": "current web evidence", "limit": 5 }'
```

Enable one exact ordinary-provider result, such as `tavily/search`. Agent-owned
accounts can change only the `enabled` flag; they cannot change pricing or other
tenant settings. The system-managed `router` provider is not mutable through
this endpoint.

```bash theme={null}
curl -X PUT "https://api.paywithlocus.com/api/credits/agent/catalog" \
  -H "Authorization: Bearer $LOCUS_AGENT_CREDENTIAL" \
  -H "Content-Type: application/json" \
  -d '{ "slug": "tavily/search", "enabled": true }'
```

## 6. Hand funding to a payer

First read the live constraints:

```bash theme={null}
curl "https://api.paywithlocus.com/api/credits/agent/funding/config" \
  -H "Authorization: Bearer $LOCUS_AGENT_CREDENTIAL"
```

Then create an exact-amount Stripe Checkout handoff. Reuse the same `Idempotency-Key` when retrying the same logical handoff.

```bash theme={null}
curl -X POST "https://api.paywithlocus.com/api/credits/agent/funding-sessions" \
  -H "Authorization: Bearer $LOCUS_AGENT_CREDENTIAL" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "usd": "20.00" }'
```

Send the payer the returned `humanHandoff.message` or `checkoutUrl`. It expires after one hour. The payer does not become the account owner, and the card is not attached for future use or delegated to the agent. Never ask the payer to send card details through chat.

Poll the authenticated `statusUrl` no faster than `pollAfterMs`. Continue only when `state` is `ready`: that state means the signed Stripe webhook has been consumed and the ledger balance is usable. A browser return or Stripe payment status alone is not enough.

| State              | Meaning                                                               | Next action                                        |
| ------------------ | --------------------------------------------------------------------- | -------------------------------------------------- |
| `awaiting_payment` | The Stripe Checkout Session is open and unpaid                        | Keep the current link until it expires             |
| `processing`       | Stripe reports payment, but the durable ledger update is not complete | Poll again after `pollAfterMs`                     |
| `ready`            | The payment webhook was consumed and the balance is usable            | Continue to Locus tools                            |
| `expired`          | The link expired before credits became usable                         | Create a new funding session                       |
| `failed`           | Payment or credit issuance reached a terminal failure                 | Check the prior attempt before creating a new link |

## 7. Use Locus

Use the MCP OAuth connection for tool discovery and execution. Keep the `lcac_…` compatibility credential for the agent-account, catalog, funding, and rotation REST routes documented by this flow. It works only for its agent-owned account; tenant-managed Agent Connection endpoints reject it where the two account models must stay separate.

## Rotate the credential

Generate a new 24-byte base64url recovery token, then rotate while the current credential is still valid:

```bash theme={null}
export LOCUS_NEW_REGISTRATION_TOKEN="$(node -e 'console.log(require("node:crypto").randomBytes(24).toString("base64url"))')"

curl -X POST "https://api.paywithlocus.com/api/credits/agent/credential/rotate" \
  -H "Authorization: Bearer $LOCUS_AGENT_CREDENTIAL" \
  -H "Content-Type: application/json" \
  -d "{\"registrationToken\":\"$LOCUS_NEW_REGISTRATION_TOKEN\"}"
```

Rotation atomically replaces both the recovery digest and bearer credential, returns the new `lcac_…` value once, and extends expiry by 365 days. Replace the stored credential and recovery token together.

<Warning>
  Never send the bearer credential or registration token to a payer. The public funding status contains only the funding state, agent display name, and credited amount.
</Warning>
