Submit scheduled payments
Submit scheduled payments through your collection module when you use an API payment provider.
Choose the submission path
How a due payment reaches a provider depends on the provider type.
| API payment provider | File-based debit provider | |
|---|---|---|
| Config | batching.enabled: true + submitPaymentsFunction | batching.enabled: false |
| Who submits | Your module's hook | The platform batcher |
| Batching | You decide, inside your hook | The platform handles it |
| Code you write | A submitPayments hook | None |
For file-based debit providers, you write no submission code. The platform batcher submits those payments for you.
The submitPayments hook
submitPayments hookFor API providers, the platform calls your submission hook with the whole batch of your module's due payments in one call. You submit them to your provider and return a result for each one.
submitPayments is an example name. The platform calls whatever function you name in submitPaymentsFunction, so your exported function and that config value must match.
export const submitPayments = async ({ payments, organization, environment }) => {
const results = [];
for (const p of payments) {
try {
// `provider` is your payment provider's client.
const charge = await provider.charge({
amount: p.amount,
currency: p.currency,
idempotencyKey: p.payment_id,
});
results.push({
payment_id: p.payment_id,
status: 'submitted',
provider_reference: charge.id,
});
} catch (error) {
results.push({
payment_id: p.payment_id,
status: 'failed',
failure_reason: error instanceof Error ? error.message : 'provider_submission_failed',
});
}
}
return { results };
};This example submits one payment at a time. You can submit in parallel, as shown in the scheduled payments example, as long as you stay within your provider's rate limits.
Parameters
The hook receives { payments, organization, environment }. Each entry in payments has these fields:
| Field | Description |
|---|---|
payment_id | The payment's id. Use it as the provider idempotency key. |
policy_id | The policy the payment belongs to. |
amount | The payment's resolved amount, in the smallest currency unit. Corresponds to the schedule's expected_amount. Note the field is amount here, not expected_amount. |
currency | The ISO currency code. |
premium_type | The kind of payment, for example recurring. See the schedule action's premium_type for the full list of values. |
billing_period_start | The first day of the period this payment covers. |
billing_period_end | The last day of the period this payment covers. |
policyholder | The policyholder object. |
policy | The policy object. |
organization is the organization the payments belong to. environment is sandbox or production.
Return shape
Return { results: [...] }, with one entry per payment.
statusreports submission, not settlement. Returnsubmittedwhen your provider accepts the request, andfailedwhen the submission itself fails. A payment you report assubmittedstays in thesubmittedstate. The platform does not yet resolve it to successful or failed automatically; settlement confirmation is not available for API providers.
| Field | Required | Description |
|---|---|---|
payment_id | Yes | The payment_id from the matching input payment. |
status | Yes | Either "submitted" or "failed". |
provider_reference | When submitted | The provider's id for the payment, for example a charge or transaction id. Stored on the payment for your reconciliation. |
failure_reason | When failed | A short reason the submission failed. |
The platform validates your return value before it applies any results.
A mixed batch can return both submitted and failed payments:
{
"results": [
{
"payment_id": "pay_123",
"status": "submitted",
"provider_reference": "ch_456"
},
{
"payment_id": "pay_789",
"status": "failed",
"failure_reason": "card_declined"
}
]
}Idempotency
Always use
payment_idas the idempotency key with your provider, as shown above. The platform may call your hook again if a batch is redelivered, and without an idempotency key a retried call charges the policyholder twice.
Next step
Review scheduled payment events and troubleshooting to monitor submissions and diagnose common issues.