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
Section titled “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
Section titled “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
Section titled “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 |
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
Section titled “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. Neither
success_postnorsuccess_emailfires at creation, because both report a successful payment and none was taken; use the CONTRACT.START webhook to learn the agreement is set up. Later collections do not trigger them either. - 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
Section titled “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
Section titled “Related”Was this page helpful?
What went wrong?
Thanks for telling us.