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

# API Overview

> REST API reference for Supapost.

## Base URL

```
https://api.supapost.so
```

For local development:

```
http://localhost:8787
```

## Authentication

All API requests (except public OAuth callbacks and webhooks) require an `Authorization` header:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

Supapost supports two credential types — Unkey API keys (prefixed `sp_live_...`) for server-to-server use and Supabase JWTs issued to browser sessions. See [Authentication](/authentication) for details.

## Response format

Every response uses a consistent JSON shape.

**Success** — the data directly (or a domain-specific envelope):

```json theme={null}
{ "id": "abc", "name": "Morning routine" }
```

**Error** — always `success: false` plus a human-readable `message`:

```json theme={null}
{ "success": false, "message": "name is required" }
```

## Pagination

Paginated list endpoints use a Stripe-style contract:

```json theme={null}
{
  "object": "list",
  "data": [],
  "has_more": false,
  "url": "/products"
}
```

Common query params:

* `limit`: number of records to return, default `15`, max `100`
* `starting_after`: fetch the next page after the given object ID
* `ending_before`: fetch the previous page before the given object ID

Currently documented paginated list endpoints include `/assets`, `/products`, `/team/members`, and `/invites`.

## Status codes

| Code | Meaning                                                  |
| ---- | -------------------------------------------------------- |
| 200  | Success                                                  |
| 202  | Accepted — async job queued, poll `/jobs/:id` for result |
| 400  | Bad request — the `message` field explains what          |
| 401  | Missing or invalid credentials                           |
| 403  | Authenticated but not authorized for this resource       |
| 404  | Not found                                                |
| 429  | Rate limit exceeded — see `Retry-After` header           |
| 500  | Internal server error                                    |
| 502  | Upstream provider error (FAL, Higgsfield, TikTok, etc.)  |

## Rate limits

Limits are per-team, bucketed by endpoint tier:

| Tier      | Limit        | Endpoints                                                            |
| --------- | ------------ | -------------------------------------------------------------------- |
| Expensive | 30 / minute  | `/generate/slides`, `/generate/image`, `/render`, `/stores/:id/sync` |
| Mutating  | 120 / minute | All POST / PATCH / DELETE writes                                     |
| Read      | 600 / minute | All GET requests (including `/jobs/:id` polling)                     |

Exceeding a limit returns `429` with a `Retry-After` header.

## Async jobs

Expensive generation endpoints (`/generate/image` and `/render`) are **always async**. They return `202 Accepted` with a `job_id` immediately — clients then poll `GET /jobs/:id` for the result. This avoids long-running HTTP requests and stays within Cloudflare Worker CPU limits.

```bash theme={null}
# Kick off the job
curl -X POST https://api.supapost.so/generate/image \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "sunset over tokyo"}'
# → 202 Accepted
# { "job_id": "0b1e...", "status": "pending" }

# Poll the job until it finishes (every 1-2 seconds)
curl https://api.supapost.so/jobs/0b1e... \
  -H "Authorization: Bearer $KEY"
# → { "id": "0b1e...", "type": "image_gen", "status": "completed",
#     "result": { "url": "https://cdn.supapost.so/...jpg" } }
```

Job status lifecycle: `pending` → `processing` → `completed | failed`.

The work runs on Cloudflare Queues with automatic retries and a dead-letter queue for failed messages.

## Endpoints

### Generation

| Method | Path               | Description                                              |
| ------ | ------------------ | -------------------------------------------------------- |
| POST   | `/generate/slides` | AI-generate a multi-slide carousel                       |
| POST   | `/generate/image`  | Generate a single image (always async, returns `job_id`) |
| GET    | `/models`          | List available image generation models                   |

### Rendering

| Method | Path      | Description                                                              |
| ------ | --------- | ------------------------------------------------------------------------ |
| POST   | `/render` | Render slides to PNG via Satori + Resvg (always async, returns `job_id`) |

### Jobs (async polling)

| Method | Path        | Description                          |
| ------ | ----------- | ------------------------------------ |
| GET    | `/jobs`     | List recent jobs for the team        |
| GET    | `/jobs/:id` | Get a single job's status and result |

### Projects

| Method | Path            | Description                |
| ------ | --------------- | -------------------------- |
| GET    | `/projects`     | List projects              |
| GET    | `/projects/:id` | Get a project              |
| POST   | `/projects`     | Create or update a project |
| DELETE | `/projects/:id` | Delete a project           |

### Scheduling

| Method | Path                  | Description                |
| ------ | --------------------- | -------------------------- |
| GET    | `/schedule/posts`     | List scheduled posts       |
| POST   | `/schedule/posts`     | Create a scheduled post    |
| PATCH  | `/schedule/posts/:id` | Update / reschedule a post |
| DELETE | `/schedule/posts/:id` | Delete a scheduled post    |

### Publishing

| Method | Path              | Description              |
| ------ | ----------------- | ------------------------ |
| POST   | `/publish/tiktok` | Publish to TikTok drafts |

### Influencers

| Method | Path               | Description          |
| ------ | ------------------ | -------------------- |
| GET    | `/influencers`     | List influencers     |
| POST   | `/influencers`     | Create an influencer |
| PATCH  | `/influencers/:id` | Update an influencer |
| DELETE | `/influencers/:id` | Delete an influencer |

### Products

| Method | Path            | Description      |
| ------ | --------------- | ---------------- |
| GET    | `/products`     | List products    |
| GET    | `/products/:id` | Get a product    |
| POST   | `/products`     | Create a product |
| PATCH  | `/products/:id` | Update a product |
| DELETE | `/products/:id` | Delete a product |

### Stores (Shopify / Etsy)

| Method | Path               | Description                                |
| ------ | ------------------ | ------------------------------------------ |
| GET    | `/stores`          | List connected stores                      |
| POST   | `/stores`          | Connect a new store (auto-syncs products)  |
| DELETE | `/stores/:id`      | Disconnect a store and delete its products |
| POST   | `/stores/:id/sync` | Re-sync products from the store            |

### Assets / library

| Method | Path                  | Description                      |
| ------ | --------------------- | -------------------------------- |
| GET    | `/assets`             | List uploaded + generated assets |
| POST   | `/upload`             | Upload a file to the library     |
| POST   | `/upload/presign`     | Get a presigned R2 upload URL    |
| POST   | `/assets/bulk/delete` | Delete assets in batches         |
| DELETE | `/assets/:id`         | Delete an asset                  |
| POST   | `/assets/delete`      | Delete an asset by URL           |

### Team

| Method | Path            | Description          |
| ------ | --------------- | -------------------- |
| GET    | `/team/members` | List team members    |
| GET    | `/invites`      | List pending invites |

### Social accounts

| Method | Path                      | Description                    |
| ------ | ------------------------- | ------------------------------ |
| GET    | `/social/accounts`        | List connected social accounts |
| GET    | `/auth/tiktok`            | Start TikTok OAuth flow        |
| POST   | `/auth/tiktok/disconnect` | Disconnect a TikTok account    |
| GET    | `/auth/instagram`         | Start Instagram OAuth flow     |
| GET    | `/auth/shopify`           | Start Shopify OAuth flow       |

### API keys

| Method | Path        | Description                |
| ------ | ----------- | -------------------------- |
| GET    | `/keys`     | List API keys for the team |
| POST   | `/keys`     | Create a new API key       |
| DELETE | `/keys/:id` | Delete an API key          |
