Create Recurring Transaction
Schedule a fixed-amount pay or collect to run automatically on a defined interval.
Creating a recurring transaction sets up a schedule once; PCE then generates the underlying transaction automatically on each due date. You define two things in one request: the schedule (transactionDetail) and the pay or collect it runs (action.transaction). Use it for rent, subscriptions, retainers, or any repeating money movement. For the full field list, jump to the Request reference.
The transaction a schedule runs is the same one you'd send as a one-off Pay or Collect; only the transactionDetail schedule wrapper is new.
Common use cases
- Pay a landlord or vendor a fixed amount every month
- Collect a subscription or membership fee on a set interval
- Disburse a fixed retainer or allowance on a weekly or yearly cadence
Make your first recurring transaction
The fastest way to see it work: schedule a fixed monthly ACH payout to a saved vendor. Send a POST to /v1/transaction/recurring with the minimal fields below. The full set of options is in the Request reference.
POST /v1/transaction/recurring
{
"name": "Monthly rent to landlord",
"externalId": "recurring-rent-001",
"transactionDetail": {
"startDate": "08/01/2026",
"occurrence": "12",
"frequency": "MONTH",
"interval": "1",
"dayOfMonth": ["1"]
},
"action": [
{
"type": "TRANSACTION",
"transaction": {
"source": { "account": { "externalId": "passport-account-001" } },
"destination": { "externalAccount": { "id": "4021726" } },
"method": "ACH",
"amount": "1200.00",
"purpose": "Rent payment",
"processingDetail": { "processingMode": "FORWARD", "authType": "WRITTEN" }
}
}
]
}You'll get back 201 Created with a url header pointing at the new schedule (for example /v1/transaction/recurring/id/8176). The schedule starts in ACTIVE status. Store the returned id and your externalId to track it and for follow-up actions (update, pause, cancel).
UseexternalIdfor safe retriesFor Treasury, PCE treats the
externalIdin the request body as the idempotency key; there's no separate header. Send a uniqueexternalIdper schedule, and retrying with the same value creates it only once. Once set,externalIdcan't be changed.
Scenarios
Every schedule uses the same request shape. What changes per scenario is the frequency (and the day/month fields it requires) and whether the action.transaction is a pay or a collect. Each generated transaction then follows the Transaction lifecycle.
Before you begin (all scenarios)
- The source Passport Account is active and, for a pay, funded when each occurrence runs.
- The
destination(pay) orsource(collect) resolves: a saved External Account, Contact, or mailing address. - For a collect, you hold authorization to debit the payer, and it's linked where your program requires it.
Scenario 1: Pay a fixed amount every month
(frequency: MONTH, requires dayOfMonth)
Use this for rent, a retainer, or any monthly payout of the same amount. Set dayOfMonth to the day it should run.
You'll also need: the payee's saved External Account or Contact.
Request
POST /v1/transaction/recurring
{
"name": "Recurring payment of fixed amount to subcontractor",
"externalId": "recurring-month-001",
"transactionDetail": {
"occurrence": "10",
"frequency": "MONTH",
"interval": "1",
"dayOfMonth": ["1"]
},
"action": [
{
"type": "TRANSACTION",
"transaction": {
"source": { "account": { "id": "4056457" } },
"destination": { "externalAccount": { "id": "4021726" } },
"method": "ACH",
"amount": "100.00",
"purpose": "Rent payment",
"processingDetail": {
"processingMode": "FORWARD",
"companyName": "AMEX",
"companyDescription": "Rent",
"authType": "WRITTEN"
}
}
}
],
"metaData": { "Landlord": "Cathy Drew" },
"tags": ["Deposit"]
}Response
201 Created, with a url header of the form /v1/transaction/recurring/id/{id}. Retrieve the schedule to read the stored resource (status: ACTIVE, nextTransactionDate, and the transactionDetail you set).
Scenario 2: Run on specific days every week
(frequency: WEEK, requires dayOfWeek)
Use this for a weekly cadence, for example a payout every Saturday and Sunday. Set dayOfWeek to one or more days.
You'll also need: the same source/destination as scenario 1.
Request
POST /v1/transaction/recurring
{
"name": "Weekly payout to subcontractor",
"externalId": "recurring-week-001",
"transactionDetail": {
"endDate": "06/30/2027",
"occurrence": "15",
"frequency": "WEEK",
"interval": "1",
"dayOfWeek": ["SATURDAY", "SUNDAY"]
},
"action": [
{
"type": "TRANSACTION",
"transaction": {
"source": { "account": { "id": "4056457" } },
"destination": { "externalAccount": { "id": "4021726" } },
"method": "ACH",
"amount": "100.00",
"purpose": "Weekly payout",
"processingDetail": { "processingMode": "FORWARD", "authType": "WRITTEN" }
}
}
]
}Response
201 Created, with a url header pointing at the new schedule.
Scenario 3: Collect a fixed fee on a schedule
(pull from a payer, with authorization)
Use this to debit a payer you're authorized to collect from, for example a subscription or membership fee. The action.transaction is a collect: the source is the payer's External Account or Contact and the destination is your Passport Account.
You'll also need: authorization to debit the payer. Collect via WIRE is supported only for Business Customers whose external account holderType is CORPORATE.
Request
POST /v1/transaction/recurring
{
"name": "Monthly subscription fee",
"externalId": "recurring-collect-001",
"transactionDetail": {
"startDate": "08/01/2026",
"occurrence": "12",
"frequency": "MONTH",
"interval": "1",
"dayOfMonth": ["1"]
},
"action": [
{
"type": "TRANSACTION",
"transaction": {
"source": {
"contact": {
"id": "4019600",
"externalAccount": { "id": "4021726" }
}
},
"destination": { "account": { "id": "4056457" } },
"method": "ACH",
"amount": "49.00",
"purpose": "Subscription fee",
"processingDetail": { "processingMode": "FORWARD", "authType": "ONLINE" }
}
}
]
}Response
201 Created, with a url header pointing at the new schedule.
Scenario 4: Run once a year on a specific date
(frequency: YEAR, requires dayOfMonth + monthOfYear)
Use this for an annual payment, such as a yearly renewal or fee. Set both monthOfYear and dayOfMonth.
Request
POST /v1/transaction/recurring
{
"name": "Annual renewal fee",
"externalId": "recurring-year-001",
"transactionDetail": {
"endDate": "12/31/2030",
"occurrence": "5",
"frequency": "YEAR",
"interval": "1",
"monthOfYear": ["FEBRUARY"],
"dayOfMonth": ["29"]
},
"action": [
{
"type": "TRANSACTION",
"transaction": {
"source": { "account": { "id": "4056457" } },
"destination": { "externalAccount": { "id": "4021726" } },
"method": "ACH",
"amount": "100.00",
"purpose": "Renewal fee",
"processingDetail": { "processingMode": "FORWARD", "authType": "WRITTEN" }
}
}
]
}Response
201 Created, with a url header pointing at the new schedule.
Track the schedule and its transactions
Retrieve the schedule with a GET to /v1/transaction/recurring/id/{id} (or /externalId/{externalId}) to read its current status, statusReason, and nextTransactionDate. To see the transactions a schedule has generated, use Find & track recurring transactions. Each generated transaction is a normal Treasury transaction; track it and subscribe to its webhooks via the Transaction lifecycle.
Request reference
The complete set of fields for the create-recurring-transaction request.
Top-level parameters
| Parameter | Required | Description |
|---|---|---|
name | ✓ | Name of the recurring instruction. |
transactionDetail | ✓ | The schedule. See Schedule (transactionDetail). |
action | ✓ | Array with one element describing what runs. action[0].type is optional (TRANSACTION); action[0].transaction is required. See Action (action.transaction). |
externalId | Recommended | Your own reference ID, also the idempotency key. Unique across recurring transactions; can't be updated once set. Maximum 45 characters. |
linkedDocument | Optional | Array of authorization documents that authorize the fund movement. See Linked documents. |
comment | Optional | Free-text comment. Maximum 512 characters. |
metaData | Optional | Key/value pairs for your own additional information. |
tags | Optional | Labels assigned to the schedule. |
Schedule (transactionDetail)
transactionDetail)| Parameter | Required | Description |
|---|---|---|
frequency | ✓ | How the interval is counted: CALENDAR_DAY, BUSINESS_DAY, WEEK, MONTH, or YEAR. Can't be changed after creation. |
interval | ✓ | Gap between two occurrences, in units of frequency. |
startDate | Optional | When the schedule begins. Current or future date. |
endDate | Optional | When the schedule ends. Must be after startDate. |
occurrence | Optional | Total number of occurrences to run. |
dayOfWeek | Conditional | Day(s) of week. Required when frequency is WEEK. Not allowed for CALENDAR_DAY or BUSINESS_DAY. |
dayOfMonth | Conditional | Day(s) of month. Required when frequency is MONTH or YEAR. Not allowed for CALENDAR_DAY, BUSINESS_DAY, or WEEK. |
monthOfYear | Conditional | Month(s) of year. Required when frequency is YEAR. Not allowed for CALENDAR_DAY, BUSINESS_DAY, WEEK, or MONTH. |
Action (action.transaction)
action.transaction)action[0].transaction reuses the transaction model. Both source and destination are required and depend on whether you're paying or collecting and on the method.
| Parameter | Required | Description |
|---|---|---|
method | ✓ | Rail: ACH, WIRE, CHECK, BOOK, INTERNATIONAL_WIRE, or VIRTUAL_CARD. |
amount | ✓ | Fixed amount per occurrence, in USD. Must be greater than zero. |
purpose | ✓ | Purpose of the transaction. |
source | ✓ | Where funds come from. See the source/destination table below. |
destination | ✓ | Where funds go. See the source/destination table below. |
processingDetail | Conditional | Rail-specific processing options; see Processing detail. |
Source and destination by intent and method
| Intent | source | destination |
|---|---|---|
| Pay (ACH) | account.id | externalAccount.id |
| Pay (CHECK) | account.id | address.id |
| Pay (BOOK) | account.id | account.id |
| Pay (INTERNATIONAL_WIRE) | account.id | internationalExternalAccount.id (+ currency) |
| Collect (ACH) | externalAccount.id, or contact.id + contact.externalAccount.id | account.id |
| Collect (WIRE) | externalAccount.id (CORPORATE holderType only) | account.id |
Reference entities by id (assigned by Passport) or externalId (your reference).
Processing detail
processingDetail fields depend on the method, and certain fields may be required by your program's configuration. These mirror the one-off transaction fields.
| Method | Fields |
|---|---|
| ACH / WIRE | processingMode (FORWARD default, SAME_DAY), companyName, companyDescription, authType (WRITTEN, PHONE, ONLINE), addenda, memo, location.id, payor |
| CHECK | deliveryMode (STANDARD default, TWO_DAY, OVERNIGHT), remittanceInfo, memo, location.id |
| BOOK | purpose (max 255), memo (max 255) |
| INTERNATIONAL_WIRE | memo (max 140), location.id, wireReference |
| VIRTUAL_CARD | virtualCard (nickname, cardProgram.id, entity.id, location.id) |
For the full processing-detail semantics per method, see the matching one-off method page under Pay or Collect.
Linked documents
linkedDocument is an array. Each entry links an authorization document that authorizes the fund movement.
| Parameter | Required | Description |
|---|---|---|
linkedDocument[].purpose | ✓ | Purpose of the document. Value: AUTHORIZATION. |
linkedDocument[].document.name | ✓ | File name. |
linkedDocument[].document.type | ✓ | Document type. Value: CONTRACT. |
linkedDocument[].document.base64encodedContent | ✓ | Base64-encoded file. Allowed: pdf, jpg, bmp, txt, tiff, rtf, doc, docx, xls, csv, wav, jpeg, png, xlsx, efx. |
Validation
The prerequisites above are the validations, and PCE enforces them when you submit. If a check fails, the request returns an error and no schedule is created.
Submit-time checks:
- Required fields are present and correctly formatted, including the conditional day/month fields for the chosen
frequency. externalIdis unique across recurring transactions.endDateis afterstartDate.startDateis the current date or a future date.- The
sourceanddestinationresolve for the chosenmethodand intent.
For the codes returned when a check fails, see Recurring Transaction Error Codes.
Statuses
A new schedule starts in ACTIVE. The schedule statuses (ACTIVE, PAUSED, CANCELLED, COMPLETED) and their reasons are on Recurring transactions. Each transaction the schedule generates follows the shared Transaction lifecycle.
Go live
The shared pre-production checklist (production credentials, webhook subscription and signature validation, idempotency, and sandbox testing) is in Getting Started. Specific to creating a recurring transaction, also confirm:
- The chosen
methodis enabled for your program (INTERNATIONAL_WIRE and VIRTUAL_CARD may require enablement). - For collects, authorization is held and linked as
linkedDocumentwhere required. - The day/month fields match the
frequencyso occurrences fall on the dates you expect.
Best practices
General practices (unique externalId, subscribe to webhooks, test in sandbox) are in Getting Started. Specific to recurring transactions:
| Practice | Description |
|---|---|
Set an endDate or occurrence | Bound every schedule so it completes on its own instead of running indefinitely. |
| Confirm the schedule with a GET | The create response has no body; retrieve the schedule to verify nextTransactionDate and stored transactionDetail. |
| Fund the source before each run | A schedule doesn't reserve funds; ensure the source Passport Account is funded ahead of each occurrence. |
| Track generated transactions by webhook | Each occurrence emits its method's usual transaction webhooks; don't poll the schedule for per-transaction status. |
Next steps
See also
- Recurring transactions: the schedule model and status overview
- Pay via ACH and Collect via ACH: the one-off equivalents of what a schedule runs
- Bank accounts & contacts: save the payees and accounts a schedule references
- Recurring Transaction Error Codes: resolve a rejected schedule request
Updated about 4 hours ago