Developers
Build integrations with the Basecomp API. Update prize fulfilment, sync data, and automate your workflows.
The Basecomp API is organised around REST. It uses predictable resource-oriented URLs, accepts and returns JSON, and uses standard HTTP response codes and verbs. Field names are camelCase; requests may send either camelCase or snake_case.
All requests are made to the following base URL, over HTTPS.
Authenticate every request with a secret API key in the Authorization header as a Bearer token. Create and manage keys in your dashboard under Settings → API Keys. A key is shown only once at creation, so store it securely and never expose it in client-side code.
A missing or invalid key returns 401.
Each key carries a set of scopes that limit what it can do. Give a third party (e.g. a supplier automating dispatch in Zapier) a fulfilment-only key so a leak can never touch the rest of your store. A request whose key lacks the required scope returns 403 with code INSUFFICIENT_SCOPE.
| Field | Type | Description |
|---|---|---|
winners:read | scope · optional | List and fetch winners. |
winners:write | scope · optional | Update a winner's prize fulfilment status. |
orders:read | scope · optional | List and fetch orders. |
customers:read | scope · optional | List and fetch customers. |
competitions:read | scope · optional | List and fetch competitions. |
* | scope · optional | Full access to every endpoint. Use only for your own server-side integrations. |
List endpoints return newest-first and use cursor pagination. Pass ?limit (1-100, default 25) to size each page, and ?cursor with the meta.nextCursor value to fetch the next page. meta.hasMore is false on the last page. Cursors are stable as new records are created, which makes them safe for polling.
Authenticated endpoints are limited to 120 requests per minute, per key. Exceeding the limit returns 429 with code RATE_LIMITED.
The API uses conventional HTTP status codes: 2xx for success, 4xx for a problem with the request, and 5xx for a server error. Every error returns the same JSON shape with a stable, machine-readable code.
| Field | Type | Description |
|---|---|---|
UNAUTHENTICATED | 401 · optional | Missing or invalid API key. |
INSUFFICIENT_SCOPE | 403 · optional | The key lacks the scope this endpoint requires. |
NOT_FOUND | 404 · optional | The resource does not exist, or does not belong to your store. |
VALIDATION_ERROR | 422 · optional | The request body failed validation. See details.validationErrors. |
WINNER_NOT_FULFILLABLE | 422 · optional | The winner cannot be fulfilled (not claimed, converted to cash/credit, or has no shipping address). |
RATE_LIMITED | 429 · optional | Too many requests. |
/api/v1/private/winnersAPI key120 requests / minuteReturns the store's winners, newest first, each with its prize, competition and customer. Cursor-paginated.
| Field | Type | Description |
|---|---|---|
fulfillment_status | string · optional | Filter by pending, processing, shipped, delivered or unfillable. |
status | string · optional | Filter by winner status (e.g. won, claimed). |
type | string · optional | Filter by instant_win or main_prize. |
since | string · optional | Only winners created on or after this date. |
limit | integer · optional | Page size, 1-100 (default 25). |
cursor | string · optional | meta.nextCursor from the previous page. |
/api/v1/private/winners/{id}API key120 requests / minuteFetch a single winner by id, scoped to your store.
/api/v1/private/winners/{id}API key120 requests / minuteUpdate a winner's prize fulfilment status. The most common use is marking a claim as shipped from a supplier's system: when the status becomes shipped, the winner is automatically emailed (once) with any tracking details, and a prize.shipped webhook fires.
The {id} is the winner id (win_...) from your prize.claimed webhook or supplier export. The winner must belong to your store, and be a claimed, non-converted physical prize with a shipping address.
| Field | Type | Description |
|---|---|---|
fulfillment_status | string · optional | One of: processing, shipped, delivered, unfillable. Required unless supplier_order_number is supplied, in which case the winner is marked shipped automatically. |
supplier_order_number | string · optional | The supplier's own order reference. Recording one (with no fulfillment_status) marks the prize shipped and emails the winner. |
tracking_number | string · optional | Carrier tracking number. |
tracking_url | string · optional | Carrier tracking URL. |
notes | string · optional | Internal fulfilment note. |
unfillable_reason | string · optional | Required when fulfillment_status is unfillable. |
notify_customer | boolean · optional | Whether to email the winner when shipping. Defaults to true. Does not affect the webhook. |
/api/v1/private/ordersAPI key120 requests / minuteReturns the store's orders, newest first. Cursor-paginated. Amounts are integers in the smallest currency unit (e.g. pence).
| Field | Type | Description |
|---|---|---|
status | string · optional | Filter by order status. |
since | string · optional | Only orders created on or after this date. |
limit | integer · optional | Page size, 1-100 (default 25). |
cursor | string · optional | meta.nextCursor from the previous page. |
/api/v1/private/orders/{id}API key120 requests / minuteFetch a single order by id, scoped to your store.
/api/v1/private/customersAPI key120 requests / minuteReturns the store's customers, newest first. Cursor-paginated.
| Field | Type | Description |
|---|---|---|
status | string · optional | Filter by customer status. |
email | string · optional | Filter by exact email address. |
since | string · optional | Only customers created on or after this date. |
limit | integer · optional | Page size, 1-100 (default 25). |
cursor | string · optional | meta.nextCursor from the previous page. |
/api/v1/private/customers/{id}API key120 requests / minuteFetch a single customer by id, scoped to your store.
/api/v1/private/competitionsAPI key120 requests / minuteReturns the store's competitions, newest first. Cursor-paginated.
| Field | Type | Description |
|---|---|---|
status | string · optional | Filter by competition status. |
since | string · optional | Only competitions created on or after this date. |
limit | integer · optional | Page size, 1-100 (default 25). |
cursor | string · optional | meta.nextCursor from the previous page. |
/api/v1/private/competitions/{id}API key120 requests / minuteFetch a single competition by id, scoped to your store.