# Record a purchase

`POST https://api.coach-platform.com/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.

- Resource: Purchases
- Authentication: API key in the `Authorization: Bearer cp_live_...` header
- HTML version: https://www.coach-platform.com/docs/api/reference/post-purchases
- OpenAPI spec: https://www.coach-platform.com/openapi.json

## Header parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `Idempotency-Key` | string | No | 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

Content type: `application/json`. Required.

| Field | Type | Required | Description |
|---|---|---|---|
| `traineeId` | string | Yes | Trainee buying the product |
| `productId` | string | Yes | Product to purchase. Must be active. |
| `purchaseAmount` | number | No | Amount actually charged. Defaults to the product price. Minimum: `0`. |
| `currency` | string | No | Defaults to ILS Allowed values: `ILS`, `USD`, `EUR`, `GBP`. |
| `status` | string | No | Defaults to ACTIVE. Use WAITING_FOR_PAYMENT to record a purchase before payment clears. Allowed values: `ACTIVE`, `EXPIRED`, `CANCELLED`, `PENDING`, `WAITING_FOR_PAYMENT`. |
| `purchaseDate` | string | No | Purchase date as YYYY-MM-DD or a full ISO-8601 date-time. Defaults to now. Use it to backdate an imported purchase. |
| `expirationDate` | string | No | 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. |
| `initialCredits` | number | No | Punch card credits granted. PUNCH_CARD products only. Defaults to the product credits. Minimum: `0`. |
| `remainingCredits` | number | No | 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`. |

## Responses

| Status | Description |
|---|---|
| `201` Created |  |
| `400` Bad Request |  |
| `401` Unauthorized |  |
| `403` Forbidden |  |
| `404` Not Found |  |
| `409` Conflict |  |
| `429` Too Many Requests |  |
| `500` Internal Server Error |  |

### 201 Created

Content type: `application/json`

| Field | Type | Description |
|---|---|---|
| `data` | object |   |
| `data.id` | string |   |
| `data.coachId` | string |   |
| `data.traineeId` | string |   |
| `data.productId` | string |   |
| `data.purchaseDate` | string<date-time> |   |
| `data.expirationDate` | string<date-time> |   |
| `data.purchaseAmount` | number |   |
| `data.currency` | string | Allowed values: `ILS`, `USD`, `EUR`, `GBP`. |
| `data.status` | string | Allowed values: `ACTIVE`, `EXPIRED`, `CANCELLED`, `PENDING`, `WAITING_FOR_PAYMENT`. |
| `data.initialCredits` | number |   |
| `data.remainingCredits` | number |   |
| `data.membershipStartDate` | string<date-time> |   |
| `data.membershipEndDate` | string<date-time> |   |
| `data.currentPeriodUsages` | number |   |
| `data.periodResetDate` | string<date-time> |   |
| `data.createdAt` | string<date-time> |   |
| `data.updatedAt` | string<date-time> |   |
| `warnings` | object[] | Non-fatal problems with follow-up writes. The resource was created, but each listed field was not applied. |
| `warnings[].field` | string |   |
| `warnings[].message` | string |   |

Example:

```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>"
    }
  ]
}
```

### Error responses 400, 401, 403, 404, 409, 429, 500

Content type: `application/json`

| Field | Type | Description |
|---|---|---|
| `error` | object |   |
| `error.code` | string |   |
| `error.message` | string |   |
| `error.fix` | string \| null |   |
| `error.details` | object \| null |   |
| `error.retryAfterMs` | number \| null |   |

Example:

```json
{
  "error": {
    "code": "<string>",
    "message": "<string>",
    "fix": "<string>",
    "details": {},
    "retryAfterMs": 123
  }
}
```

## Examples

### cURL

```bash
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)

```js
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();
```

## Related endpoints

- [List purchases](https://www.coach-platform.com/docs/api/reference/get-purchases/index.md): `GET /api/public/purchases`. List customer purchases.
- [Get a purchase](https://www.coach-platform.com/docs/api/reference/get-purchases-purchase-id/index.md): `GET /api/public/purchases/{purchaseId}`. Get a customer purchase by id.
- Previous: [List purchases](https://www.coach-platform.com/docs/api/reference/get-purchases/index.md): `GET /api/public/purchases`. List customer purchases.
- Next: [Get a purchase](https://www.coach-platform.com/docs/api/reference/get-purchases-purchase-id/index.md): `GET /api/public/purchases/{purchaseId}`. Get a customer purchase by id.
