Skip to main content
Version: 2026-05

API Reference

The &Open API is a RESTful JSON API for the gifting platform. You create and retrieve gift requests, browse campaigns, and integrate gifting into your own workflows over HTTPS, using resource-based URLs, standard HTTP verbs, and conventional status codes.

Base URL and authentication

Send requests to the base URL for the region your account was provisioned in, and authenticate every request with a bearer token. See Environments for the regional base URLs and Authentication for how tokens work.

Every request must also carry the AndOpen-API-Version header. See Versioning for the supported versions and what counts as a breaking change.

Requests

Send JSON bodies with Content-Type: application/json. Request bodies are flat top-level objects with snake_case keys — there is no envelope and no resource-type wrapper.

curl -X POST "https://api.andopen.co/gift_requests" \
-H "Authorization: Bearer ao-v1-production-your_secret_here" \
-H "AndOpen-API-Version: 2026-05" \
-H "Content-Type: application/json" \
-d '{
"campaign_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recipient": {
"first_name": "Alice",
"last_name": "Smith",
"email": "alice@example.com"
}
}'

Responses

A single resource is returned as a flat top-level JSON object — no envelope.

{
"id": "4fb4cb3f-9666-43b5-8884-7f5194483d1a",
"status": "submitted",
"campaign_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"redemption_url": "https://gift.andopen.co/r/abc123",
"recipient": {
"id": "b2c3d4e5-f6a7-8901-bcde-f01234567890",
"first_name": "Alice",
"last_name": "Smith",
"email": "alice@example.com"
},
"shipping_address": null,
"line_items": null,
"created_at": "2026-04-16T10:30:00.000Z",
"updated_at": "2026-04-16T10:30:00.000Z"
}

A collection is wrapped in a { data, has_more } envelope and nothing else — no total count, no precomputed page links. Each item in data has the same shape as the single-resource response.

{
"data": [
{
"id": "4fb4cb3f-9666-43b5-8884-7f5194483d1a",
"status": "submitted"
}
],
"has_more": true
}

Data types

The API represents common types consistently:

TypeNotes
KeysAlways snake_case.
IDsUUIDs with no prefix, such as 4fb4cb3f-9666-43b5-8884-7f5194483d1a.
TimestampsISO 8601 strings with millisecond precision in UTC, such as 2026-04-16T10:30:00.000Z.
Enumerated valuesLowercase snake_case strings from a fixed set — for example a status of "delivered". The allowed values are listed on each field.
MoneyAn object — { "amount": 2500, "currency": "EUR" } — where amount is an integer in the smallest unit of the currency (cents for EUR and USD, pence for GBP) and currency is an ISO 4217 code. 2500 with "currency": "EUR" is €25.00.
Country codesISO 3166-1 alpha-2, uppercase — IE, US, GB.
Phone numbersStrings. Use E.164 (a leading + and country code) for a number outside the destination country.
EmailsPlain strings, validated as email addresses.
URLsAbsolute https URLs, as plain strings.
Booleanstrue or false.
Absent valuesA field with no value is still included in the response and returned as null, never omitted — including nullable arrays. The schema defines the full set of keys.

Associations and references

A related resource appears in a response in one of three shapes. Which one you get depends on what you need to use the resource:

  • Bare id — a <resource>_id UUID, such as variant_id on a line item. The related record is not included; fetch it from its own endpoint when you need it.
  • Embedded summary — a small object of identifying fields that always includes id, such as { "id": "…", "name": "…" }. You get a usable label inline, and the id lets you fetch the full resource when you need more than the label.
  • Embedded full — the complete sub-resource, in the same shape its own endpoint returns. A gift request's recipient, shipping_address, and line_items are embedded in full because you need them to make sense of the request.

Two things hold whatever the shape:

  • An embedded association is serialised the same way everywhere — you see the identical shape whether you fetch the resource directly, list it, or receive it in a webhook.
  • The same entity can take different shapes in different responses, each chosen for what that response is for — a variant is a bare variant_id on a line item but a full object in a campaign's catalogue.

When you send a resource that embeds a child — a recipient in a create request, say — you supply it by value, without an id; the response echoes it back embedded, now carrying its server-assigned id.

Pagination

List endpoints page with a forward cursor. Pass limit to set the page size and after to continue from where the last page ended:

  • limit — how many records to return. Defaults to 25; each endpoint sets its own maximum.
  • after — the id of the last record from the previous page. Omit it on the first request.

Every collection response includes has_more. When it is true, take the id of the last item in data and pass it as after to fetch the next page; when it is false, you have reached the end.

curl "https://api.andopen.co/campaigns?limit=25&after=4fb4cb3f-9666-43b5-8884-7f5194483d1a" \
-H "Authorization: Bearer ao-v1-production-your_secret_here" \
-H "AndOpen-API-Version: 2026-05"

Errors

Errors are always returned as an array under errors, even when there is only one, so you can handle one and many the same way. Each error carries a type, a code, a human-readable message, and — for errors tied to a specific field — a param in dot notation.

{
"errors": [
{
"type": "validation_error",
"code": "required",
"message": "is required",
"param": "recipient.email"
}
]
}

See Errors for the full type and code taxonomy and the HTTP status each maps to.

Request IDs and rate limits

Every response includes a Request-Id header — a UUID identifying that request. Include it when you contact support so we can find the exact request in our logs.

Responses also carry rate-limit headers: RateLimit-Limit (the ceiling for the current window), RateLimit-Remaining (requests left), and RateLimit-Reset (the absolute Unix time, in seconds, when the window resets). When you are rate-limited, the response includes Retry-After — the number of seconds to wait before retrying. Use Retry-After for scheduling retries; RateLimit-Reset is an absolute timestamp, not a delay.

Forward compatibility

Within a version, adding a field, an endpoint, or an enum value is not a breaking change. Write your integration to ignore fields it does not recognise and to handle unknown enum and error-code values gracefully — typically by falling back to the error type or message. Doing so means new fields and values never break your code. See Versioning for the full list of what is and is not a breaking change.

OpenAPI specification

The full 2026-05 contract is available as a downloadable OpenAPI 3.1 specification. Use it to generate a client, validate requests and responses, or give an AI agent the exact request and response shapes.

New to &Open, or scoping whether to integrate? These guides cover the business and IT context behind the API: