Set up a recurring or scheduled agreement
Creates an agreement whose collections are driven by a schedule rather than a single payment now: a recurring agreement (a frequency, optionally a fixed number of payments and a delayed start), a one-off payment due on a future date, or a schedule of named charges. It is the same checkout submission as Take a one-off payment; the payload decides which shape of contract Shuttle builds. A recurring agreement with no start date and a charge schedule with a charge due "now" still take their first payment at checkout; a delayed start, a scheduled date or an all-future schedule create the contract and store the payment method without charging, and the scheduler collects when the dates fall due.
Where you can do this
- The hosted checkout: Payment form (Process Payment (recurring, scheduled date or charge schedule))
- API: Create a checkout (
POST /checkouts) — frequency other than ONEOFF, or scheduled_date / scheduled_days, or a charges[] schedule; prepares the checkout the form then submits - The hosted checkout: the hosted checkout submits a frequency other than ONEOFF, or a scheduled date, or the request carried a charges[] schedule
- The hosted checkout: completing the same agreement after a 3DS or hosted redirect
- API: Create a payment (
POST /payments) — no contract named and the body carries frequency other than ONEOFF, start_date / start_days, scheduled_date / scheduled_days, or charges[]
Before you start
- A channel with an initiative whose amount-due configuration lists the requested frequency as active (the hosted checkout only offers the initiative's frequencies); a charge schedule or scheduled date needs no frequency.
- A payment method the gateway can store: recurring, scheduled and charge-schedule agreements always store the method, so the gateway must offer save-card or create-token for the card type (the hosted checkout forces the save-card option on and refuses to submit a card type the gateway cannot save).
- From the hosted checkout: a checkout request for the channel, prepared by
POST /c/api/checkoutor the legacy per-session request, holding the fixed values (nonce, amount, currency, frequency, occurrences, dates, action, account, charges).
Inputs
Names are as POST /c/api/checkout and POST /c/api/payments carry them.
| Input | Required | Meaning and constraints |
|---|---|---|
| frequency | conditional | Recurring interval; anything other than ONEOFF makes the agreement recurring. Must be one the initiative lists. Cannot be combined with charges[] or scheduled_date |
| occurrences | no | Fixed number of collections; absent means indefinite. Read only alongside a recurring frequency, because Shuttle files it under that frequency's own values, so an occurrences sent with a ONEOFF, a scheduled date or a charge schedule is dropped (a schedule's number of payments is its number of charges). the hosted checkout accepts 1 to 99 (below 1000 when the request fixes it); the server accepts any integer |
| start_date | no | Delays the first collection to that date; only meaningful with a recurring frequency |
| start_days | no | Delays the first collection by that many days; an alternative to start_date |
| scheduled_date | no | For a ONEOFF with an amount, the future date the single payment falls due |
| scheduled_days | no | The same, expressed as a number of days ahead |
| charges[] | conditional | Named instalments: amount above zero, due (an ISO date or the literal "now"), optional alt_key and legal_entities[] (id, amount). Amounts must sum to amount; each charge's legal-entity split must sum to the charge. Cannot be combined with frequency, occurrences, start or scheduled dates, or an authorise action |
| amount | conditional | Present makes a known-amount recurring agreement; absent with a frequency makes a variable-amount one. A scheduled date needs an amount. Scaled to four decimals, must not be zero |
| currency | conditional | Required whenever amount is sent; ISO 4217 code |
| keep_active_until | no | Date until which an ongoing contract is held open after its last collection instead of completing; a malformed date is ignored on this path |
| nonce | yes | Idempotency key; a contract is bound to it for 24 hours (two years for payment-link nonces) |
| alt_key | no | Your reference for the contract |
| metadata | no | Custom key-value pairs stored on the contract |
| event_date | no | The date the contract relates to |
| description | no | Goods or service description shown on receipts |
| payment_method, save_card, action, account | see Take a one-off payment | Payment method values, account resolution and the payment action are shared with the one-off path |
Rules
Checked by the API means Shuttle refuses the request however it is sent; a screen name means only that screen refuses it, and a direct API call would be accepted.
| Rule | Checked by | What you see |
|---|---|---|
| The frequency must be one the initiative's amount-due configuration lists as active and, unless indefinite, the number of payments must be present; otherwise the agreement never reaches its submission step | The API | BOLT-1101 AGREEMENT_CREATION_FAILED, with the amount-step validation errors; the hosted checkout only offers the initiative's frequencies and requires 1 to 99 occurrences when finite |
| If the initiative's amount-due configuration has recurring switched off, a frequency is ignored and a one-off contract is built | The API | silent |
| charges[] and a recurring frequency are mutually exclusive | The API, mirrored by the hosted checkout | hosted checkout: INVALID_REQUEST "Cannot specify both charges and frequency"; POST /c/api/payments: VALIDATION_ERROR "Cannot specify both charges[] and frequency"; Shuttle: BOLT-7004 CONTRACT_CREATION_FAILED "validation.error.charges.mutually.exclusive"; the form: "frequency cannot be used with charges" |
| A charge schedule cannot carry start_date, start_days, scheduled_date, scheduled_days or occurrences | The hosted checkout only | the form refuses with "... cannot be used with charges"; not enforced server-side (Shuttle takes the schedule and ignores the other fields) |
| Each charge needs an amount above zero and a due date; the charges must sum to the contract amount; each charge's legal-entity split must sum to the charge; an empty schedule is refused | The API, mirrored by the hosted checkout | Shuttle: INVALID (BOLT-7004) "validation.error.charges.empty" / "amount.required" / "amount.must.be.positive" / "whenDue.required" / "amount.mismatch" / "legal.entity.mismatch" / "legal.entity.amount.invalid"; POST /c/api/payments: VALIDATION_ERROR "Charge at index n 'amount' required..." / "Sum of charges (...) must equal contract amount (...)" (within 0.01); the form: "Invalid charge amount..." / "Amount parameter (...) does not match the charges total (...)" |
| A charge schedule is not supported when tax rules are configured on the designation | The API | INVALID (BOLT-7086) "Scheduled charges are not supported when tax rules are configured on the designation" |
| A scheduled one-off cannot be an authorisation | The API, mirrored by the hosted checkout | Shuttle: INVALID "Invalid value for field action."; POST /c/api/payments and the form: "Scheduled payments do not support auth / capture" |
| A scheduled date cannot be combined with a recurring frequency | The API (POST /c/api/payments) and the hosted checkout | VALIDATION_ERROR / "Scheduled payments do not support frequency"; Shuttle silently drops the scheduled date when the frequency is not ONEOFF |
| A scheduled date must be at least one minute in the future | The API (POST /c/api/payments) and the hosted checkout | VALIDATION_ERROR / "Scheduled payments must be scheduled for at least 1 minute in the future"; not enforced by Shuttle or the hosted checkout, so a past date on the form path collects as soon as the scheduler fires |
| A start date cannot be more than 48 hours in the past | The API | VALIDATION_ERROR "start_date cannot be more than 48 hours in the past"; not enforced by Shuttle or the hosted checkout (the form only offers tomorrow onwards for four years); a past start date collects immediately after activation |
| start_date requires a recurring frequency | The hosted checkout only | "start_date requires a recurring frequency..."; Shuttle ignores a start date on a ONEOFF |
| save_card cannot be false for a scheduled date or a schedule with future charges; the method is always stored for recurring, scheduled and charge-schedule agreements | The API, mirrored by the hosted checkout | Shuttle forces storage regardless of save_card; the form refuses "Scheduled payments do not support save_card: false" / "saveCard cannot be false with future-dated charges..." |
| The payment method must be storable by the gateway when nothing is collected at checkout; a gateway that reports a tokenisation failure rejects the agreement, one that needs a redirect parks the contract in setup until the redirect completes | The API | BOLT-1206 TOKENISATION_FAILED with the gateway message; otherwise the response carries the tokenisation redirect and the contract stays in SETUP (see Change the payment method on a contract for the attach-on-completion rule) |
A payment method (or gateway data, or force_payment_method) is required on POST /c/api/payments | The API | VALIDATION_ERROR "Missing payment method" |
| The amount is scaled to four decimals and must not be zero | The API | BOLT-1168 INVALID_AMOUNT |
| For a recurring agreement, any contract created on the same nonce in the last 24 hours that has left SETUP counts as a duplicate, even with no transaction; for every shape a contract on the nonce with a successful, pending, unattributed or unresolved transaction is a duplicate | The API, mirrored by the hosted checkout | Shuttle: status DUPLICATE, BOLT-1191 with the existing contract (and transaction) identifiers; POST /c/api/checkout: DUPLICATE or PROCESSING "duplicate nonce"; the form shows "This payment has already been processed." and offers Continue to the existing receipt |
| Only one submission per nonce runs at a time | The API | BOLT-7059, shown by the hosted checkout as "It appears this payment is already in progress." |
| Account, channel and initiative resolution, fraud blocking and gateway selection are shared with the one-off path: unknown or foreign account, registration or anonymous checkout disabled, blocked session, initiative key and code both given, no initiative or valid domicile for the channel | The API | see Take a one-off payment; INVALID_ACCOUNT / REGISTRATION_DISABLED / ANONYMOUS_DISABLED / BAD_PERMISSIONS_EXCEPTION, BOLT-1188 FRAUD_DETECTED, BOLT-1165, BOLT-7081, BOLT-1164 |
| The completion call after a redirect re-runs submission for the same contract; a contract that has already left setup returns its existing transaction rather than a second one | The API | as submission |
What happens
- A contract is created in SETUP, shaped by the payload: recurring (frequency, optional occurrences and start_date), a single payment due on scheduled_date, or a charge schedule (charges[]). The payment method is always stored on it, and CHARGE.CREATED is raised for each charge created up front.
- Anything due now (a recurring agreement with no start date, or a charge due "now") is collected at checkout. A successful payment activates the contract (ACTIVE, or PENDING while a delayed-settlement method clears), raises CONTRACT.START and PAYMENT.SUCCESS, and emails the addresses the checkout request named in
success_email. A decline leaves the contract in SETUP so the same nonce can be retried. - Nothing due now (a delayed start, a scheduled date, all charges in the future) takes no payment: the stored method activates the contract (ACTIVE) and raises CONTRACT.START; no
success_emailis sent at creation. - No receipt is emailed or texted to the payer automatically. The hosted checkout shows a receipt page at the end (unless
skip_receiptis set), and the checkout'ssuccess_emailemails the addresses the checkout request names, but sending the payer a receipt of their own is the integrator's to do. - The response carries the contract id and, when a payment was taken, the transaction id; or a 3DS, hosted or tokenisation redirect that must be completed through the submit call before the contract leaves SETUP.
- Later, each collection is taken on its due date: recurring at each frequency interval from the start or first charge (CHARGE.CREATED and CONTRACT.UPDATE, then PAYMENT.SUCCESS or PAYMENT.FAILED); a scheduled payment or charge schedule on each charge's due date. The contract completes (COMPLETED, CONTRACT.COMPLETE) once the fixed number of payments, or every charge, is settled; keep_active_until holds it open until that date.
- A failed collection moves the contract to FAILING and is retried on the initiative's retry schedule; when the retries are spent the arrears are settled through a manual payment or by rescheduling.
Who can do this
- Roles: none; the entry points are customer-facing and authorised by the checkout or account session, not by an operator.
- Recurring is offered only when the initiative has frequencies configured and its amount-due configuration supports recurring; the form hides the recurring section when the request fixes the frequency to ONEOFF. A charge schedule or scheduled date can only be set on the request, not chosen on the form.
Related
Updated 30 minutes ago