Developers : Scheduled & Recurring Payments with the Stax Pay API

If you want to charge a customer sometime in the future one or more times, you’ll need to use our POST invoice/schedule resource. Before we dig into that, let’s look at some prerequisites. 

Before accepting any payments, you’ll need to create a customer record. For this, use the POST customer route

After you have a customer id, you can use it to create a payment method for that customer. However, you don’t have to do that when creating a scheduled invoice.

A schedule record may be easier to comprehend if you consider it an “Invoice Generator.” It generates invoices at different points in time. It stores the invoice information like the total, the invoice meta (tax, line items etc.) and which customer the invoice should belong to. Then, when that point in time occurs, the invoice is generated. At that time, if the schedule had a payment_method_id value (we call this “autopay”), the invoice would attempt a payment against that payment method. At that moment, a child transaction against that invoice would also be created and show the fate of the transaction - whether it succeeded or failed. The functionality is identical regardless of whether the payment method is a bank or card. 

If you don’t attach a payment_method_id to the schedule, then when the invoice is sent, the customer will be able to key in their payment method and pay the invoice. At this time, the customer will have the option of saving the card “for the future,” which will put the payment method id on the schedule to which the invoice belongs.

Let’s take a look at the API call to create a schedule:

POST invoice/schedule


    "rule": "FREQ=DAILY;COUNT=3;DTSTART=20181126T000000Z",

    "total": "12.00",

    "url": ““,

    "email_notification": false,

    "files": [],

    "customer_id": "d45ee88c-8b27-4be8-8d81-77dda1b81826",


    "meta": {



        "lineItems": [


                "id": "optional-fm-catalog-item-id"

                "item":"Demo Item",

                "details":"this is a regular demo item",


                "price": 1






This call (and all calls) require three headers:

Authorization:Bearer insert_api_key_here



(More information about api keys)

The post body is raw JSON. Meta will become the meta of the invoices and transactions which are generated later on by the API when your next run at date occurs. To learn more about the meta see our documentation on Invoice meta.

customer_id and payment_method_id are optional. Meta is also optional, but the emails that are sent out rely on the meta information here. If you are relying on these emails, you’ll probably want to populate meta.subtotal,, and meta.lineItems since those fields show up in the emails and in the Omni web platform when you drill down into an invoice or payment.

The rule field is really what sets apart scheduled invoices. This field is a semicolon delimited list of “RRule” params. We require the DTSTART params. Please see the RRule spec for a full explanation.

Also, there is a super handy javascript utility you can use to see how the RRule spec works called Jakubroztocil/rrule.

Again, we require the DTSTART argument and it must be in the proper format, ex. 20200329T051500Z. This is a UTC timestamp and the format is called the ISO 8601 combined date time format. Here’s a stack overflow article to explain.


Here is a short guide for common RRule strings:


Repeat monthly and never end: 



Repeat monthly for 12 months: 



Repeat every other week and end on DEC 31st 2020: 



Run one time on a future date:

(freq is still required but will be ignored after the first invoice is generated)



You cannot supply a DTSTART in the past, but you can use the current time. However, in case of latency, you should at least add a couple of seconds or a minute when generating your DTSTART.

If you do pass the current time, the response will still be scheduled and but will have a PENDING status. Once you create a schedule, the next_run_at field will show the exact time Omni will generate the next invoice.

The statuses on schedules are as follows:

  • DELETED - schedule has been deleted by DELETE invoice/schedule/id and has a deleted_at date
  • PAUSED - schedule has been paused with PUT invoice/schedule/id and the ‘active’ field is set to 0
  • PENDING - DTSTART is in the past, but the API hasn’t processed it yet. Our scheduler runs on the minute and can get slightly delayed at times.
  • COMPLETED - if the schedule had a UNTIL or COUNT and those items have passed, then the schedule is completed.
  • NOT STARTED - the DTSTART is still in the future (and next_run_at is in the future)
  • WAITING - the schedule has already started but is simply waiting for the next run date to occur.

Note about pausing: If you use PUT invoice/schedule/id to pause the schedule. It will clear the next_run_at date also. This means no new invoices will be generated. To resume the schedule, you must mark active to 1 or true again, and you will need to update your rule’s DTSTART to have a date in the future. A date in the past is never allowed during a PUT or POST operation. 

The future_occurrences is an array of timestamps and is truncated to 50. So estimating total revenue for a schedule only really works if it has a specific end date or your calculation only cares about a certain number of occurrences. 

If you want to delete a schedule, simply call DELETE invoice/schedule/id, and you’ll see that it now has a deleted_at. There is no way to undelete a schedule without opening a support request with us.

When an invoice is generated, by default, it will be emailed to the customer - if there is a customer attached and the customer has an email value. If there is a payment_method_id on the schedule record, then the payment will be attempted, and then the invoice will be emailed, and that email will show the status of the payment and any remaining balance due on the invoice. If you do not wish your invoices to be sent automatically, then supply email_notification with a value of 0 or false. This will prevent an email from automatically sending when an invoice is created. By default, this field is true.

We believe our scheduled invoice system is robust and easy to use. Please let us know if you have any questions or suggestions.