Skip to main content
Version: 2026-05

Cancel a gift request

POST /gift_requests/{id}/cancel

Description​

Cancels a gift request the recipient hasn't redeemed yet, so they can no longer redeem it. Their redemption_url then lands on an expired-gift page, and &Open sends the gift_request_cancelled webhook. The response is the cancelled gift request, in the same shape Get a gift request returns.

When to use​

Reach for this endpoint when a gift should no longer go out: the recipient has left the company, the deal fell through, or the gift was sent to the wrong person. Only a gift request whose status is submitted can be cancelled.

Read the gift request's cancellable field first, with Get a gift request or List gift requests. It's true when the gift request's current state allows a cancel, so you can hide or disable a cancel action for one that has moved on. Still handle the errors below: the state can change between your read and the cancel, and a token that can read a gift request isn't always allowed to cancel it.

An admin or a system token can cancel any gift request in your account, as can an OAuth token from an account-level partner grant. Any other user, or a user-level grant made by a non-admin, can cancel only the gift requests they sent; one outside that scope returns 404, the same as one that doesn't exist.

Parameters​

Path​

id (string · uuid · required) is the gift request to cancel. An id that doesn't match a gift request you can see returns 404.

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.

Idempotency-Key (string · optional) keys a retry explicitly, but you don't need one here. The request takes no body, so a retry is already matched on the gift request id, exactly as you sent it in the path, for 24 hours. A repeat within that window returns the original 200 response, with an Idempotent-Replayed: true header, and changes nothing. That means a retry after a timeout gets the cancelled gift request back, not a 422.

Send a key when you want to name the retry yourself. Reusing a key within 24 hours for a different gift request returns a 422 with idempotency_key_mismatch.

Only a successful cancel is stored. A refusal (404, 403, or not_cancellable) is never replayed: a retry is checked again from scratch.

Worked examples​

A cancel is a POST to the gift request's cancel path, with no request body. The JavaScript, Python, and Ruby versions send the cancel and read the new status off the response; swap in the id you want to cancel.

curl -X POST https://api.andopen.co/gift_requests/4fb4cb3f-9666-43b5-8884-7f5194483d1a/cancel \
-H "Authorization: Bearer <api_key>" \
-H "AndOpen-API-Version: 2026-05"

Response shape​

A successful call returns 200 OK with the cancelled gift request as a flat top-level JSON object: the same shape Get a gift request returns, with status now cancelled.

FieldDescription
reference (string · required)A human-readable handle for the gift request, unique within your account and stable for its lifetime. Show it to your own users and quote it to support; the API itself takes the id.
status (string · required)The public-facing status, one of submitted, redeemed, dispatched, delivered, cancelled. After a successful cancel it's cancelled.
cancellable (boolean · required)Whether the gift request's current state allows a cancel. Always false in this response, because the gift request is already cancelled.
campaign (object · required · nullable)The campaign this request belongs to, embedded as an { id, name, web_url } summary. null for an ad-hoc send that belongs to no campaign.
redemption_url (string · uri · required)The recipient's link. It's still returned, but now opens an expired-gift page.
web_url (string · uri · required)The gift request's page in the &Open web app, on your organization's own domain. This is the sender-facing view and needs a signed-in session.
recipient (object · required)The recipient, returned inline.
sender (object · required)The user recorded as responsible for the send, embedded as an { id, name, email } summary.
offering (object · required)What was put in front of the recipient: the items on offer, whether they receive all of them or choose one, and whether they see them at redemption.
line_items (array · required · nullable)null, because a gift request is only cancellable before the recipient chooses, so its items were never locked.
lifecycle_events (object · required)When each step happened before the cancel, such as when the invitation email was sent and when the recipient first opened it. redeemed_at, dispatched_at, and delivered_at are null.

The response also carries invitation_method, invitation_subject, and notecard_message, as described on Get a gift request.

Response · 200
{
"id": "4fb4cb3f-9666-43b5-8884-7f5194483d1a",
"reference": "ACME-M5RD6J8",
"status": "cancelled",
"cancellable": false,
"invitation_method": "email_invitation",
"campaign": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Q4 Customer Appreciation",
"web_url": "https://acme.andopen.co/sender/gift-history/campaigns/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"redemption_url": "https://gift.andopen.co/r/abc123",
"web_url": "https://acme.andopen.co/sender/gift-history/4fb4cb3f-9666-43b5-8884-7f5194483d1a",
"recipient": {
"id": "b2c3d4e5-f6a7-8901-bcde-f01234567890",
"thank_you_count": 0,
"first_name": "Alice",
"last_name": "Smith",
"name": "Alice Smith",
"email": "alice@example.com"
},
"sender": {
"id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"name": "Dana Okafor",
"email": "dana@acme.example"
},
"shipping_address": null,
"offering": {
"selection_mode": "one",
"visible_at_redemption": true,
"line_items": [
{
"id": "f6a7b8c9-d0e1-2345-6789-0abcdef01234",
"sku": "NOTEBOOK-A5",
"variant_id": "a7b8c9d0-e1f2-3456-789a-bcdef0123456",
"name": "Leather Notebook",
"quantity": 1,
"images": [
{
"name": "leather-notebook.jpg",
"url": "https://files.andopen.co/rndd63mwgj94j2vf3v2ngnye0hkn",
"urls": {
"thumbnail": "https://files.andopen.co/vw2mvwevyqxh98l7esf67nvunr4h",
"large": "https://files.andopen.co/mz4rc8kx1nvq7j93wtf5bd2hs0yl",
"large_wide": "https://files.andopen.co/q7pz3n8htv2ke0d5rjw94flxs6cb"
}
}
]
}
]
},
"line_items": null,
"email_message": {
"subject": "A small thank-you",
"body": "Thanks for being a great customer!"
},
"invitation_subject": "A small thank-you",
"notecard_message": null,
"lifecycle_events": {
"invitation_email_sent_at": "2026-04-16T10:31:00.000Z",
"invitation_first_opened_at": "2026-04-16T18:40:00.000Z",
"invitation_last_opened_at": "2026-04-17T08:12:00.000Z",
"reminder_sent_at": null,
"redeemed_at": null,
"dispatched_at": null,
"delivered_at": null
},
"created_at": "2026-04-16T10:30:00.000Z",
"updated_at": "2026-04-18T09:15:00.000Z"
}

Per-field notes​

  • cancellable is true only while status is submitted. Read it before you offer a cancel action, rather than comparing status yourself.
  • A cancel is final. There's no endpoint to restore a cancelled gift request, so create a new one with Create a gift request if you change your mind.
  • The gift_request_cancelled webhook fires for this cancel. The same event also fires when a gift request expires, so don't treat every delivery as a cancel you made. See Webhooks.

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.
404The requested resource does not exist.
409An identical request under the same idempotency key is still being processed. Retry after the interval in the Retry-After header.
422Validation error: the request was parseable but contains invalid data. All validation errors are returned at once.
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 failure you'll handle most is a gift request that has moved on:

  • 422 validation_error:
    • not_cancellable: the gift request is already redeemed, dispatched, delivered, or cancelled. The message names its current status. This isn't a field problem, so there's no param.
    • idempotency_key_mismatch: the Idempotency-Key you sent was used in the last 24 hours for a different gift request. Use a fresh key.
  • 404 not_found_error: not_found. No gift request with that id, or one you're not allowed to see.
  • 409 api_error: request_in_progress. An identical cancel is still being processed, so this one was neither run nor rejected. Wait the number of seconds in the Retry-After header and send it again.
  • 401 authentication_error: the token is missing, unrecognized, or expired (unauthorized). A token is only valid in the region it was issued for, so one presented to the wrong region fails the same way.
  • 403 authorization_error: the token authenticated but isn't allowed to cancel gift requests (forbidden).
  • 400 api_error: unsupported_api_version when the AndOpen-API-Version header is missing or unsupported (returned before authentication), or malformed_request for an Idempotency-Key that is empty or longer than 255 characters.
  • 429 rate_limit_error: you've exceeded the rate limit; back off using the Retry-After header.
  • 500 / 503 api_error: a fault on our side; rare, and safe to retry after a short delay (honor Retry-After on a 503).

A gift request the recipient has already redeemed returns a single error with no param:

Response · 422
{
"errors": [
{
"type": "validation_error",
"code": "not_cancellable",
"message": "Gift request is already redeemed"
}
]
}