Skip to main content
Cresora Commerce

Recurring

Manage recurring billing plans. First payment captures a gateway token via HPP; subsequent charges use the stored token. Retries are configurable per plan (soft decline + ACH R01).

🔬Planned operations — published for review, not callable
This reference includes operations marked x-cresora-status: planned in the canonical contract: they have no route on any host and return 404 (or 501 for reserved discriminator variants) until released. There is no separate preview stream, no feature flag to enable one, and no enrollment — the badge on each operation tells you whether it is served. See the stable /api/v1 reference for what you can call today. Like the stable API, these operations are server-to-server: there is no interactive console here. Download the preview spec (YAML).
GET/contracts

Authorization

BearerAuth
AuthorizationBearer <token>

Cresora API key, sent as an opaque bearer token in the Authorization header. Format:

csk_<prefix>_<random>
  • <prefix> — 8 URL-safe chars, shown in UI and logs for identification without revealing the full key (e.g. csk_Ab3kX9mQ…). Use ApiKey.prefix to match.
  • <random> — 24+ cryptographically random URL-safe chars.

Obtain via Partner Portal → Settings → API keys. Keys are only shown in full at creation/rotation time — Cresora does not retain the full value in retrievable form. Rotate any key that may have been exposed via logs, client code, or source control.

In: header

Query Parameters

cursor?string

Opaque pagination cursor from previous response. Do not parse.

Lengthlength <= 256
page_size?integer

Items per page (1–100).

Range1 <= value <= 100
Default25

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X GET "https://example.com/contracts"
{  "data": [    {      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",      "merchant_name": "string",      "rail": "CARD",      "card_last4": "string",      "amount_per_period": 0,      "currency": "USD",      "period_unit": "DAILY",      "total_periods": 0,      "periods_completed": 0,      "state": "PENDING_ACTIVATION"    }  ],  "pagination": {    "next_cursor": "string",    "has_more": true,    "total_count": 0  }}
POST/contracts

Authorization

BearerAuth
AuthorizationBearer <token>

Cresora API key, sent as an opaque bearer token in the Authorization header. Format:

csk_<prefix>_<random>
  • <prefix> — 8 URL-safe chars, shown in UI and logs for identification without revealing the full key (e.g. csk_Ab3kX9mQ…). Use ApiKey.prefix to match.
  • <random> — 24+ cryptographically random URL-safe chars.

Obtain via Partner Portal → Settings → API keys. Keys are only shown in full at creation/rotation time — Cresora does not retain the full value in retrievable form. Rotate any key that may have been exposed via logs, client code, or source control.

In: header

Header Parameters

Idempotency-Key*string

Client-generated unique key — a UUIDv4 is the recommended form. Cresora deduplicates within a 24-hour window scoped to the partner.

Format: 1–128 characters of letters, digits, . _ : -. Anything else is rejected with 400 validation_error. The character set is narrower than base64: padded base64 (+ / =) is NOT accepted, base64url is. The key is forwarded verbatim to the payment gateway on transaction creates, so it must satisfy the gateway's key contract too — rejecting locally gives you an actionable error instead of an opaque upstream failure mid-request.

Reserved prefixes — rejected with 400 idempotency_key_reserved:

  • hpp:, recurring: — Cresora's own server-minted deterministic keys. A client key in these namespaces could collide with a platform-generated record.
  • rb:, inv-charge:, inv-installment: — reserved by the payment gateway for its internally-minted keys.

Replay semantics:

  • Same key + same request body → Cresora returns the cached response from the original call. Response includes header X-Idempotent-Replay: true so the client can distinguish replays from fresh executions. Status code, body and side effects are identical to the original call.
  • Same key + different body → 422 idempotency_key_reused. Generate a new key and retry, or re-send the original body.
  • Key older than 24 hours → treated as a fresh key; no replay guarantee from beyond the window.

Retrying after an indeterminate failure. On 502 gateway_outcome_unknown the transaction is recorded as pending and the outcome is not yet known — retry with the SAME key (a fresh key risks a double charge) or poll the transaction. This is also what a gateway-side "an earlier request with this key is still in flight" response surfaces as.

Do NOT reuse keys across different partners. Scope is enforced per partner_id so the same key in partner A and partner B is independent.

Match^[A-Za-z0-9._:\-]+$
Length1 <= length <= 128

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X POST "https://example.com/contracts" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{    "merchant_id": "500924a8-3f5e-4c00-beb8-2efcde988aea",    "payment_method_type": "string",    "payment_method_token": "string",    "amount": "string",    "frequency": "string",    "start_date": "2019-08-24"  }'
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "partner_id": "6a3a39f6-861b-4a48-b868-5de838400e06",  "merchant_id": "500924a8-3f5e-4c00-beb8-2efcde988aea",  "state": "PENDING_ACTIVATION",  "payment_method_type": "CARD",  "amount": "string",  "currency": "USD",  "frequency": "DAILY",  "start_date": "2019-08-24",  "end_date": "2019-08-24",  "total_amount": "string",  "remaining_installments": 0,  "amount_paid": "string",  "last_successful_charge_date": "2019-08-24",  "next_charge_date": "2019-08-24",  "retry_count": 0,  "max_retries": 0,  "created_at": "2019-08-24T14:15:22Z",  "custom_fields": [    {      "name": "patientId",      "value": "PT48213"    }  ],  "level2_data": {    "po_number": "string",    "merchant_zip": "string"  },  "level3_data": {    "ship_from_zip": "string",    "destination_zip": "string",    "destination_country_code": "string",    "invoice_number": "string",    "order_number": "string",    "duty_amount": "string",    "freight_amount": "string",    "discount_amount": "string",    "line_items": [      {        "product_code": "string",        "commodity_code": "string",        "description": "string",        "upc": "string",        "invoice_number": "string",        "tax_type": "string",        "quantity": "string",        "unit_of_measure": "string",        "unit_price": "string",        "discount_amount": "string",        "total_amount": "string",        "tax_amount": "string",        "tax_rate": "string",        "extended_amount": "string",        "freight_amount": "string",        "duty_amount": "string",        "tax_included": true      }    ]  }}
GET/contracts/{contractId}

Authorization

BearerAuth
AuthorizationBearer <token>

Cresora API key, sent as an opaque bearer token in the Authorization header. Format:

csk_<prefix>_<random>
  • <prefix> — 8 URL-safe chars, shown in UI and logs for identification without revealing the full key (e.g. csk_Ab3kX9mQ…). Use ApiKey.prefix to match.
  • <random> — 24+ cryptographically random URL-safe chars.

Obtain via Partner Portal → Settings → API keys. Keys are only shown in full at creation/rotation time — Cresora does not retain the full value in retrievable form. Rotate any key that may have been exposed via logs, client code, or source control.

In: header

Path Parameters

contractId*string
Formatuuid

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X GET "https://example.com/contracts/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "partner_id": "6a3a39f6-861b-4a48-b868-5de838400e06",  "merchant_id": "500924a8-3f5e-4c00-beb8-2efcde988aea",  "state": "PENDING_ACTIVATION",  "payment_method_type": "CARD",  "amount": "string",  "currency": "USD",  "frequency": "DAILY",  "start_date": "2019-08-24",  "end_date": "2019-08-24",  "total_amount": "string",  "remaining_installments": 0,  "amount_paid": "string",  "last_successful_charge_date": "2019-08-24",  "next_charge_date": "2019-08-24",  "retry_count": 0,  "max_retries": 0,  "created_at": "2019-08-24T14:15:22Z",  "custom_fields": [    {      "name": "patientId",      "value": "PT48213"    }  ],  "level2_data": {    "po_number": "string",    "merchant_zip": "string"  },  "level3_data": {    "ship_from_zip": "string",    "destination_zip": "string",    "destination_country_code": "string",    "invoice_number": "string",    "order_number": "string",    "duty_amount": "string",    "freight_amount": "string",    "discount_amount": "string",    "line_items": [      {        "product_code": "string",        "commodity_code": "string",        "description": "string",        "upc": "string",        "invoice_number": "string",        "tax_type": "string",        "quantity": "string",        "unit_of_measure": "string",        "unit_price": "string",        "discount_amount": "string",        "total_amount": "string",        "tax_amount": "string",        "tax_rate": "string",        "extended_amount": "string",        "freight_amount": "string",        "duty_amount": "string",        "tax_included": true      }    ]  }}
PATCH/contracts/{contractId}

Authorization

BearerAuth
AuthorizationBearer <token>

Cresora API key, sent as an opaque bearer token in the Authorization header. Format:

csk_<prefix>_<random>
  • <prefix> — 8 URL-safe chars, shown in UI and logs for identification without revealing the full key (e.g. csk_Ab3kX9mQ…). Use ApiKey.prefix to match.
  • <random> — 24+ cryptographically random URL-safe chars.

Obtain via Partner Portal → Settings → API keys. Keys are only shown in full at creation/rotation time — Cresora does not retain the full value in retrievable form. Rotate any key that may have been exposed via logs, client code, or source control.

In: header

Path Parameters

contractId*string
Formatuuid

Header Parameters

Idempotency-Key*string

Client-generated unique key — a UUIDv4 is the recommended form. Cresora deduplicates within a 24-hour window scoped to the partner.

Format: 1–128 characters of letters, digits, . _ : -. Anything else is rejected with 400 validation_error. The character set is narrower than base64: padded base64 (+ / =) is NOT accepted, base64url is. The key is forwarded verbatim to the payment gateway on transaction creates, so it must satisfy the gateway's key contract too — rejecting locally gives you an actionable error instead of an opaque upstream failure mid-request.

Reserved prefixes — rejected with 400 idempotency_key_reserved:

  • hpp:, recurring: — Cresora's own server-minted deterministic keys. A client key in these namespaces could collide with a platform-generated record.
  • rb:, inv-charge:, inv-installment: — reserved by the payment gateway for its internally-minted keys.

Replay semantics:

  • Same key + same request body → Cresora returns the cached response from the original call. Response includes header X-Idempotent-Replay: true so the client can distinguish replays from fresh executions. Status code, body and side effects are identical to the original call.
  • Same key + different body → 422 idempotency_key_reused. Generate a new key and retry, or re-send the original body.
  • Key older than 24 hours → treated as a fresh key; no replay guarantee from beyond the window.

Retrying after an indeterminate failure. On 502 gateway_outcome_unknown the transaction is recorded as pending and the outcome is not yet known — retry with the SAME key (a fresh key risks a double charge) or poll the transaction. This is also what a gateway-side "an earlier request with this key is still in flight" response surfaces as.

Do NOT reuse keys across different partners. Scope is enforced per partner_id so the same key in partner A and partner B is independent.

Match^[A-Za-z0-9._:\-]+$
Length1 <= length <= 128

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

All fields optional — only present fields are considered. Accepted: next_charge_date, end_date, reason. amount, frequency, and max_retries are surfaced only to produce a structured recurring_update_not_supported rejection — changing them requires cancel-and-recreate.

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X PATCH "https://example.com/contracts/497f6eca-6276-4993-bfeb-53cbbbba6f08" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{}'
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "partner_id": "6a3a39f6-861b-4a48-b868-5de838400e06",  "merchant_id": "500924a8-3f5e-4c00-beb8-2efcde988aea",  "state": "PENDING_ACTIVATION",  "payment_method_type": "CARD",  "amount": "string",  "currency": "USD",  "frequency": "DAILY",  "start_date": "2019-08-24",  "end_date": "2019-08-24",  "total_amount": "string",  "remaining_installments": 0,  "amount_paid": "string",  "last_successful_charge_date": "2019-08-24",  "next_charge_date": "2019-08-24",  "retry_count": 0,  "max_retries": 0,  "created_at": "2019-08-24T14:15:22Z",  "custom_fields": [    {      "name": "patientId",      "value": "PT48213"    }  ],  "level2_data": {    "po_number": "string",    "merchant_zip": "string"  },  "level3_data": {    "ship_from_zip": "string",    "destination_zip": "string",    "destination_country_code": "string",    "invoice_number": "string",    "order_number": "string",    "duty_amount": "string",    "freight_amount": "string",    "discount_amount": "string",    "line_items": [      {        "product_code": "string",        "commodity_code": "string",        "description": "string",        "upc": "string",        "invoice_number": "string",        "tax_type": "string",        "quantity": "string",        "unit_of_measure": "string",        "unit_price": "string",        "discount_amount": "string",        "total_amount": "string",        "tax_amount": "string",        "tax_rate": "string",        "extended_amount": "string",        "freight_amount": "string",        "duty_amount": "string",        "tax_included": true      }    ]  }}
POST/contracts/{contractId}/cancel

Authorization

BearerAuth
AuthorizationBearer <token>

Cresora API key, sent as an opaque bearer token in the Authorization header. Format:

csk_<prefix>_<random>
  • <prefix> — 8 URL-safe chars, shown in UI and logs for identification without revealing the full key (e.g. csk_Ab3kX9mQ…). Use ApiKey.prefix to match.
  • <random> — 24+ cryptographically random URL-safe chars.

Obtain via Partner Portal → Settings → API keys. Keys are only shown in full at creation/rotation time — Cresora does not retain the full value in retrievable form. Rotate any key that may have been exposed via logs, client code, or source control.

In: header

Path Parameters

contractId*string
Formatuuid

Header Parameters

Idempotency-Key*string

Client-generated unique key — a UUIDv4 is the recommended form. Cresora deduplicates within a 24-hour window scoped to the partner.

Format: 1–128 characters of letters, digits, . _ : -. Anything else is rejected with 400 validation_error. The character set is narrower than base64: padded base64 (+ / =) is NOT accepted, base64url is. The key is forwarded verbatim to the payment gateway on transaction creates, so it must satisfy the gateway's key contract too — rejecting locally gives you an actionable error instead of an opaque upstream failure mid-request.

Reserved prefixes — rejected with 400 idempotency_key_reserved:

  • hpp:, recurring: — Cresora's own server-minted deterministic keys. A client key in these namespaces could collide with a platform-generated record.
  • rb:, inv-charge:, inv-installment: — reserved by the payment gateway for its internally-minted keys.

Replay semantics:

  • Same key + same request body → Cresora returns the cached response from the original call. Response includes header X-Idempotent-Replay: true so the client can distinguish replays from fresh executions. Status code, body and side effects are identical to the original call.
  • Same key + different body → 422 idempotency_key_reused. Generate a new key and retry, or re-send the original body.
  • Key older than 24 hours → treated as a fresh key; no replay guarantee from beyond the window.

Retrying after an indeterminate failure. On 502 gateway_outcome_unknown the transaction is recorded as pending and the outcome is not yet known — retry with the SAME key (a fresh key risks a double charge) or poll the transaction. This is also what a gateway-side "an earlier request with this key is still in flight" response surfaces as.

Do NOT reuse keys across different partners. Scope is enforced per partner_id so the same key in partner A and partner B is independent.

Match^[A-Za-z0-9._:\-]+$
Length1 <= length <= 128

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X POST "https://example.com/contracts/497f6eca-6276-4993-bfeb-53cbbbba6f08/cancel" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{}'
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "partner_id": "6a3a39f6-861b-4a48-b868-5de838400e06",  "merchant_id": "500924a8-3f5e-4c00-beb8-2efcde988aea",  "state": "PENDING_ACTIVATION",  "payment_method_type": "CARD",  "amount": "string",  "currency": "USD",  "frequency": "DAILY",  "start_date": "2019-08-24",  "end_date": "2019-08-24",  "total_amount": "string",  "remaining_installments": 0,  "amount_paid": "string",  "last_successful_charge_date": "2019-08-24",  "next_charge_date": "2019-08-24",  "retry_count": 0,  "max_retries": 0,  "created_at": "2019-08-24T14:15:22Z",  "custom_fields": [    {      "name": "patientId",      "value": "PT48213"    }  ],  "level2_data": {    "po_number": "string",    "merchant_zip": "string"  },  "level3_data": {    "ship_from_zip": "string",    "destination_zip": "string",    "destination_country_code": "string",    "invoice_number": "string",    "order_number": "string",    "duty_amount": "string",    "freight_amount": "string",    "discount_amount": "string",    "line_items": [      {        "product_code": "string",        "commodity_code": "string",        "description": "string",        "upc": "string",        "invoice_number": "string",        "tax_type": "string",        "quantity": "string",        "unit_of_measure": "string",        "unit_price": "string",        "discount_amount": "string",        "total_amount": "string",        "tax_amount": "string",        "tax_rate": "string",        "extended_amount": "string",        "freight_amount": "string",        "duty_amount": "string",        "tax_included": true      }    ]  }}
POST/contracts/{contractId}/retry

Authorization

BearerAuth
AuthorizationBearer <token>

Cresora API key, sent as an opaque bearer token in the Authorization header. Format:

csk_<prefix>_<random>
  • <prefix> — 8 URL-safe chars, shown in UI and logs for identification without revealing the full key (e.g. csk_Ab3kX9mQ…). Use ApiKey.prefix to match.
  • <random> — 24+ cryptographically random URL-safe chars.

Obtain via Partner Portal → Settings → API keys. Keys are only shown in full at creation/rotation time — Cresora does not retain the full value in retrievable form. Rotate any key that may have been exposed via logs, client code, or source control.

In: header

Path Parameters

contractId*string
Formatuuid

Header Parameters

Idempotency-Key*string

Client-generated unique key — a UUIDv4 is the recommended form. Cresora deduplicates within a 24-hour window scoped to the partner.

Format: 1–128 characters of letters, digits, . _ : -. Anything else is rejected with 400 validation_error. The character set is narrower than base64: padded base64 (+ / =) is NOT accepted, base64url is. The key is forwarded verbatim to the payment gateway on transaction creates, so it must satisfy the gateway's key contract too — rejecting locally gives you an actionable error instead of an opaque upstream failure mid-request.

Reserved prefixes — rejected with 400 idempotency_key_reserved:

  • hpp:, recurring: — Cresora's own server-minted deterministic keys. A client key in these namespaces could collide with a platform-generated record.
  • rb:, inv-charge:, inv-installment: — reserved by the payment gateway for its internally-minted keys.

Replay semantics:

  • Same key + same request body → Cresora returns the cached response from the original call. Response includes header X-Idempotent-Replay: true so the client can distinguish replays from fresh executions. Status code, body and side effects are identical to the original call.
  • Same key + different body → 422 idempotency_key_reused. Generate a new key and retry, or re-send the original body.
  • Key older than 24 hours → treated as a fresh key; no replay guarantee from beyond the window.

Retrying after an indeterminate failure. On 502 gateway_outcome_unknown the transaction is recorded as pending and the outcome is not yet known — retry with the SAME key (a fresh key risks a double charge) or poll the transaction. This is also what a gateway-side "an earlier request with this key is still in flight" response surfaces as.

Do NOT reuse keys across different partners. Scope is enforced per partner_id so the same key in partner A and partner B is independent.

Match^[A-Za-z0-9._:\-]+$
Length1 <= length <= 128

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X POST "https://example.com/contracts/497f6eca-6276-4993-bfeb-53cbbbba6f08/retry" \  -H "Idempotency-Key: string"
{  "outcome": "RUN_REQUESTED",  "contract_id": "9aafc1a8-e497-46c9-ba0b-bd5b03c353e4",  "contract_state": "PENDING_ACTIVATION"}