Sales

Record a sale

Charge -> sale -> commission -> balance, atomically, through the same writer the processor webhooks use. Idempotent on external_charge_id: sending the same charge twice returns the same sale with a 200 instead of a 201. amount_minor is gross; tax is subtracted before the rate when the program commissions on net revenue. The response says explicitly whether money followed: activity_outcome is commission_created or sale_recorded, and a sale that paid nobody carries machine-readable warnings instead of failing the call. Customer auto-enrol runs on processor webhooks, not on this endpoint. Charge ids are unique per program, so another program using the same id never affects yours. A charge id already recorded in your program in the other mode (a test-mode id sent with a live key, or the reverse) answers 409 external_charge_id_taken with no sale fields.

Scope: commissions:write (or write)

post/v1/sales

Request

  • Base URL: https://api.affiliaterail.com
  • URL: https://api.affiliaterail.com/v1/sales
  • Auth: HTTP bearer

Request body

program_idstring required

Prefixed id (prg_…)

customer_idstring required

Prefixed id (cus_…)

external_charge_idstring required

Your charge id. One charge produces at most one sale, forever.

amount_minorinteger required

Integer minor units (cents, pence). Never a float, never a string.

tax_minorinteger nullable

Integer minor units (cents, pence). Never a float, never a string.

currencystring required

ISO-4217

billing_type'one_time' | 'subscription'
interval'day' | 'week' | 'month' | 'year' | 'null' nullable
product_idstring nullable
product_namestring nullable
occurred_atstring date-time

ISO-8601, UTC

metadataobject nullable

Your own key/value data, stored as given

Example request

{
  "program_id": "prg_7uSyy9FqVLCFWrdPeZaK",
  "customer_id": "cus_7uSyy9FqVLCFWrdPeZaK",
  "amount_minor": 2500,
  "tax_minor": 2500,
  "currency": "USD",
  "occurred_at": "2026-08-21T10:15:30.000Z"
}

Response

Already recorded: the existing sale

idstring required

Prefixed id (sale_…)

object'sale' required
program_idstring required

Prefixed id (prg_…)

customer_idstring required

Prefixed id (cus_…)

partner_idstring required

Prefixed id (part_…)

external_charge_idstring required
external_payment_intent_idstring nullable required
processor'stripe' | 'paddle' | 'chargebee' | 'manual' | 'api' required
amount_minorinteger required

Integer minor units (cents, pence). Never a float, never a string.

tax_minorinteger nullable required

Integer minor units (cents, pence). Never a float, never a string.

currencystring required

ISO-4217

billing_type'one_time' | 'subscription' required
interval'day' | 'week' | 'month' | 'year' | 'null' nullable required
product_idstring nullable required
product_namestring nullable required
is_first_saleboolean required
occurred_atstring date-time required

ISO-8601, UTC

refunded_atstring date-time nullable required

ISO-8601, UTC

metadataobject nullable required

Your own key/value data, stored as given

created_atstring date-time required

ISO-8601, UTC

updated_atstring date-time required

ISO-8601, UTC

activity_outcome'commission_created' | 'sale_recorded' required

commission_created when the sale produced a commission; sale_recorded when we accepted the sale and paid nobody (see warnings for why)

Example response

{
  "id": "sale_7uSyy9FqVLCFWrdPeZaK",
  "program_id": "prg_7uSyy9FqVLCFWrdPeZaK",
  "customer_id": "cus_7uSyy9FqVLCFWrdPeZaK",
  "partner_id": "part_7uSyy9FqVLCFWrdPeZaK",
  "amount_minor": 2500,
  "tax_minor": 2500,
  "currency": "USD",
  "occurred_at": "2026-08-21T10:15:30.000Z",
  "refunded_at": "2026-08-21T10:15:30.000Z",
  "created_at": "2026-08-21T10:15:30.000Z",
  "updated_at": "2026-08-21T10:15:30.000Z"
}

Changes

No recorded changes to this operation across all 1 revision of this API.