---
title: "API Reference"
description: "Call the Shorebird Code Push REST API: where the OpenAPI spec is, how to authenticate with an API key, the resource model, endpoint groups and rate limits."
---

Interact programmatically with your Shorebird account. You can manage apps, releases, and over-the-air patches with the Shorebird Code Push API. It offers everything the `Shorebird` CLI does under the hood.

The full, always-up-to-date reference is published as an OpenAPI 3 document:

[**https://api.shorebird.dev/openapi.json**](https://api.shorebird.dev/openapi.json)

Load that URL into any OpenAPI-compatible viewer to browse every endpoint, parameter, and schema interactively. If you are pointing a tool at Shorebird and only have the hostname, the API catalog at [**https://api.shorebird.dev/.well-known/api-catalog**](https://api.shorebird.dev/.well-known/api-catalog) lists the spec, these docs, and the Shorebird status page.

The API does not yet carry a compatibility guarantee. It is the same API the Shorebird CLI and console use, and it changes when they do. You are welcome to build on it; expect to follow it.

## Calling the API from the command line

For everyday tasks, use the dedicated commands (`shorebird apps list`, `shorebird releases list`, `shorebird patches list`, and so on). `shorebird api` is for everything else: it calls any API endpoint, including ones with no dedicated command, and is designed mainly for coding agents and scripts. It sends an authenticated request using your current Shorebird credentials, so there is no token to copy and no headers to set. Only the response body goes to stdout (the global `--json` flag is not supported), and a failed request exits with a non-zero status. `--jq` applies only to successful responses; on an error the raw error body is printed instead, so check the exit status before using the output. Find endpoints in [the OpenAPI spec](https://api.shorebird.dev/openapi.json).

`shorebird api` needs Shorebird 1.6.129 or newer.

```
# List the members of an organization (find its id with `shorebird orgs list`, or `shorebird account orgs` before 1.6.135)
shorebird api /organizations/ORG_ID/users --jq '.users[].user.email'
```

The HTTP method can go before the endpoint, or in `-X`. Without one, the request is a GET, or a POST when you pass fields with `-f` or `-F`:

```
shorebird api GET /apps
shorebird api DELETE /apps/APP_ID/releases/RELEASE_ID
```

To read a whole paged list in one call, add `--paginate`. It keeps requesting the next page and prints the pages as one JSON object, with the list fields joined. It works only with GET, and on an endpoint that doesn’t page it makes a single request:

```
shorebird api /apps -f per_page=100 --paginate --jq '.apps[].app_id'
```

Because `--paginate` always sends a GET, the `-f` fields here go in the query string.

The method before the endpoint and `--paginate` need Shorebird 1.6.130 or newer.

Run `shorebird api --help` for all options. For how paging works, see [Pagination](#common-patterns) below.

## Base URL

```
https://api.shorebird.dev/api/v1
```

## Authentication

Every request (other than the patch-check endpoint, see below) needs a bearer token. No other headers are required:

```
Authorization: Bearer <token>
```

There are three kinds of tokens, and which one you use depends on context:

* **API keys** (`sb_api_*`): long-lived, [generated from the Shorebird console](/account/api-keys/). Use these for CI pipelines, scripts, and any non-interactive automation. Default expiration is 1 year, with options for 30 or 90 days, and only a service account’s key can be set to never expire. Treat these like any other long-lived secret.
* **OAuth JWTs**: short-lived (15 minutes), issued by the interactive login flow and refreshed automatically by the CLI. Use these for interactive/local tooling. Given the fast expiration, these should not be hardcoded anywhere.
* **Service account tokens from GitHub Actions**: short-lived (15 minutes), for a [service account](/account/service-accounts/), issued in exchange for the OIDC token GitHub gives a workflow that a [trust rule](/account/trust-rules/) allows. The Shorebird CLI and actions make the exchange for you, so there’s no Shorebird secret to store. Trust rules need a Business or Enterprise plan.

## Resource model

The core objects and how they relate:

* **Organization** → has **Users** as members, with a **Role** (owner, admin, appManager, developer, viewer) each.
* **App** → belongs to an organization, has **Channels** (e.g. stable, beta).
* **Release** → belongs to an app, has a platform (`android`, `ios`, `linux`, `macos`, `windows`) and status (`draft`, `active`), and one or more **Release Artifacts** (the platform/arch-specific binaries).
* **Patch** → an OTA update tied to a release, with its own **Patch Artifacts**; patches get promoted to a channel to go live for devices.

## Endpoint groups

The operations, grouped by feature. Each group links to the page that explains the feature; the spec has every parameter and response:

* **Users**: your own account, its [email notification preferences](/account/cli/#turn-email-notifications-on-or-off), and [deleting it](/account/delete-account/).
* **Apps**: create, list, rename and delete apps, and read an app’s signing key.
* **Releases**: create releases, upload and list their artifacts, edit notes, and delete them. See [Release](/code-push/release/).
* **Patches**: create patches and upload their artifacts, promote, roll back and roll forward, and the device’s patch check. See [Patch](/code-push/patch/) and [Rollback](/code-push/rollback/).
* **Channels**: create, list and delete [tracks](/code-push/tracks/).
* **Metrics**: active users, new devices, version distribution, patch adoption, installs and downloads, active hours and the activity heatmap.
* **Organizations**: your memberships, creating, renaming and deleting organizations, their apps (and transferring an app into one), members and their roles, and organization invitations. See [Organizations](/account/orgs/).
* **Collaborators**: an app’s [per-app collaborators](/account/orgs/#per-app-collaborators) and their invitations.
* **Invitations**: invitations sent to you, and accepting or declining them. See [Accept an invitation](/account/orgs/#accept-an-invitation).
* **Billing**: your plan and patch install usage, and an organization’s. See [Plans & Upgrading](/account/plans/).
* **Service accounts**: an organization’s service accounts, their keys and their trust rules. See [Service Accounts](/account/service-accounts/) and [Trust Rules](/account/trust-rules/).
* **Audit logs**: an organization’s or enterprise’s audit log (`/organizations/{organizationId}/audit-logs`, `/enterprises/{enterpriseId}/audit-logs`). See [Audit Logs](/enterprise/audit-logs/).
* **Enterprises**: your enterprise, its apps, members, guests, organizations and their members, service accounts, and billing. See [Enterprise](/enterprise/) and [Enterprise Roles](/enterprise/roles/).
* **Diagnostics**: upload and download speed-test URLs.

Many operations’ descriptions in the spec name the permission they need. Most need a role in the organization that owns the resource; see [What each role can do](/account/orgs/#what-each-role-can-do).

## Rate limits

Requests are rate limited per caller: per bearer token, or per IP address for a request without one. Every response carries `RateLimit-Policy` and `RateLimit` headers, which give the limit, the requests left, and the seconds until the window resets, so a script can slow down before it’s refused.

A refused request gets a `429` with a `Retry-After` header, in seconds, and the usual error body:

```
{
  "code": "rate_limited",
  "message": "Too many requests. Wait and try again.",
  "details": "Limit is ... requests per ... seconds; it resets in ... seconds."
}
```

Wait for `Retry-After` and send the request again.

## Common patterns

* **Errors**: non-2xx responses return a standard `ErrorResponse` with a machine-readable `code`, a human-readable `message`, and optional `details` and `documentation_url`. Branch on `code` rather than on `message`.

* **Pagination**: the apps, releases and patches lists accept an optional `per_page` (default 30, maximum 100) and `cursor`. A paged response includes `next_cursor` when there is another page; pass it as `cursor` to fetch the next one. Without `per_page` or `cursor`, these lists return every item. Some newer list endpoints page by default, with the same parameters. `shorebird api --paginate` follows `next_cursor` for you.

  On a CLI older than 1.6.130, this script prints every app ID, one page of 50 at a time, stops when a page has no `next_cursor`, and exits with status 1 if a request fails:

  ```
  cursor=""
  while :; do
    page=(-X GET /apps -f per_page=50)
    [ -n "$cursor" ] && page+=(-f "cursor=$cursor")
    shorebird api "${page[@]}" --jq '.apps[].app_id' || exit 1
    cursor=$(shorebird api "${page[@]}" --jq '.next_cursor | select(. != null)') || exit 1
    [ -n "$cursor" ] || break
  done
  ```

* **Unauthenticated endpoint**: `POST /patches/check` is the one exception to the auth rule above: it’s what a device calls to check for an available patch, and it doesn’t require a bearer token.
