Recurring Billing

Charge a customer on a repeating schedule with a contract and subscription

Recurring billing charges a customer automatically on a repeating schedule — a monthly membership, an annual renewal, or a fixed installment plan. You set it up once by creating a contract (the schedule, amount, and line items) and a subscription (the customer, the saved card, and the status), and PCE bills each cycle for you. For the full field list, jump to the Request reference.

A single call to /checkout/v3/contractsubscription creates both objects together. To bill a customer once instead of on a schedule, use Sale. To collect with an emailed bill instead of an automatic charge, use invoicing (a companion page in this section).

Common use cases

  • Bill a subscription or membership every month or year
  • Spread a purchase across a fixed number of installments
  • Renew a service automatically on a saved card, with receipts each cycle

Make your first recurring plan

The fastest way to see it work: create a monthly plan on a customer's saved card. You'll need a customerId and a saved-card cardAccountId first — vault a card with Card Vaulting. The full set of options is in the Request reference.

POST /checkout/v3/contractsubscription

{
  "contract": {
    "merchantId": 1000157980,
    "type": "Recurring",
    "interval": "Monthly",
    "frequency": 1,
    "totalAmount": 49.99
  },
  "subscription": {
    "customerId": 10000001524400,
    "cardAccountId": 10000001225823,
    "invoiceMethod": "Autopay",
    "status": "Active",
    "startDate": "2026-02-01"
  }
}

You'll get back a 200 OK with the created contract and subscription, each with a server-assigned id. Store contract.id (to update or cancel the plan) and subscription.id.

{
  "contract": {
    "id": 10000000027043,
    "merchantId": 1000157980,
    "interval": "Monthly",
    "frequency": 1,
    "totalAmount": "49.99",
    "subTotalAmount": "49.99",
    "subscriptionCount": 1,
    "prorated": false,
    "billNow": false
  },
  "subscription": {
    "id": 10000000015147,
    "contractId": 10000000027043,
    "startDate": "2026-02-01T05:00:00Z",
    "invoiceMethod": "AutoPay",
    "cardAccountId": 10000001225823,
    "customerId": 10000001524400,
    "status": "Active",
    "sendReceipt": "Always",
    "allowPartialPayment": false,
    "eftAgreementRequested": false,
    "created": "2026-01-06T20:15:40.853Z",
    "modified": "2026-01-06T20:15:40.853Z"
  }
}

The endpoint is documented in the API reference at POST /checkout/v3/contractsubscription.


Scenarios

Every recurring plan is a contract + subscription pair. What changes per scenario is the schedule and how the first cycle is billed. Pick the one that matches the problem you're solving.

sequenceDiagram
    participant You as Your Application
    participant PCE as PCE
    participant Issuer as Cardholder's Bank

    You->>PCE: POST /checkout/v3/contractsubscription
    PCE->>PCE: Create contract + subscription (status: Active)
    PCE-->>You: 200 OK (contract.id, subscription.id)
    loop Each billing cycle
        PCE->>Issuer: Charge saved card for the cycle amount
        Issuer-->>PCE: Approved / Declined
        PCE-->>You: Webhook (PaymentSuccess / PaymentFail)
    end

Before you begin (all scenarios)

  • The customer exists and you have their customerId (see Create a customer).
  • A card is vaulted for that customer and you have its cardAccountId (see Card Vaulting).

Scenario 1: Monthly subscription on a saved card

(recurring plan, billed automatically)

Use this for memberships and subscriptions billed the same amount every month. Set interval to Monthly and frequency to 1, point the subscription at the customer's saved card, and set invoiceMethod to Autopay so PCE charges the card each cycle.

You'll also need: the customer's customerId and a saved cardAccountId.

Request

POST /checkout/v3/contractsubscription

{
  "contract": {
    "merchantId": 1000157980,
    "type": "Recurring",
    "interval": "Monthly",
    "frequency": 1,
    "totalAmount": 49.99
  },
  "subscription": {
    "customerId": 10000001524400,
    "cardAccountId": 10000001225823,
    "invoiceMethod": "Autopay",
    "status": "Active",
    "sendReceipt": "Always",
    "startDate": "2026-02-01"
  }
}

Response

{
  "contract": {
    "id": 10000000027043,
    "merchantId": 1000157980,
    "interval": "Monthly",
    "frequency": 1,
    "totalAmount": "49.99",
    "subscriptionCount": 1,
    "billNow": false
  },
  "subscription": {
    "id": 10000000015147,
    "contractId": 10000000027043,
    "startDate": "2026-02-01T05:00:00Z",
    "invoiceMethod": "AutoPay",
    "cardAccountId": 10000001225823,
    "customerId": 10000001524400,
    "status": "Active",
    "sendReceipt": "Always"
  }
}

Scenario 2: Annual plan billed on a fixed date

(yearly interval on a specific calendar day)

Use this for annual renewals that must land on a set date. Set interval to Yearly, then pin the day with month, dayNumber, and dayType. Here the plan bills every January 1.

You'll also need: the calendar date the renewal should charge.

Request

POST /checkout/v3/contractsubscription

{
  "contract": {
    "merchantId": 1000157980,
    "type": "Recurring",
    "interval": "Yearly",
    "frequency": 1,
    "month": "January",
    "dayNumber": 1,
    "dayType": "Day",
    "totalAmount": 240.00
  },
  "subscription": {
    "customerId": 10000001524400,
    "cardAccountId": 10000001225823,
    "invoiceMethod": "Autopay",
    "status": "Active",
    "startDate": "2026-01-01"
  }
}

Response

{
  "contract": {
    "id": 10000000027050,
    "merchantId": 1000157980,
    "interval": "Yearly",
    "frequency": 1,
    "month": "January",
    "dayNumber": 1,
    "dayType": "Day",
    "totalAmount": "240.00",
    "billNow": false
  },
  "subscription": {
    "id": 10000000015160,
    "contractId": 10000000027050,
    "startDate": "2026-01-01T05:00:00Z",
    "invoiceMethod": "AutoPay",
    "cardAccountId": 10000001225823,
    "customerId": 10000001524400,
    "status": "Active"
  }
}

Scenario 3: Plan with line items, tax, and a discount, billed now

(itemized contract with the first cycle charged immediately)

Use this when the plan has itemized products, sales tax, and a discount, and you want to charge the first cycle at creation. Provide purchases[], taxes[], and discounts[], and set billNow to true.

You'll also need: the product line items, applicable tax rate, and any discount to apply.

Request

POST /checkout/v3/contractsubscription

{
  "contract": {
    "merchantId": 1000157980,
    "type": "Recurring",
    "interval": "Monthly",
    "frequency": 1,
    "prorated": false,
    "billNow": true,
    "purchases": [
      {
        "productName": "Mittens",
        "description": "Warm Gloves",
        "price": 4.99,
        "quantity": 5,
        "subTotalAmount": "24.95",
        "taxRate": "0.089",
        "taxAmount": "1.93"
      }
    ],
    "taxes": [
      { "name": "Sales Tax", "rate": "0.089", "taxAmount": "1.93" }
    ],
    "discounts": [
      {
        "name": "Loyalty 13%",
        "discountType": "Order",
        "discountRateType": "Percent",
        "discountApplicationType": "Automatic",
        "rate": "0.13",
        "code": "LOYAL13"
      }
    ],
    "subTotalAmount": "24.95",
    "taxAmount": "1.93",
    "discountAmount": "3.24",
    "totalAmount": 23.64
  },
  "subscription": {
    "customerId": 10000001524400,
    "cardAccountId": 10000001225823,
    "invoiceMethod": "Autopay",
    "status": "Active",
    "allowPartialPayment": false,
    "startDate": "2026-02-01"
  }
}

Response

{
  "contract": {
    "id": 10000000027055,
    "merchantId": 1000157980,
    "interval": "Monthly",
    "frequency": 1,
    "purchases": [
      {
        "id": 10000000027413,
        "productName": "Mittens",
        "description": "Warm Gloves",
        "quantity": 5,
        "price": "4.99",
        "subTotalAmount": "24.95",
        "taxAmount": "1.93"
      }
    ],
    "subTotalAmount": "24.95",
    "taxAmount": "1.93",
    "totalAmount": "23.64",
    "prorated": false,
    "billNow": true
  },
  "subscription": {
    "id": 10000000015170,
    "contractId": 10000000027055,
    "startDate": "2026-02-01T05:00:00Z",
    "invoiceMethod": "AutoPay",
    "cardAccountId": 10000001225823,
    "customerId": 10000001524400,
    "status": "Active",
    "allowPartialPayment": false
  }
}

Track the plan

Read the subscription.status on the response for the immediate outcome. To follow a plan afterwards:

Each scheduled charge is a payment, so subscribe to the payment webhooks to track cycles without polling:

  • PaymentSuccess: a cycle charge was approved.
  • PaymentFail: a cycle charge was declined.

Manage a plan

JobCallReference
Cancel / remove a subscriptionDELETE /checkout/v3/contractsubscription/{id}Remove a subscription
Update the underlying contractPUT /checkout/v3/contract/{id}Update a contract
Delete the contractDELETE /checkout/v3/contract/{id}Delete a contract

To pause billing without deleting the plan, update the subscription status to Inactive; set it back to Active to resume.

Additional operations. Contracts also support file attachments (attach / read / delete). For reconciling contracts against settlement and deposits, see Reports & Reconciliation.


Request reference

The complete set of fields for the create request. The body is a { "contract": { … }, "subscription": { … } } envelope. Scenarios above use subsets of these.

Contract object

The schedule, amounts, and line items.

ParameterRequiredDescription
merchantIdYour PCE merchant identifier that owns the contract.
typeRecommendedBilling behavior. Possible values: Recurring, Installment.
intervalRequired for billingHow often the contract bills. Possible values: Once, Daily, Weekly, Monthly, Yearly.
frequencyRequired for billingNumber of intervals between each billing cycle (for example, interval: Monthly + frequency: 3 bills quarterly).
weekDayOptionalDay of the week billing occurs. Possible values: SundaySaturday.
monthOptionalMonth billing is scheduled. Possible values: JanuaryDecember.
dayNumberOptionalDay number of the month on which billing occurs.
dayTypeOptionalHow the billing day is calculated. Possible values: Day, First, Second, Third, Fourth, Last.
dayOptionalSpecific day configuration. Possible values: SundaySaturday, Day, Weekday, Weekend.
purchasesOptionalArray of line items on the contract (product name, price, quantity, per-item tax).
taxesOptionalArray of tax breakdowns applied to the contract.
discountsOptionalArray of discounts applied to the contract.
totalAmountRecommendedFinal amount charged each cycle, including taxes and discounts.
subTotalAmountOptionalAmount before taxes and discounts.
taxAmountOptionalTotal tax applied to the contract.
discountAmountOptionalTotal discount applied to the contract.
proratedOptionalSet to true to prorate the first invoice amount.
billNowOptionalSet to true to charge the first cycle immediately at creation.

Subscription object

The customer, the funding card, and the status.

ParameterRequiredDescription
customerIdThe customer being billed. See Create a customer.
cardAccountIdRequired for billingThe saved card used for billing. Vault a card with Card Vaulting.
startDateRecommendedDate the subscription becomes active and billing begins.
invoiceMethodRecommendedHow each cycle is collected. Use Autopay to charge the saved card automatically.
statusRecommendedSubscription status. Possible values: Active, Inactive, Cancelled, Trial, Pending, Completed, PendingAuthorization, Deleted.
sendReceiptOptionalWhen to send receipts. Possible values: Always, Never, First.
allowPartialPaymentOptionalSet to true to allow partial payments against a cycle's invoice.
eftAgreementRequestedOptionalSet to true to request an EFT/ACH agreement for the subscription.

Validation

The prerequisites above are the validations, and PCE enforces them when you submit. Only contract.merchantId and subscription.customerId are required by the schema; to actually bill, you must also supply a schedule (interval + frequency) and a funding method (cardAccountId). A submission is checked synchronously; if a check fails, the request returns an error and no contract is created.

Submission checks:

  • Required fields are present and correctly formatted.
  • The customerId and cardAccountId resolve to a real customer and a chargeable saved card.
  • Your merchant account is permitted to create recurring contracts.

Statuses

A subscription carries one of these statuses. Active bills on schedule; Inactive pauses billing; Cancelled and Deleted stop it; Trial and Pending/PendingAuthorization cover pre-active states; Completed applies when a fixed plan has run its course.

StatusMeaning
ActiveBilling on schedule.
InactivePaused; not billing until reactivated.
TrialIn a trial period before regular billing.
PendingCreated but not yet active.
PendingAuthorizationAwaiting authorization (for example, an EFT/ACH agreement).
CompletedAll scheduled cycles have run (installment plans).
CancelledStopped by request; no further billing.
DeletedRemoved.

Go live

The shared pre-production checklist (production credentials, webhook subscription, and sandbox testing) is in Getting Started. Specific to recurring billing, also confirm:

  • Customers and cards are vaulted before you create their plans (you need customerId and cardAccountId).
  • You subscribe to PaymentSuccess and PaymentFail and handle a declined cycle (retry, dunning, or pause the plan).
  • The schedule fields (interval, frequency, and where used month/dayNumber/dayType) produce the billing date you expect.
  • Receipts (sendReceipt) and any EFT agreement (eftAgreementRequested) match your business and compliance requirements.

Best practices

General practices (subscribe to webhooks, test in sandbox) are in Getting Started. Specific to recurring billing:

PracticeDescription
Vault firstCreate the customer and vault their card before the plan, so customerId and cardAccountId are ready.
Handle failed cyclesWatch PaymentFail and apply dunning or retry logic; a declined cycle shouldn't silently stop revenue.
Pause, don't deleteTo hold billing temporarily, set status: Inactive rather than deleting — you keep the plan and history.
Reconcile with historyUse /checkout/v3/contract/payment and /checkout/v3/contract/history to reconcile what a plan has billed.
Keep amounts explicitSend subTotalAmount, taxAmount, discountAmount, and totalAmount so the billed amount is unambiguous.

Next steps

See also



Did this page help you?
.readme-logo { display: none !important; }