Payment Types
Shuttle supports four payment models. All of them create a contract under the hood — the differences are in how and when charges are generated and when payment is attempted. Any model other than single pay-now relies on the scheduler to drive future-dated activity.
| Model | How charges are created | When payment is attempted | Amounts | Typical use case |
|---|---|---|---|---|
| Single pay-now | One charge at creation | Immediately (synchronous) | Fixed | One-off purchase |
| Scheduled one-time | One charge at creation | Asynchronously on the scheduled date | Fixed | A single payment agreed now, taken on a specific future date (e.g., end-of-month billing) |
| Recurring (frequency-based) | One charge per billing cycle, generated as each cycle becomes due | Asynchronously shortly after each charge is created | Same each cycle | Subscriptions, memberships |
| Scheduled charges | All charges created upfront from an explicit array | Sync for any charge due now/in the past; async for future-dated charges | Vary per charge | Irregular instalment plans, staged billing |
Single Pay-Now
A one-off payment taken immediately.
Required: currency, amount, payment_method, account
Omit: frequency (or set to ONEOFF), scheduled_date, charges
{
"payment": {
"currency": "GBP",
"amount": "49.99",
"account": { "crm_key": "CUS-001" },
"payment_method": { "card_number": "4111...", "card_cvc": "123", "card_expiry": "2030-12" }
}
}Scheduled One-Time Payment
A single payment deferred to a future date.
Key fields: scheduled_date (ISO timestamp, up to 365 days out) or scheduled_days (integer, up to 31).
The charge is created at the moment of contract creation, with its due date set to scheduled_date. The scheduler picks it up and attempts payment when that time arrives (typically within a few minutes of the scheduled time). A failed attempt enters the normal retry flow.
{
"payment": {
"currency": "GBP",
"amount": "200.00",
"scheduled_date": "2026-06-01T09:00:00Z",
"account": { "crm_key": "CUS-001" },
"payment_method": "pm_11842_10000"
}
}Recurring (Frequency-Based) Payment
A series of charges generated on a regular cadence. Charges are created one at a time — when a charge becomes due, it is created, the frequency is applied to determine the next next_charge date, and payment is attempted asynchronously against the newly-created charge (typically within a minute of the charge being created). Failed payments are retried automatically — see Scheduler for the retry schedules.
Key fields: frequency, occurrences (blank = forever), start_date or start_days.
frequency enum: ONEOFF, WEEKLY, FORTNIGHTLY, BIMONTHLY, MONTHLY, QUARTERLY, BIANNUALLY, ANNUALLY.
Frequency Specifics
- BIMONTHLY — charges fall on the 1st and the 15th of every month.
- MONTHLY, QUARTERLY, BIANNUALLY, ANNUALLY — calculated from the previous charge date. When the previous charge date does not exist in the target month, the charge falls on the last day of that month and subsequent charges are calculated from that adjusted date rather than the original anchor. For example, a monthly contract whose first charge is on 31 January produces the next charge on 28 February (or 29 Feb in a leap year), then 28 March, 28 April, and so on — the anchor drifts to 28th and stays there.
{
"payment": {
"currency": "GBP",
"amount": "19.99",
"frequency": "MONTHLY",
"occurrences": 12,
"start_date": "2026-05-01T00:00:00Z",
"account": { "crm_key": "CUS-001" },
"payment_method": "pm_11842_10000"
}
}Scheduled Charges
An explicit list of charges, each with its own amount and due date. All charges are created upfront at contract creation. Use this when amounts or dates vary between charges — e.g., irregular instalment plans, staged billing for services, or deposits followed by balance payments.
Key field: charges[]. Each entry accepts:
| Field | Required | Description |
|---|---|---|
alt_key | No | Your reference for the charge (e.g., instalment number or invoice line ID) |
amount | Yes | The charge amount, as a string |
due | Yes | ISO 8601 timestamp or the literal string "now". A timestamp more than 24 hours in the past is rejected |
When each charge is taken:
due value | Timing | Effect of a decline |
|---|---|---|
"now" or a past timestamp (within 24h) | Taken synchronously during contract creation | Blocks contract creation — no contract is created |
| Future timestamp | Taken asynchronously by the scheduler on the due date | Contract is created regardless; the charge enters the normal retry flow |
To have the first charge run asynchronously, set its due to a future timestamp (even a few minutes ahead).
Rules:
- Cannot be combined with
frequency(must be omitted orONEOFF) - Not supported with
action: AUTH - The top-level
amountis optional. If provided, it must equal the sum ofcharges[].amount
{
"payment": {
"currency": "GBP",
"account": { "crm_key": "CUS-001" },
"payment_method": "pm_11842_10000",
"charges": [
{ "alt_key": "DEPOSIT", "amount": "100.00", "due": "now" },
{ "alt_key": "BALANCE_1", "amount": "50.00", "due": "2026-06-01T09:00:00Z" },
{ "alt_key": "BALANCE_2", "amount": "50.00", "due": "2026-07-01T09:00:00Z" }
]
}
}Retrieve the resulting charges via List contract charges. Each entry on a scheduled-charges contract is a normal charge object and can be listed, retrieved, or modified via the standard Charges API.
Choosing Between Recurring and Scheduled Charges
| If… | Use |
|---|---|
| Amount and cadence are uniform (e.g., £20 every month) | Recurring |
| You want "forever until cancelled" billing | Recurring |
| Amounts or dates vary between charges | Scheduled charges |
| You have a finite, pre-known schedule (e.g., deposit + 3 instalments on specific dates) | Scheduled charges |
You need per-charge references (alt_key) for reconciliation | Scheduled charges |
Converting a Recurring Contract to Scheduled Charges
If you need to change a specific future instalment on a recurring contract — a different amount, a different date, an extra one-off charge — you can convert the contract to scheduled charges mid-stream. This switches the contract from frequency-based generation to an explicit list of remaining charges that you can then manage individually.
Prerequisite: the recurring contract must have a finite occurrences value. Scheduled-charges contracts are finite by definition, so a "forever until cancelled" recurring contract cannot be converted.
Process:
- Fetch the existing charges on the contract via
GET /contracts/{id}/charges. - Send a
PUT /contracts/{id}with acharges[]array that contains every existing charge — even ones that have already been paid or written off — plus any modifications, deletions, or additions you want.
Rule for past charges. Any charge that has already been processed (COMPLETED, WRITTENOFF, or PENDING) must appear in the array with just its id and no other fields. This tells Shuttle "leave this charge as-is" and ensures historical activity is preserved. Omitting a charge is interpreted as a request to remove it; past charges will refuse the deletion and the request will fail.
Rule for future charges. You can:
- Leave unchanged:
{ "id": "cg_..." } - Modify:
{ "id": "cg_...", "amount": "25.00" }(only the fields you want to change) - Delete:
{ "id": "cg_...", "deleted": true } - Add a new one:
{ "alt_key": "BONUS", "amount": "15.00", "due": "2026-09-15T09:00:00Z" }
Example — modify a future instalment, delete another, add a new one:
PUT /contracts/co_11842_10000
{
"contract": {
"charges": [
{ "id": "cg_11842_10001" },
{ "id": "cg_11842_10002" },
{ "id": "cg_11842_10003", "amount": "25.00" },
{ "id": "cg_11842_10004", "deleted": true },
{ "alt_key": "BONUS", "amount": "15.00", "due": "2026-09-15T09:00:00Z" }
]
}
}In this example, charges 10001 and 10002 are preserved unchanged (already paid), 10003 is updated to a new amount, 10004 is removed, and a new charge is appended at the end. After the update the contract behaves as a scheduled-charges contract — it will no longer generate further charges by frequency, and you manage it by amending charges[] rather than frequency / occurrences.
The conversion is one-way: once converted, you can't switch back to frequency-based generation on the same contract.
Related
- Scheduler — how deferred charges are processed, retry schedules, and the
next_charge/next_paymentfields
Updated about 21 hours ago