Skip to main content
Version: 2026-05

List themes

GET /themes

Description​

Lists your account's themes, most recently edited first, as a cursor-paginated collection. A theme sets how a gift's invitation email and landing page look and read: the colors, fonts, and logo, and the default wording the recipient sees.

Each item carries the full theme shape, the same object Get a theme returns.

When to use​

Use this endpoint to show your users which themes they can send with, for example as a picker of swatches built from each theme's appearance. Filter with default=true to find the account's default theme: a gift request sent without a campaign uses it, and so does a campaign with no theme of its own.

When you already have a theme's id, fetch it directly with Get a theme.

Parameters​

Headers​

AndOpen-API-Version (string · required) is the API version this request targets. Always send 2026-05. Requests authenticate with a bearer token; see Authentication for how to present it and Environments for the regional base URL to send it to.

Query parameters​

Every one of these is optional, and sent together they page, sort, and filter the same collection.

Paging​

limit (integer · optional) is how many themes to return per page. Defaults to 25, and the most is 50: ask for more and you get 50. A non-numeric, zero, or negative value is rejected with a 400.

after (string · uuid · optional) is the keyset pagination cursor. To fetch the next page, pass the id of the last theme in the page you just received. Omit it for the first page. A cursor that references no existing theme is rejected with a 400. Stop paging when the response's has_more is false.

Ordering​

sort (string · optional) is the field to order by, - prefix for descending. Defaults to -updated_at, so the theme edited most recently comes first; updated_at, created_at, and -created_at are also accepted. Any other field is rejected with a 400.

Filtering​

Filters combine with AND, so each one you add narrows the page further. None of them rejects a value it doesn't recognize: an unknown id, a malformed team UUID, or a blank substring matches nothing and returns an empty page.

default (string · optional) takes true or false. true returns the account's default theme on its own, or an empty page when the account has no default. false returns every other theme. Any other value matches nothing.

name (string · optional) matches themes whose name contains the value, case-insensitively.

owner (string · optional) filters by the id of the user who created the theme. The literal me resolves to the authenticated user, which needs user authentication: a service token has no connecting user and gets a 400.

owner.name (string · optional) and owner.email (string · optional) match against the creator instead of the theme. Both are case-insensitive substring matches, so a bare domain such as @example.com in owner.email selects every creator on it.

team (string · optional) filters by the creator's team. Accepts a single UUID or a comma-separated list.

Worked examples​

The cURL version is the raw HTTP call; the JavaScript, Python, and Ruby versions are idiomatic equivalents. Each requests the account's default theme.

curl -X GET "https://api.andopen.co/themes?default=true" \
-H "Authorization: Bearer <api_key>" \
-H "AndOpen-API-Version: 2026-05"

Paging through every theme​

To walk the whole collection, keep fetching while has_more is true, passing the last theme's id as the after cursor each time. The cURL version shows a single follow-up request; the others loop until the last page.

curl -X GET "https://api.andopen.co/themes?limit=50&after=7c9e6679-7425-40de-944b-e07fc1f90ae7" \
-H "Authorization: Bearer <api_key>" \
-H "AndOpen-API-Version: 2026-05"

Response shape​

A successful call returns 200 OK with a page object: a data array of themes plus a boolean cursor flag.

FieldDescription
data (array · required)The themes in this page. Each entry is a full theme object, identical to what Get a theme returns; see that page for the per-field detail.
has_more (boolean · required)Whether more themes exist beyond this page. When true, fetch the next page by passing the last item's id as the after cursor; when false, you've reached the end.
data.default (boolean · required)Whether each theme is the account's default. At most one theme in the page, or in the account, is true.
data.appearance (object · required)Each theme's colors, heading font, and logo, enough to draw a swatch without opening the theme.
Response · 200
{
"data": [
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"name": "Acme Classic",
"default": true,
"appearance": {
"background_color": "#FCF8F2",
"text_color": "#000000",
"button_background_color": "#000000",
"button_text_color": "#FCF8F2",
"heading_font_family": "Playfair Display, serif",
"logo_url": "https://files.andopen.co/rndd63mwgj94j2vf3v2ngnye0hkn"
},
"owner": {
"id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"name": "Dana Okafor",
"email": "dana@acme.example"
},
"web_url": "https://acme.andopen.co/sender/themes/42",
"created_at": "2026-04-16T10:30:00.000Z",
"updated_at": "2026-04-16T10:30:00.000Z"
}
],
"has_more": false
}

Per-field notes​

  • has_more drives paging, not a total count. The response carries no total and no next URL, so build the next request from the last item's id.
  • An account may have no default theme. Then no item has default: true, and default=true returns an empty page.
  • data[].owner is null when the theme's creator isn't recorded or is no longer a user. Filtering by owner, owner.name, or owner.email never matches those themes.

Error cases​

Every failure uses the shared error model: a top-level errors array of objects carrying type, code, message, and (for field-level problems) param. See Errors for the full type/code taxonomy and how to handle each category; the codes below are the ones this endpoint produces.

StatusMeaning
400The request is malformed or violates a precondition. Typical triggers are a missing or unsupported `AndOpen-API-Version` header, a request body that is not valid JSON, or pagination parameters that fail server-side validation (`limit` non-numeric or non-positive, `after` referencing a record that does not exist).
401Authentication failed: missing or invalid bearer token.
403Authorized but not permitted to access this resource.
429Too many requests. Rate limit exceeded.
500Internal server error.
503Service unavailable. The account may be under maintenance. Check the `Retry-After` header.

Every error carries a type, one of: validation_error, authentication_error, authorization_error, not_found_error, rate_limit_error, api_error.

The ones you'll meet in practice:

  • 400 validation_error: a query parameter was rejected, naming the offending one in param. An after cursor referencing no existing theme is invalid_reference. A limit that is not a positive integer and an unsupported sort field are both invalid_format, and so is owner=me sent with a service token, which has no user to resolve.
  • 400 api_error: unsupported_api_version when the AndOpen-API-Version header is missing or unsupported (returned before authentication).
  • 401 authentication_error: the bearer token is missing, invalid, or expired (unauthorized).
  • 403 authorization_error: the token is valid but not permitted to list themes (forbidden).
  • 429 rate_limit_error: too many requests; back off and retry (rate_limited). The RateLimit-* response headers tell you the budget and reset time.