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

# Authentication

> PingBack uses JWT Bearer tokens. Learn how to obtain your token and authenticate every API request.

Every PingBack API request must include a valid Bearer token in the `Authorization` header. You get this token by registering or logging in. PingBack also supports signing in with Google.

## Register

Create a new account by sending your email address, full name, and a password. Passwords must be at least 8 characters.

`POST /api/v1/auth/register`

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.pingback.live/api/v1/auth/register \
    -H "Content-Type: application/json" \
    -d '{
      "email": "you@example.com",
      "full_name": "Ada Lovelace",
      "password": "supersecret123"
    }'
  ```

  ```javascript JavaScript (fetch) theme={null}
  const response = await fetch("https://api.pingback.live/api/v1/auth/register", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "you@example.com",
      full_name: "Ada Lovelace",
      password: "supersecret123",
    }),
  });

  const { access_token } = await response.json();
  ```
</CodeGroup>

**Request body**

<ParamField body="email" type="string" required>
  Your email address. Must be a valid email format.
</ParamField>

<ParamField body="full_name" type="string" required>
  Your display name shown in the PingBack dashboard.
</ParamField>

<ParamField body="password" type="string" required>
  Must be at least 8 characters.
</ParamField>

**Response**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}
```

<ResponseField name="access_token" type="string">
  The JWT you'll include in every subsequent request.
</ResponseField>

<ResponseField name="token_type" type="string">
  Always `"bearer"`.
</ResponseField>

***

## Log in

If you already have an account, exchange your email and password for a token.

`POST /api/v1/auth/login`

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.pingback.live/api/v1/auth/login \
    -H "Content-Type: application/json" \
    -d '{
      "email": "you@example.com",
      "password": "supersecret123"
    }'
  ```

  ```javascript JavaScript (fetch) theme={null}
  const response = await fetch("https://api.pingback.live/api/v1/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "you@example.com",
      password: "supersecret123",
    }),
  });

  const { access_token } = await response.json();
  ```
</CodeGroup>

**Request body**

<ParamField body="email" type="string" required>
  The email address you registered with.
</ParamField>

<ParamField body="password" type="string" required>
  Your account password.
</ParamField>

**Response**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}
```

***

## Authenticate requests

Pass your token in the `Authorization` header on every protected API call:

```
Authorization: Bearer <your_access_token>
```

<Warning>
  Never expose your token in client-side JavaScript, public repositories, or log output. Treat it like a password. If you believe a token has been compromised, log out to invalidate it and log in again to get a new one.
</Warning>

**Example authenticated request**

```bash theme={null}
curl https://api.pingback.live/api/v1/auth/me \
  -H "Authorization: Bearer <your_access_token>"
```

***

## Verify your token

Call `GET /api/v1/auth/me` to confirm your token is valid and to retrieve your user profile and workspace context.

`GET /api/v1/auth/me`

<CodeGroup>
  ```bash curl theme={null}
  curl https://api.pingback.live/api/v1/auth/me \
    -H "Authorization: Bearer <your_access_token>"
  ```

  ```javascript JavaScript (fetch) theme={null}
  const response = await fetch("https://api.pingback.live/api/v1/auth/me", {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });

  const context = await response.json();
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "user": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "email": "you@example.com",
    "full_name": "Ada Lovelace",
    "is_verified": true,
    "is_google_account": false,
    "avatar_url": null
  },
  "business": {
    "id": "8e4a1b2c-3d5f-4e6a-9b7c-1d2e3f4a5b6c",
    "name": "Acme Support",
    "website": "https://acme.com",
    "industry": "E-commerce",
    "team_size": "1-10",
    "goal": "Improve customer response time",
    "created_at": "2026-04-05T10:00:00Z"
  },
  "onboarding_complete": true,
  "team_role": "owner"
}
```

<ResponseField name="user.id" type="string (UUID)">
  Your unique user identifier.
</ResponseField>

<ResponseField name="user.email" type="string">
  The email address on your account.
</ResponseField>

<ResponseField name="user.full_name" type="string">
  Your display name.
</ResponseField>

<ResponseField name="user.is_verified" type="boolean">
  Whether your email address has been verified.
</ResponseField>

<ResponseField name="user.is_google_account" type="boolean">
  `true` if you signed in with Google OAuth.
</ResponseField>

<ResponseField name="business" type="object or null">
  Your workspace details. `null` if you haven't created a workspace yet.
</ResponseField>

<ResponseField name="onboarding_complete" type="boolean">
  `true` once you've created a workspace. Use this to gate onboarding UI.
</ResponseField>

<ResponseField name="team_role" type="string or null">
  Your role in the workspace — `"owner"` or a team member role. `null` if no workspace exists yet.
</ResponseField>

***

## Sign in with Google

PingBack supports Google OAuth as an alternative to email and password. Pass the Google ID token from your frontend OAuth flow to:

`POST /api/v1/auth/google`

```bash theme={null}
curl -X POST https://api.pingback.live/api/v1/auth/google \
  -H "Content-Type: application/json" \
  -d '{
    "id_token": "<google_id_token>"
  }'
```

The response is identical to email login — you receive an `access_token` to use as a Bearer token.

***

## Error responses

| Status                     | Meaning                                                                                                                              |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `401 Unauthorized`         | Token is missing, expired, or invalid. Check that you included the `Authorization: Bearer` header and that the token hasn't expired. |
| `422 Unprocessable Entity` | Request body failed validation. Check that `email` is a valid email address and `password` is at least 8 characters.                 |

**401 example**

```json theme={null}
{
  "detail": "Missing bearer token"
}
```

**422 example**

```json theme={null}
{
  "detail": [
    {
      "loc": ["body", "password"],
      "msg": "Password must be at least 8 characters",
      "type": "value_error"
    }
  ]
}
```

<Tip>
  If you receive a `401` on a request you expect to succeed, call `GET /api/v1/auth/me` first to confirm your token is still valid. If that also returns `401`, log in again to get a fresh token.
</Tip>
