> ## Documentation Index
> Fetch the complete documentation index at: https://doc.playsmart.api.dolly.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Register and authenticate players with the PlaySmart API

> Step-by-step guide to creating player accounts and authenticating returning players using the PlaySmart API's register and login endpoints.

Before your game can call any protected endpoint, each player needs an account and a valid access token. PlaySmart handles authentication through two simple endpoints: `POST /auth/register` creates a new account and returns tokens immediately, and `POST /auth/login` does the same for returning players. Both return the same response shape, so your token-handling code only needs to be written once.

<Steps>
  <Step title="Register a new player">
    Call `POST /auth/register` with the player's email address, a password of at least 8 characters, and a `deviceId` that uniquely identifies their device. The `deviceId` becomes the player's `auth_user_id` and is used as the JWT `sub` claim on every subsequent request.

    ```bash theme={null}
    curl -X POST https://playsmart-gateway-1w8ko864.uc.gateway.dev/auth/register \
      -H "Content-Type: application/json" \
      -d '{
        "email": "player@example.com",
        "password": "s3cur3pass",
        "deviceId": "device-abc-123"
      }'
    ```

    A successful registration returns HTTP `201` with the following body:

    ```json theme={null}
    {
      "data": {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "user": {
          "id": "device-abc-123",
          "email": "player@example.com",
          "pseudo": "",
          "total_games_completed": 0
        }
      }
    }
    ```
  </Step>

  <Step title="Store tokens securely">
    Save both tokens on the device immediately after registration or login.

    * **`access_token`** — valid for **30 days**. Include this in the `Authorization` header on every authenticated request.
    * **`refresh_token`** — valid for **180 days**. Use this to obtain a new `access_token` when the current one expires.

    Store tokens in your platform's secure credential store (for example, Android Keystore or iOS Keychain). Do not store them in plain shared preferences or `PlayerPrefs`.
  </Step>

  <Step title="Log in returning players">
    For a player who already has an account, call `POST /auth/login` with their email and password. No `deviceId` is needed here.

    ```bash theme={null}
    curl -X POST https://playsmart-gateway-1w8ko864.uc.gateway.dev/auth/login \
      -H "Content-Type: application/json" \
      -d '{
        "email": "player@example.com",
        "password": "s3cur3pass"
      }'
    ```

    A successful login returns HTTP `200` with the same response shape as registration:

    ```json theme={null}
    {
      "data": {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "user": {
          "id": "device-abc-123",
          "email": "player@example.com",
          "pseudo": "CoolPlayer99",
          "total_games_completed": 0
        }
      }
    }
    ```
  </Step>

  <Step title="Use the access token">
    Add the `access_token` as a Bearer token in the `Authorization` header on every protected API call. All `/v1/*` and `/ingest/*` endpoints require this header.

    ```bash theme={null}
    curl https://playsmart-gateway-1w8ko864.uc.gateway.dev/v1/games \
      -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    ```

    If the token is missing or invalid, the API returns `401 UNAUTHORIZED`.
  </Step>
</Steps>

## Error handling

| HTTP status        | Error code                 | Meaning                                                                                                                                                                       |
| ------------------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `409 CONFLICT`     | `email_already_registered` | An account with that email already exists. Prompt the player to log in instead.                                                                                               |
| `401 UNAUTHORIZED` | `invalid_credentials`      | The email and password combination does not match any account.                                                                                                                |
| `400 BAD_REQUEST`  | `invalid_payload`          | The request body failed validation — for example, the password is fewer than 8 characters or the email is malformed. Check the `details` field in the response for specifics. |
