# User accounts and email verification
A user needs a Done ID account before the user can sign in to your app. This page tells you how a user creates an account and how the email verification works.

## Create an account

Done OS creates all Done ID accounts. Your app does not create accounts.

1. The user selects "Create account" on the Done ID login page.
2. Done ID opens the registration page of Done OS.
3. The user enters a name, an email address, a password, and a phone number (optional).
4. Done OS creates the account and sends a verification email. The account is disabled until the user verifies the email address.
5. The user opens the link in the email.
6. Done OS enables the account and shows a login button.

## Send users back to your app after registration

If your app starts the onboarding, you can send the user back to your app after the user verifies the email address. Your backend creates a registration session and sends the user to the link that Done OS returns.

Before you start:

- You need a machine-to-machine client. See [Machine to machine](/machine-to-machine).
- Tell the Done team which URLs your app uses as redirect URLs, with your [client request](/request-a-client#information-to-send). The Done team adds them to your partner in each environment. Until then, creating a session fails with `INVALID_VALUE`.

The endpoint is part of the external API. See the OpenAPI file of the environment, `https://api.sandbox.done.ai/openapi/external_v1.json`, under the tag `RegistrationSessions`.

### Redirect URLs

A redirect URL must follow these rules:

- It uses `https`.
- The scheme, host, and port match an allowed URL exactly.
- The path matches an allowed URL exactly, or it is below an allowed URL that ends with `/*`. The entry `https://partner.company.io/onboarding/*` matches `https://partner.company.io/onboarding/done`, but not `https://partner.company.io/onboarding`.
- It has no user name or password, no backslash, no dot segments (`/../`), no `;`, and no encoded slashes.

Done OS checks the URL when you create the session and again when the user verifies the email address. If the Done team removes a URL from your partner, sessions that already exist stop redirecting to it.

### Create a session

Send a `POST` request with the access token of your client:

```bash
curl -X POST https://api.sandbox.done.ai/v1/registration-sessions \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "redirectUrlAfterVerification": "https://partner.company.io/onboarding/done",
    "email": "anna@example.com",
    "buttonText": "Back to Partner",
    "firstName": "Anna",
    "lastName": "Andersson",
    "phoneNumber": "+46701234567"
  }'
```

| Field | Required | Description |
|---|---|---|
| `redirectUrlAfterVerification` | Yes | The URL to send the user to after the verification. Maximum 2048 characters. |
| `email` | Yes | The email address of the user. The user registers with exactly this address. The registration page does not show the field, and the server rejects any other address. |
| `buttonText` | No | The text of the button that takes the user back to your app. Default `Continue`. Maximum 60 characters. |
| `firstName` | No | Prefilled first name. Maximum 100 characters. The user can edit it. |
| `lastName` | No | Prefilled last name. Maximum 100 characters. The user can edit it. |
| `phoneNumber` | No | Prefilled phone number in E.164 format, for example `+46701234567`. The user can edit it. |

Done OS returns `201 Created`:

```json
{
  "sessionId": "0b9f5c1e-8a2d-4f6e-9c41-5d7a3e2b1f90",
  "returnUrl": "https://app.sandbox.done.ai/registration?session-id=0b9f5c1e-8a2d-4f6e-9c41-5d7a3e2b1f90",
  "expiration": "2026-10-21T14:00:00+00:00"
}
```

| Field | Description |
|---|---|
| `sessionId` | The ID of the session. |
| `returnUrl` | The registration link for the user. Despite the name, this is not your redirect URL. |
| `expiration` | When the session expires (UTC). |

### What the user sees

1. Send the user to `returnUrl`.
2. The registration page shows the prefilled values. The email address is locked and hidden.
3. The user registers. Done OS sends the verification email.
4. The user opens the link in the email.
5. Done OS enables the account and shows a button with your `buttonText`. The user selects the button and returns to your redirect URL. There is no automatic redirect.

The user is not signed in to Done ID when the user arrives at your app. Start a normal login (see [User login](/user-login)) if your app needs a session. The redirect URL has no user ID or email address, so do not treat a user who arrives there as proof of registration. Check `email_verified` in the token after the login.

### Limits

- A session expires after 2 hours. The user must start the registration before it expires.
- A session works for one registration. A second registration with the same session fails.
- The verification link in the email is valid for 4 hours, even if the session has expired by then.
- If the verification link is expired, or a newer link replaced it, the user can register again on the plain registration page. The user does not return to your app. Create a new session and send the user to the new link.

### Errors

Creating a session can return these errors:

| Status | Error code | Cause |
|---|---|---|
| `400` | `MISSING_REQUIRED_VALUE` | `redirectUrlAfterVerification` or `email` is missing. |
| `400` | `INVALID_VALUE` | The redirect URL is not allowed for your partner, a value is too long, or a text contains control or direction-changing characters. |
| `400` | `INVALID_EMAIL` | The email address is invalid. |
| `400` | `INVALID_PHONE_NUMBER` | The phone number is not in E.164 format. |
| `401` | `UNAUTHORIZED` | The access token is missing, expired, or has no `partner_id` claim. |
| `403` | `FORBIDDEN` | The token is not allowed to call the partner API. |

If the session is unknown, expired, or already used, or the email does not match, the registration page shows an error and no form. Create a new session and send the user to the new link.

### Without a session

Without a session, the registration page and the verification link go to Done OS, and the user stays in Done OS after the verification. The user must go back to your app and sign in again. Because the Done ID session is active, the second login does not show the login page.

| Environment | Registration page |
|---|---|
| Sandbox | `https://app.sandbox.done.ai/registration` |
| Production | `https://app.done.ai/registration` |

## Check the email status

If your client has the `email` scope, the ID token and the access token contain `email_verified`. Use it if your app needs a confirmed email address.

## See also

- [Done ID for partner apps](/)
- [Machine to machine](/machine-to-machine)
