Purchases
2 endpoints
/v1/purchasesRecord a purchase made outside Capturia
A store, a course platform or a backend sends a purchase made on its
side. Capturia resolves the buyer the same way as an event
(external_ → phone → email, contact created if needed), records
the purchase on the contact (customer of this offer since the purchase
date), files the purchase in its offer's deal and moves the card of the
current deal to the won stage. The purchase also starts the "Payment
received" automations, the "Purchase completed" gateway of your
systems and the "Custom event" automations listening to the purchase
event, recorded on the contact.
Idempotency
A purchase is unique by its external_: sent again with the same
offer, amount and currency, the response returns the purchase already
recorded (200, created: false) without restarting anything; sent
with another offer, amount or currency, it is rejected (409 purchase_). The Idempotency- header remains available
for retries.
Availability
Online sales must be open for the account, otherwise 403 feature_. An archived contact rejects the purchase (422 contact_): restore it, then send the purchase again.
Past purchases
A purchase dated (purchased_) more than two days ago, for example
when importing a sales history, is recorded on the contact and in its
offer's deal, and the purchase event is recorded; but it is not a
sale of the day: neither the "Payment received" automations, nor the
"Purchase completed" gateway, nor the "New sale" bell start for it.
events:ingestHeaders
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | optional | Idempotency key (UUID v4 or ULID recommended). A second request with the same key and the same payload returns the original response without repeating the operation. Stored for 24h. Optional but recommended. |
Request body
| Property | Type | Required | Description |
|---|---|---|---|
external_id | string | required | Identifier of the purchase in the source system (order number,
transaction ID). Makes the call idempotent: the same external_ sent
again unchanged returns the purchase already recorded. |
offer | object | required | The purchased offer: key (required), its stable identifier in the
source system (SKU, product identifier); name (optional), the name
shown on the contact, read on the first purchase with this key. |
amount_cents | integer | required | Amount paid, in cents, before taxes. |
currency | string | optional | ISO 4217 currency of the amount. |
purchased_at | string | optional | Purchase date, today at the latest. Default: when the request is received. |
contact | EventIngestContact | required | Identity of the contact the event targets. At least one identifier is
required among external_, email, phone. The server resolves the contact
in the order external_+external_ → phone → email; the identity
fields you send enrich the contact non-destructively (a
value that is already set is never overwritten). |
source_label | string | optional | Free-form label identifying the source (shown on the contact). |
Responses
| Status | Description |
|---|---|
200 | Purchase already received under this |
201 | Purchase recorded. |
400 | The request is malformed (missing header, invalid JSON, invalid parameter). |
401 | Unknown API key or invalid format. |
403 | Authorization denied. Two causes, distinguished by |
404 | The requested resource doesn't exist (or isn't within the tenant's scope). |
409 | A resource with a conflicting unique identifier already exists. |
422 | Parameter or body validation failed. |
429 | The per-window request quota has been exceeded for this API key or endpoint. |
500 | Unexpected server error. Always include the |
Example request
curl -X POST 'https://api.capturia.io/v1/purchases' \
-H 'Authorization: Bearer cap_live_<your-key>' \
-H 'Content-Type: application/json' \
-d '{
"external_id": "commande-10482",
"offer": {
"key": "formation-vente-avancee",
"name": "Formation vente avancée"
},
"amount_cents": 49700,
"currency": "CAD",
"purchased_at": "2026-10-18T14:32:00-04:00",
"contact": {
"email": "[email protected]",
"first_name": "Alex"
},
"source_label": "Boutique en ligne"
}'/v1/purchases/refundsRecord a purchase refund
Sets the total amount refunded for a purchase received through POST / (the running total, not the latest refund). Once fully
refunded, the purchase becomes refunded and the contact is no longer
a customer of this offer; a lower total, after a cancelled refund,
makes the contact a customer again. Sending the same total again
changes nothing. A $0 purchase cannot be refunded. A total greater
than the purchase amount is rejected (422 refund_) and
nothing changes. An unknown purchase returns 404 purchase_.
events:ingestHeaders
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | optional | Idempotency key (UUID v4 or ULID recommended). A second request with the same key and the same payload returns the original response without repeating the operation. Stored for 24h. Optional but recommended. |
Request body
| Property | Type | Required | Description |
|---|---|---|---|
external_id | string | required | The external_ of the refunded purchase. |
refunded_cents | integer | required | Total amount refunded for this purchase, in cents (the running total,
not the latest refund). At most the purchase amount: above it, the
refund is rejected (422 refund_). |
Responses
| Status | Description |
|---|---|
200 | Refund recorded. |
400 | The request is malformed (missing header, invalid JSON, invalid parameter). |
401 | Unknown API key or invalid format. |
403 | Authorization denied. Two causes, distinguished by |
404 | The requested resource doesn't exist (or isn't within the tenant's scope). |
409 | A previous request with the same |
422 | Parameter or body validation failed. |
429 | The per-window request quota has been exceeded for this API key or endpoint. |
500 | Unexpected server error. Always include the |
Example request
curl -X POST 'https://api.capturia.io/v1/purchases/refunds' \
-H 'Authorization: Bearer cap_live_<your-key>' \
-H 'Content-Type: application/json' \
-d '{
"external_id": "commande-10482",
"refunded_cents": 49700
}'