Skip to main content
POST
Report a refunded purchase
Part of the v2 events contract. See also: signup created, purchase created, demo attended.

Headers

Idempotency-Key
string

An opaque key identifying this submission attempt, so that a retry can be recognised as the same event.

A repeat of the same request, for the same tenant and event type, within 72 hours returns the original 202 — the same eventId, receivedAt, and warnings — and does not create a second event. A repeat that uses the same key with a different body is refused with 409 and IDEMPOTENCY_CONFLICT. After 72 hours the same key is a new submission.

The same key may be sent in the idempotencyKey body field instead. If both are sent they must be equal after trim, otherwise the request is refused with IDEMPOTENCY_KEY_CONFLICT — there is no precedence rule, because guessing which one the caller meant is worse than saying so.

Leading and trailing whitespace is trimmed on both forms before the key is stored or compared. The 1–255 character limit applies to that trimmed value; a key that is empty after trim is refused.

Required string length: 1 - 255

Body

application/json
ucc
string
required

The unique Cello code that attributes this event to a referral.

Required string length: 1 - 255
Example:

"ucc_7f3d9a"

occurredAt
string<rfc3339-offset>
required

When the event happened in your system, as an RFC 3339 date-time with an explicit UTC offset: either Z or ±HH:MM.

The offset is mandatory and the T separator is mandatory. A local time with no offset is ambiguous by exactly the amount that makes referral attribution wrong, and 2022-10-05 14:14:34 is refused even though v1 tolerated it.

A syntactically valid timestamp is never refused for being implausible, however far it is from our clock. If it looks wrong we accept the event and tell you so in warnings, because dropping a real purchase over a misconfigured clock is the worse failure.

Examples:

"2026-08-05T16:14:34+02:00"

"2026-08-05T14:14:34Z"

newUser
Referred user · object
required

The referred user this event is about. Only id is required; the rest improves what Cello can show in the portal.

currency
string<iso4217>
required

An uppercase ISO 4217 alphabetic code, validated against the code list rather than against a three-letter pattern, so EUR is accepted and eur and XYZ are both refused with a message saying which rule they broke.

The same code selects the minor-unit exponent that interprets amount in documentation (JPY is ¥1580, not 158000). The exponent is not used to rescale v1 payload.price; v1 is already in minor units.

Examples:

"JPY"

"USD"

"EUR"

invoiceId
string
required

The payment being reported or reversed. Any stable identifier from your billing system is acceptable, as long as the refund for a purchase carries the same one the purchase did. Required on both money endpoints, because without it a refund cannot be matched to what it reverses.

Required string length: 1 - 255
Example:

"inv_456"

amount
integer
required

The positive magnitude of the refund. The event type already says this is a reversal, so a negative amount is a mistake rather than a direction, and a zero-value refund is not an event.

Required range: 1 <= x <= 9007199254740991
Example:

4900

idempotencyKey
string

The body form of the Idempotency-Key header. See that header for the full description. Leading and trailing whitespace is trimmed; the 1–255 character limit applies after trim.

Required string length: 1 - 255
Example:

"purchase-inv_456"

subscription
Subscription detail · object

Detail about the subscription the payment belongs to. Required on purchase-created, where interval is required. Optional on purchase-refunded, where every field is optional.

Response

The event was validated and durably written to the event stream.

This says the event was accepted, not that attribution or reward accrual has run. Those happen asynchronously afterwards.

eventId
string<uuid>
required

A UUIDv7 assigned by Cello. It is the identifier of the stored event (id on the stream record). Quote it in support conversations. Never accepted from a request body.

Example:

"019205ff-8e00-7cc0-9f2e-2b4c1d5a6e70"

receivedAt
string<date-time>
required

When Cello received the event, from our clock. Compare it with your occurredAt to see the skew we saw. Never accepted from a request body.

Example:

"2026-08-05T14:14:35.123Z"

warnings
Warning · object[]

Non-fatal observations about an accepted event. Absent entirely when there is nothing to report, rather than present and empty.

A warning never changes the status code and never changes how the event is processed: an event carrying warnings is stored, attributed and rewarded exactly like one without.

New codes may appear at any time without a version bump, so treat an unrecognised code as informational rather than failing on it.

Minimum array length: 1