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

# Let your agents sign in with Versine

> Vouch for your users so your agents can sign in and sign up on Versine platforms.

When your agent reaches a Versine sign-in, your backend tells Versine who your
user is and gets back a one-time **sign-in token**. Your agent's browser sends
it to Versine, which returns the agent to the platform, signed in. Your users
never need a Versine account.

Versine handles the tokens, keys and platform rules. You add three things:

1. **A sign-in token request** from your backend: when your agent reaches a
   Versine sign-in, you send Versine your user's details and get back a
   one-time token for that sign-in.
2. **A browser hook** that adds the token to the Versine sign-in request.
3. **A consent model** to verify which sites your users want to allow signing
   into.

See [How Versine works](/docs/how-it-works) for the full flow.

## 1. Register your assistant

Register an assistant in Console. You get an
assistant ID, which platforms see in every sign-in, and a secret:

```bash theme={null}
VERSINE_ASSISTANT_ID=example-assistant
VERSINE_ASSISTANT_SECRET=...   # your backend only; never the browser or the agent
```

Until Versine approves your registration, you can sign in only to
[demo.versine.com](https://demo.versine.com) and platform projects in your own
Console organization.

<Accordion title="Rotate or revoke your secret">
  In Console, create a second secret, switch to it, then revoke the old one. You
  can also limit the secret to your backend's IP addresses. Console lists every
  sign-in made with your credentials. If a secret leaks, revoke it or contact
  [security@versine.com](mailto:security@versine.com).
</Accordion>

## 2. Recognize a Versine sign-in

Tell your agent to use Versine when a site offers it, for example in its system
prompt:

```text theme={null}
When you need to sign in to or sign up for a website and it offers
"Continue with Versine" or "Are you an agent?", choose that option.
```

The browser is then sent, often through redirects, to
`https://auth.versine.com/authorize?client_id=...&scope=...`. Your browser hook
catches that request ([step 4](#4-add-the-token-to-the-request)).

## 3. Request a sign-in token

```bash theme={null}
curl https://api.versine.com/v1/sign-ins \
  -u "$VERSINE_ASSISTANT_ID:$VERSINE_ASSISTANT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://auth.versine.com/authorize?client_id=...",
    "user": {
      "id": "usr_8f2c…",
      "email": "ada@example.com",
      "emailVerification": { "method": "provider_sso", "provider": "google", "verifiedAt": "2026-09-20T09:30:00Z" },
      "givenName": "Ada",
      "familyName": "Lovelace"
    }
  }'
```

```json theme={null}
{ "token": "vsi_…", "expiresAt": "2026-10-01T12:01:00Z" }
```

The token works once, for that URL only, within 60 seconds.

| Field | Scope | Value |
| - | - | - |
| `url` | | The exact URL the browser is about to request |
| `user.id` | `openid` | Your stable, opaque user ID. Never an email, never reused |
| `user.givenName`, `user.familyName` | `profile` | First and last name |
| `user.email`, `user.emailVerification` | `email` | Email address, and how you verified it |
| `user.phoneNumber`, `user.phoneVerification` | `phone` | Number in E.164 format, and how you verified it |

Platforms that follow the [setup guide](/docs/platforms) request
`openid profile email phone`; the URL's `scope` parameter says which. Versine
passes on only the requested details and doesn't check consent. If you leave a
detail out, the platform gets the sign-in without it. Many platforms can't
create an account without an email.

| Status | Error | Meaning |
| - | - | - |
| `403` | `assistant_not_accepted` | The platform doesn't accept your assistant |
| `403` | `assistant_not_approved` | Your registration isn't approved, and this isn't your project |
| `404` | `sign_in_not_found` | Unknown or paused platform, or unknown sign-in page |
| `401` | `invalid_client` | Wrong assistant ID or secret |

<Accordion title="Show your user which platform they're signing in to">
  `GET /v1/sign-ins/preview?url=…`, with the same credentials, returns the
  platform's `name`, `logoUrl`, `termsUrl` and `privacyUrl`, and the requested
  `scopes`. Use these rather than anything on the web page.
</Accordion>

### Report verification

Platforms use verification to decide whether a sign-in can reach an existing
account. Versine treats an email as verified for a year after `verifiedAt`, and
a phone number for 30 days.

| Field | `method` | Meaning |
| - | - | - |
| `emailVerification` | `provider_sso` | Your user signed in through `google`, `apple` or `microsoft` (`provider`), which said the address is verified. For Microsoft, only tenant-verified domains |
| `emailVerification` | `otp` | Your user used a one-time code or link sent to the address |
| `phoneVerification` | `messaging` | Your user messages you from this number (`channel`: `sms`, `whatsapp`, `imessage` or `rcs`). `verifiedAt` is their latest message. For `sms`, confirm the number once with a code first |
| `phoneVerification` | `otp` | Your user entered a one-time code sent to the number |

If you haven't verified a value, leave out its verification object.

## 4. Add the token to the request

In the browser your agent drives, intercept requests to
`https://auth.versine.com/authorize`, including redirects, and add the token as
the `Versine-Sign-In` header:

```ts theme={null}
browser.onRequest(async (request) => {
  const url = new URL(request.url);
  if (
    url.origin !== "https://auth.versine.com" ||
    url.pathname !== "/authorize"
  )
    return request.continue();

  const token = await backend.versineSignIn(request.url, session.userId);
  if (!token) return request.abort(); // you chose not to sign in here

  return request.continue({
    headers: { ...request.headers, "Versine-Sign-In": token },
  });
});
```

`browser.onRequest` stands for your runtime's request interception, such as the
Chrome DevTools Protocol's `Fetch` domain. On failure, Versine shows an error
page with a `Versine-Sign-In-Error` header:

| Error | Meaning |
| - | - |
| `token_invalid` | Unknown token, or requested for a different URL |
| `token_expired` | Older than 60 seconds; request it just before navigating |
| `token_used` | Already used; request a new one for every attempt |
| `platform_unavailable` | The platform paused or deleted its project |

<Warning>
  A sign-in token signs in as your user. Add it only to requests to
  `https://auth.versine.com/authorize`, and keep it away from the model, page
  scripts, tool results, logs and screenshots. Request it in the browser layer,
  not through a tool the agent can call. Keep your secret on your backend.
</Warning>

## Use a code instead of a header

If your agent's browser can't add headers, and the platform allows code
sign-in, the Versine sign-in page asks for a code instead. Give your agent a
tool that takes the page's address. Your backend calls `POST /v1/sign-ins` with
that address as `url` and `"delivery": "code"`:

```json theme={null}
{ "code": "K7QM-4ZPX", "expiresAt": "2026-10-01T12:02:00Z" }
```

The agent types the code into the page. It works once, on that page only, for
two minutes.

<Warning>
  The code signs in as your user. Tell your agent to type it only into the
  `auth.versine.com` page it requested it for, and never to share it anywhere
  else.
</Warning>

## 5. Test

Test your integration at [demo.versine.com](https://demo.versine.com), a sample
platform that accepts every registered assistant. Then request review in
Console.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.