Record a purchase

POST/api/public/purchases

Record a product purchase for a trainee. Credits, expiration and membership dates are derived from the product when omitted: a punch card opens with the product credits and a one-year expiration, a membership starts immediately for the product duration.

Authentication

Requires an API key, sent as Authorization: Bearer cp_live_....

API keys carry scopes. Get the catalog of scopes and webhook events lists every scope.

Header parameters

Header parameters
NameTypeDescription
Idempotency-Keystring

Optional. Send a unique key (e.g. a UUID) to make this POST safe to retry. The same key within 24h returns the original result instead of creating a duplicate.

Request body

application/json, required

Request body fields
NameTypeDescription
traineeIdrequiredstring

Trainee buying the product

productIdrequiredstring

Product to purchase. Must be active.

purchaseAmountnumber

Amount actually charged. Defaults to the product price.

Minimum: 0

currencystring

Defaults to ILS

Allowed values: ILS USD EUR GBP

statusstring

Defaults to ACTIVE. Use WAITING_FOR_PAYMENT to record a purchase before payment clears.

Allowed values: ACTIVE EXPIRED CANCELLED PENDING WAITING_FOR_PAYMENT

purchaseDatestring

Purchase date as YYYY-MM-DD or a full ISO-8601 date-time. Defaults to now. Use it to backdate an imported purchase.

expirationDatestring

Expiration as YYYY-MM-DD or a full ISO-8601 date-time, and never before purchaseDate. Defaults to one year from now for punch cards. A date in the past is accepted for history imports; the purchase flips to EXPIRED the first time its credits are used.

initialCreditsnumber

Punch card credits granted. PUNCH_CARD products only. Defaults to the product credits.

Minimum: 0

remainingCreditsnumber

Credits still available, and never more than initialCredits. PUNCH_CARD products only. Defaults to initialCredits; set it lower to import a partly used card.

Minimum: 0

Request examples

cURL
curl --request POST \
  --url 'https://api.coach-platform.com/api/public/purchases' \
  --header 'Authorization: Bearer cp_live_...' \
  --header 'Content-Type: application/json' \
  --data '{
  "traineeId": "<string>",
  "productId": "<string>"
}'
JavaScript (fetch)
const response = await fetch('https://api.coach-platform.com/api/public/purchases', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer cp_live_...',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "traineeId": "<string>",
    "productId": "<string>"
  }),
});

const data = await response.json();

Responses

201 Created

Example body (application/json)
{
  "data": {
    "id": "<string>",
    "coachId": "<string>",
    "traineeId": "<string>",
    "productId": "<string>",
    "purchaseDate": "<date-time>",
    "expirationDate": "<date-time>",
    "purchaseAmount": 123,
    "currency": "ILS",
    "status": "ACTIVE",
    "initialCredits": 123,
    "remainingCredits": 123,
    "membershipStartDate": "<date-time>",
    "membershipEndDate": "<date-time>",
    "currentPeriodUsages": 123,
    "periodResetDate": "<date-time>",
    "createdAt": "<date-time>",
    "updatedAt": "<date-time>"
  },
  "warnings": [
    {
      "field": "<string>",
      "message": "<string>"
    }
  ]
}
Response fields (21)
Response fields
NameTypeDescription
dataobject
data.idstring
data.coachIdstring
data.traineeIdstring
data.productIdstring
data.purchaseDatestring<date-time>
data.expirationDatestring<date-time>
data.purchaseAmountnumber
data.currencystring

Allowed values: ILS USD EUR GBP

data.statusstring

Allowed values: ACTIVE EXPIRED CANCELLED PENDING WAITING_FOR_PAYMENT

data.initialCreditsnumber
data.remainingCreditsnumber
data.membershipStartDatestring<date-time>
data.membershipEndDatestring<date-time>
data.currentPeriodUsagesnumber
data.periodResetDatestring<date-time>
data.createdAtstring<date-time>
data.updatedAtstring<date-time>
warningsobject[]

Non-fatal problems with follow-up writes. The resource was created, but each listed field was not applied.

warnings[].fieldstring
warnings[].messagestring

Error responses

  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 409 Conflict
  • 429 Too Many Requests
  • 500 Internal Server Error

These statuses share the same response body.

Example body (application/json)
{
  "error": {
    "code": "<string>",
    "message": "<string>",
    "fix": "<string>",
    "details": {},
    "retryAfterMs": 123
  }
}
Error fields (6)
Error fields
NameTypeDescription
errorobject
error.codestring
error.messagestring
error.fixstring | null
error.detailsobject | null
error.retryAfterMsnumber | null

This page is also available as Markdown. Browse it in the interactive explorer or download the OpenAPI spec.