Subscriptions#
Create and manage recurring billing schedules ("recurring payments") with automatic payment processing.
Overview#
The Recurring API enables you to:
- 🔁 Create recurring schedules - Weekly, bi-weekly, semi-monthly, monthly, quarterly, annually, or a one-time scheduled charge
- 💳 Automatic billing - Due payments are charged by an hourly scheduler
- ⏸️ Pause & resume - Temporarily stop a schedule
- ⏭️ Skip payments - Move the next charge forward by one period
- 🔄 Auto-retry failed payments - Declined charges are retried automatically
- 📧 Customer notifications - Setup links, success, failure and dunning emails
- 📊 Schedule & history - Per-payment schedule rows and a full activity log
Authentication#
All /api/v1/recurring endpoints are admin endpoints:
Authorization: Bearer YOUR_JWT
X-Tenant-ID: your-tenant-idAn API key (x-api-key) is also accepted on these routes; the merchant is then taken from the key.
- The merchant is taken from the JWT (or API key). Tenant-level users without a merchant in their token must pass
merchantId(in the body for writes, in the query string for reads). - The
recurringfeature must be enabled for the tenant/merchant; otherwise the gateway answers404 NOT_FOUND. - Errors use
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "..." } }(400 VALIDATION_ERROR,404 NOT_FOUND,401 UNAUTHORIZED,500 INTERNAL_ERROR).
Note: IDs are UUIDs. Field names are camelCase and mirror the stored record (
recurringAmount,period,recurringDate1, ...).
Create a Subscription#
Endpoint#
Request#
curl -X POST https://uat.auxcore.net/api/v1/recurring \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"recurringAmount": 29.99,
"period": "Monthly",
"recurringDate1": "2026-11-01",
"nextPaymentDate": "2026-11-01",
"maximumOccurrence": "12",
"suggestedMode": "CARD",
"customerId": "3f6c2a1e-8b4d-4c7a-9e21-5d0b7f1a2c34",
"recurringUserName": "John Doe",
"customerEmail": "john@example.com",
"description": "Premium membership",
"requestOrigin": "recurring",
"sendNotifications": true,
"children": [
{
"pciToken": "pci_tok_9f8e7d6c5b4a",
"gatewayType": "TsysSierra",
"isDefault": true
}
],
"metadata": { "plan": "premium" }
}'Parameters#
| Field | Type | Description | Required |
|---|---|---|---|
recurringAmount |
decimal | Amount charged each cycle | Yes |
period |
string | Weekly, BiWeekly, SemiMonthly, Monthly, Quarterly, Annually, Custom (case-sensitive) |
Yes |
merchantId |
uuid | Only needed when the token/key carries no merchant | Conditional |
recurringDate1 |
date | First charge date (YYYY-MM-DD). Cannot be in the past. Defaults to today |
No |
recurringDate2 |
date | End date. Cannot be in the past | No |
recurringDate3, recurringDate4 |
date | Extra dates for custom schedules | No |
nextPaymentDate |
date | Date of the first automatic charge. See note below | No |
maximumOccurrence |
string | Number of payments (1-999) or NoExpire |
No |
suggestedMode |
string | CARD or ACH — selects how the scheduler charges |
Yes, for automatic charging |
children |
array | Payment methods (see below). Without one, the schedule cannot be charged | No |
customerId |
uuid | Customer record | No |
recurringUserName |
string | Customer display name | No |
customerEmail |
string | Customer email, used for notifications | No |
description |
string | Description (max 255) | No |
branchId |
uuid | Location (branch) the schedule belongs to | No |
requestOrigin |
string | recurring, scheduled, virtual_terminal, invoice |
No |
status |
string | Initial status, e.g. pending while waiting for customer authorization. Defaults to active (scheduled when requestOrigin is scheduled) |
No |
planType |
string | Label, e.g. Subscription, Payment Plan, Scheduled Payment |
No |
gracePeriodDays |
integer | Stored for display | No |
lateFeeType / lateFeeAmount |
string / decimal | none, fixed, percent — stored only, not applied to recurring charges |
No |
planFeeType / planFeeAmount |
string / decimal | none, fixed, percent — stored only |
No |
sendNotifications |
boolean | Email the customer on creation (needs customerEmail) |
No |
templateInvoiceId |
uuid | Template invoice for recurring invoices (requestOrigin: invoice) |
No |
metadata |
object | Custom key-value pairs | No |
children[] (payment method):
| Field | Type | Description |
|---|---|---|
pciToken |
string | PCI vault card token; promoted to a long-lived card-on-file token before the schedule is saved |
gatewayToken / gatewayCustomerId |
string | Existing gateway card token / customer vault ID |
gatewayType |
string | Gateway the token belongs to |
accountToken / routingToken / accountType |
string | ACH account (checking or savings) or a saved bank-account vault token in accountToken |
isDefault |
boolean | The scheduler charges the default method |
Note: If
nextPaymentDateis omitted, the first automatic charge is scheduled one period afterrecurringDate1(the portal takes the first payment up front). SendnextPaymentDateequal torecurringDate1to have the scheduler take the first charge on the start date. One-time schedules (requestOrigin: "scheduled"ormaximumOccurrence: "1") are always charged onrecurringDate1.
Note: When
sendNotificationsistrueand no payment method is supplied, AuxCORE emails the customer a setup/consent link (valid 7 days) so they can authorize a card; sendstatus: "pending"in that case.
Note: An identical request (same merchant,
recurringUserName,recurringAmountandperiod) within 5 seconds returns the existing schedule instead of creating a duplicate.
Response#
201 Created
{
"success": true,
"data": {
"id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61",
"tenantId": "your-tenant-id",
"merchantId": "c1a7e5d2-3b4f-4e6a-9c8d-7f0b1a2e3d45",
"customerId": "3f6c2a1e-8b4d-4c7a-9e21-5d0b7f1a2c34",
"recurringAmount": 29.99,
"period": "Monthly",
"recurringDate1": "2026-11-01",
"maximumOccurrence": "12",
"suggestedMode": "CARD",
"status": "active",
"isRecurring": true,
"nextPaymentDate": "2026-11-01",
"successCount": 0,
"failCount": 0,
"requestOrigin": "recurring",
"createdAt": "2026-10-01T16:00:00.000Z"
}
}Subscription Periods#
| Period | Cadence |
|---|---|
Weekly |
Every 7 days |
BiWeekly |
Every 14 days |
SemiMonthly |
Every 15 days |
Monthly |
Same day each month |
Quarterly |
Every 3 months |
Annually |
Same day each year |
Custom |
Used for one-time scheduled payments; if it recurs, the next charge is the same day next month |
Create via Public API#
Server-to-server integrations can create a schedule with an API key. The merchant is always taken from the key; any merchantId in the body is overwritten.
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/public/recurring \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recurringAmount": 29.99,
"period": "Monthly",
"recurringDate1": "2026-11-01",
"nextPaymentDate": "2026-11-01",
"suggestedMode": "CARD",
"recurringUserName": "John Doe",
"customerEmail": "john@example.com",
"children": [{ "pciToken": "pci_tok_9f8e7d6c5b4a", "isDefault": true }]
}'Body and response are the same as Create a Subscription above. Authentication errors from the gateway use the public format ({ "success": false, "error": "Invalid API key", "message": "..." }).
Get Subscription#
Endpoint#
curl https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Returns the full schedule record, including children (payment methods), counters (successCount, failCount, failedPaymentCount, retryCount, totalCollectedAmount), dates (nextPaymentDate, lastPaymentDate, lastFailedPaymentDate, nextRetryAt) and pause info (pausedAt, pausedReason). 404 NOT_FOUND if it does not exist.
List Subscriptions#
Endpoint#
Query Parameters#
| Parameter | Type | Description |
|---|---|---|
page |
integer | Page number (default 1) |
perPage |
integer | Items per page (default 10; limit is accepted as an alias) |
sort |
string | asc or desc (default desc) |
sortColumn |
string | createdAt, recurringAmount, nextPaymentDate, period (default createdAt) |
q |
string | Search by customer name |
customerId |
uuid | Filter by customer |
period |
string | Filter by period (e.g. Monthly) |
isRecurring |
boolean | true / false |
requestOrigin |
string | Filter by one origin |
requestOrigins |
string | Comma-separated list of origins |
branchId |
uuid | Filter by location |
merchantId |
uuid | Required only when the token carries no merchant |
curl "https://uat.auxcore.net/api/v1/recurring?period=Monthly&perPage=50" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{
"success": true,
"data": {
"data": [ { "id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61", "recurringAmount": 29.99, "period": "Monthly", "status": "active" } ],
"total": 1,
"page": 1,
"perPage": 50,
"totalPages": 1
}
}There is no status filter; filter on status client-side. Deleted schedules are excluded.
Update Subscription#
Endpoint#
curl -X PUT https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"recurringAmount": 39.99,
"description": "Premium plus"
}'Updatable Fields: recurringAmount, period, recurringDate1-recurringDate4, maximumOccurrence, suggestedMode, isRecurring, customerId, recurringUserName, customerEmail, status, children, description, gracePeriodDays, lateFeeType, lateFeeAmount, planType, planFeeType, planFeeAmount, setupLinkId.
The same date and maximumOccurrence validation as create applies. Changing only the amount updates the unpaid schedule rows in place; changing the period rebuilds them. Paid rows are kept.
Pause Subscription#
Temporarily pause a subscription without cancelling it. Cancelled or expired schedules cannot be paused (400).
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/pause \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{ "reason": "Customer travelling" }'Response:
{
"success": true,
"data": {
"id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61",
"status": "paused",
"isRecurring": false,
"pausedAt": "2026-10-01T16:30:00.000Z",
"pausedReason": "Customer travelling"
},
"message": "Recurring subscription paused successfully"
}Resume Subscription#
Resume a paused, pending or cancelled schedule. The status returns to active and nextPaymentDate is recalculated as one period from today. Any other status returns 400.
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/resume \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Skip Next Payment#
Move the next charge forward by one period. Only active schedules can skip (400 otherwise). No request body.
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/skip-next \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{
"success": true,
"data": {
"id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61",
"status": "active",
"nextPaymentDate": "2026-12-01"
},
"message": "Next payment skipped successfully"
}Cancel Subscription#
Cancel immediately. Future schedule rows are marked cancelled; the record stays visible. Cancelling an already cancelled schedule returns 400. There is no "cancel at period end" option.
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/cancel \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{ "reason": "Customer request" }'Response:
{
"success": true,
"data": {
"id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61",
"status": "cancelled",
"isRecurring": false,
"pausedReason": "Customer request"
},
"message": "Recurring subscription cancelled successfully"
}Delete Subscription#
Soft-deletes the schedule (hidden from lists, never charged again).
Endpoint#
curl -X DELETE https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{ "success": true, "data": { "message": "Recurring payment deleted successfully" } }Subscription Statuses#
| Status | Description |
|---|---|
active |
Billing on schedule |
scheduled |
One-time scheduled payment waiting for its date |
pending |
Waiting for the customer to authorize a payment method (setup link) |
processing |
A charge is in progress (short-lived lock) |
paused |
Paused by a user, or automatically after retries were exhausted |
cancelled |
Cancelled — no future payments |
completed |
All planned payments collected |
expired |
Ended by date |
Charge Now#
Charge the next payment immediately. Fails with 400 for pending schedules, schedules without a default payment method or suggestedMode, a charge already in progress, or a charge attempted in the last 60 seconds. A decline returns 400 PROCESSING_ERROR.
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/charge-now \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{
"success": true,
"data": { "success": true, "transactionId": "5b9e2d7a-1c3f-4a8e-b6d0-2f4c8a1e7b93" },
"message": "Payment processed successfully"
}Payment History#
Summary of collected and failed payments.
Endpoint#
curl https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/payment-history \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{
"success": true,
"data": {
"recurring": { "id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61", "status": "active" },
"totalSuccessful": 3,
"totalFailed": 1,
"lastSuccessfulPayment": "2026-10-01",
"lastFailedPayment": "2026-09-01",
"nextPayment": "2026-11-01",
"status": "active"
}
}For per-payment rows use Get Payment Schedule; for the activity log use GET /api/v1/recurring/:id/history.
Activity History#
Audit log of the schedule (created, updated, paused, resumed, cancelled, payment_succeeded, payment_failed, retry_scheduled, skipped, payment_method_linked, ...).
Endpoint#
curl https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/history \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Link Payment Method#
Attach a new card to the schedule. A pciToken is promoted to a long-lived card-on-file token and becomes the default method. One of pciToken or paymentMethodId is required (400 otherwise).
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/link-payment-method \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"pciToken": "pci_tok_1a2b3c4d5e6f",
"gatewayType": "TsysSierra",
"last4": "4242",
"brand": "visa",
"isDefault": true
}'| Field | Type | Description |
|---|---|---|
pciToken |
string | PCI vault card token |
paymentMethodId |
uuid | Saved customer payment method (vault reference) |
gatewayType |
string | Defaults to TsysSierra |
last4, brand |
string | Display details for the activity log |
isDefault |
boolean | Defaults to true |
Send Payment Method Update Link#
Email the customer a secure link (valid 24 hours) to update their card. Returns 400 NO_EMAIL if the customer has no email on file.
Endpoint#
Response:
{
"success": true,
"data": {
"token": "0f1e2d3c-4b5a-4968-8776-a5b4c3d2e1f0",
"updateUrl": "https://uat.auxcore.net/update-payment-method?token=0f1e2d3c-4b5a-4968-8776-a5b4c3d2e1f0&type=recurring&id=8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61"
}
}Auto-Retry Logic#
When a scheduled charge is declined, AuxCORE retries it automatically:
- Each schedule allows
maxRetryAttemptsretries (default 3). - After a decline, the next retry is scheduled 24 hours later (
nextRetryAt). Due charges are processed hourly and retries are also swept every 6 hours. - A successful charge resets the failure counters and moves
nextPaymentDateto the next period. - When the retries are exhausted the schedule is set to
paused(pausedReason: "Payment failed after 3 retry attempts") and a dunning email is sent if notifications are enabled.
Notifications#
AuxCORE does not emit subscription-specific webhook events. Each charge creates an ordinary transaction (with requestOrigin: "recurring"), and customer emails are sent by the platform:
| When | |
|---|---|
| Recurring created / setup link | On creation with sendNotifications: true |
| Payment successful | After each successful automatic charge |
| Payment failed | After each failed automatic charge |
| Dunning notice | When retries are exhausted (can be turned off per merchant — see Dunning) |
Best Practices#
✅ DO:#
- Tokenize the card first - Pass a
pciToken, never raw card data - Set
suggestedMode- The scheduler cannot charge without it - Send
nextPaymentDate- When the first charge should happen on the start date - Use the setup link - Create with
status: "pending"when the customer must authorize the card - Watch the overview - Follow up on schedules with failed payments
❌ DON'T:#
- Don't create duplicate subscriptions - Search by
customerIdfirst - Don't cancel when a pause will do - Paused schedules can be resumed
- Don't ignore paused schedules - A schedule paused after failed retries needs a new card
Next Steps#
Need help? Contact support@auxcore.net