# API Documentation

The BubbleNote REST API — read your teams, projects, feedback, and notifications programmatically with a personal access token.

## Authentication

The API authenticates with a personal access token. Create one from **Settings → API keys** inside the app — you'll see the token once, so copy it immediately.

Send it as a bearer token on every request:

```
Authorization: Bearer <your-token>
```

The base URL for all endpoints is:

```
https://bubblenote.app/api
```

All requests must be made over HTTPS. Tokens can be named and given an expiry (30/60/90 days, a custom date, or no expiration) and revoked at any time.

## Scope & permissions

A token belongs to **you** and can read anything you can already see in the app, across **all of your teams**. If you don't have access to a team, project, or piece of feedback, the API won't return it either.

- Tokens are private to the user who created them; teammates never see them.
- Requesting a team you don't belong to returns `403`.
- Feedback that exceeds a team's plan usage limit is redacted, exactly as in the dashboard.

## Rate limits

Requests are limited to **60 per minute** per token. The `X-RateLimit-Remaining` response header tells you how many you have left; exceeding the limit returns `429 Too Many Requests`.

## List teams

`GET /api/teams`

Returns every team you can access. Use a team's `id` to list its projects.

**Example request**

```bash
curl https://bubblenote.app/api/teams \
  -H "Authorization: Bearer <your-token>"
```

**Example response**

```json
{
  "data": [
    {
      "id": 7,
      "name": "Acme Inc",
      "created_at": "2026-05-01T10:00:00.000000Z",
      "updated_at": "2026-06-20T14:30:00.000000Z"
    }
  ]
}
```

## List projects

`GET /api/teams/{team}/projects`

Returns every project in the given team that you can access.

**Example request**

```bash
curl https://bubblenote.app/api/teams/7/projects \
  -H "Authorization: Bearer <your-token>"
```

**Example response**

```json
{
  "data": [
    {
      "id": 3,
      "name": "Acme Checkout",
      "domain": "acme.test",
      "is_active": true,
      "feedback_count": 42,
      "created_at": "2026-05-01T10:00:00.000000Z",
      "updated_at": "2026-06-20T14:30:00.000000Z"
    }
  ]
}
```

## List feedback

`GET /api/teams/{team}/projects/{project}/feedbacks`

Returns a paginated list of feedback for the given project, newest first.

**Query parameters**

| Parameter | Description |
| --- | --- |
| `status` | Filter by one or more statuses: `new`, `reviewed`, `resolved`, `archived`. Pass a comma-separated list (`status=new,resolved`) or repeat the key (`status[]=new&status[]=resolved`). |
| `include` | Embed related comments. One or more of `publicComments`, `internalComments` (comma-separated or repeated). |

**Example request**

```bash
curl "https://bubblenote.app/api/teams/7/projects/3/feedbacks?status=new,resolved&include=publicComments" \
  -H "Authorization: Bearer <your-token>"
```

**Example response**

```json
{
  "data": [
    {
      "id": 12,
      "url": "https://bubblenote.app/feedbacks/12",
      "status": "new",
      "comment": "The submit button is misaligned on mobile.",
      "page_url": "https://acme.test/checkout",
      "submitter_name": "Jane Doe",
      "submitter_email": "jane@acme.test",
      "browser": "Chrome 120.0",
      "os": "macOS 14.2",
      "device": "Desktop",
      "country": "US",
      "city": "San Francisco",
      "is_restricted": false,
      "created_at": "2026-06-20T14:30:00.000000Z",
      "updated_at": "2026-06-21T09:15:00.000000Z",
      "public_comments": [
        {
          "id": 5,
          "body": "Thanks — we're on it!",
          "is_internal": false,
          "author": "Alex Rivera",
          "created_at": "2026-06-21T09:15:00.000000Z"
        }
      ]
    }
  ],
  "links": { "first": "...", "last": "...", "prev": null, "next": null },
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
```

Each item's `url` links to the feedback in the app. Pass `?page=2` to page through results. Internal comments are only returned to users with access to the project.

## List notifications

`GET /api/notifications`

Returns a paginated list of your notifications, newest first.

**Query parameters**

| Parameter | Description |
| --- | --- |
| `status` | Filter by read state: `read` or `unread`. |
| `project_id` | Only notifications related to the given project. |
| `team_id` | Only notifications related to projects in the given team. |

**Example request**

```bash
curl "https://bubblenote.app/api/notifications?status=unread" \
  -H "Authorization: Bearer <your-token>"
```

**Example response**

```json
{
  "data": [
    {
      "id": "9f8c1e2a-...",
      "type": "new_feedback_received",
      "data": { "feedback_id": 12, "project_id": 3 },
      "read_at": null,
      "created_at": "2026-06-20T14:30:00.000000Z"
    }
  ],
  "links": { "first": "...", "last": "...", "prev": null, "next": null },
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
```

## Errors

The API uses standard HTTP status codes and returns JSON error bodies.

| Status | Meaning |
| --- | --- |
| `401` | Missing, invalid, revoked, or expired token. |
| `403` | You don't have access to the requested team or resource. |
| `404` | The resource doesn't exist or isn't in the given team. |
| `422` | A query parameter was invalid (e.g. an unknown status or include value). |
| `429` | Rate limit exceeded — slow down and retry. |