HomeProduct DocsAPI ReferenceChangelog
RecurlyAPI GuidesRecurly.jsWebhooksAPI ReferenceSupportBook demo
API Reference

Getting started v2021-02-25

A reference guide to the Recurly Subscriptions API fundamentals, covering versioning, error handling, pagination, and rate limits.

This guide covers the essential concepts you'll need to build a stable integration with the Recurly Subscriptions API — versioning, error handling, pagination, and rate limits.

API versioning

The Recurly Subscriptions API uses date-based versioning to give you stability while we continue improving the platform. Your code won't break when we ship new features.

Specify a version in every request

Every API request must include an Accept header specifying the API version you're targeting.

ImportantEvery request must include an Accept header with a valid API version. Without it, your request will fail.
Accept: application/vnd.recurly.v2021-02-25
Accept: application/vnd.recurly.v2021-02-25+json

All responses include a Recurly-Version header confirming which version processed your request:

Recurly-Version: recurly.v2021-02-25

Version format

Versions follow a YYYY-MM-DD format (for example, v2021-02-25), which reflects the approximate date the changes were released.

Available versions and client library compatibility

If you're using one of Recurly's official client libraries, make sure your library version aligns with your API version:

API versionClient library version
v2021-02-254.x
v2019-10-103.x

We recommend keeping both your API version and client library up to date. Later versions are more performant and include important bug fixes. See the changelog for a complete list of improvements.

Client libraries by language:

Using the latest version

If you want to automatically use the newest API version and are comfortable accepting the risk of breaking changes, specify latest instead of a specific date:

Accept: application/vnd.recurly.latest
Accept: application/vnd.recurly.latest+json
WarningUsing latest means your integration may break without notice if we introduce breaking changes. Use a pinned version in production.

Deprecated versions

When we deprecate an API version, response headers will tell you it's nearing retirement:

Recurly-Deprecated: TRUE
Recurly-Sunset-Date: 2017-06-01T00:00:00+00:00

The sunset date is an ISO 8601 formatted timestamp. After that date, the version will no longer be accessible.

Unsupported versions

Requests to unsupported API versions return a 406 status code with a list of acceptable versions:

{
  "error": {
    "type": "invalid_api_version",
    "message": "That accept header isn't in the format we use to specify an API version. Try one of these instead:",
    "acceptable_accept_headers": [
      "application/vnd.recurly.v2021-02-25",
      "application/vnd.recurly.v2019-10-10"
    ]
  }
}

Error messages

API errors are designed for developers. If you're displaying these messages to end users, translate them into language your users will understand — for example, a technical message like "Invalid account code format" might be better displayed as "We couldn't find that account."

For detailed information on transaction-specific error codes, see our documentation.

Pagination

All GET listing endpoints return results in pages to keep responses fast.

Response format

Every listing endpoint returns the same response structure:

{
  "object": "list",
  "has_more": true,
  "next": "https://api.recurly.com/v2021-02-25/accounts?limit=200&cursor=1234",
  "data": [
    { "id": "account1", "code": "acme-corp" },
    { "id": "account2", "code": "widgets-inc" }
  ]
}
FieldDescription
objectAlways "list" for listing endpoints.
has_moretrue if there are more pages; false if you've reached the last page.
nextA URL pointing to the next page of results.
dataAn array of objects for the current page.

Walking through all pages

To retrieve every record, follow the next URL until has_more is false:

let allRecords = [];
let nextUrl = 'https://api.recurly.com/v2021-02-25/accounts';

while (nextUrl) {
  const response = await fetch(nextUrl, {
    headers: { 'Accept': 'application/vnd.recurly.v2021-02-25' }
  });
  const page = await response.json();
  allRecords = allRecords.concat(page.data);
  nextUrl = page.has_more ? page.next : null;
}

Query parameters

Most listing endpoints accept parameters to filter and sort results:

  • ids — A comma-separated list of specific IDs to fetch.
  • limit — The number of records to return per page.
  • order — The sort order (asc for ascending, desc for descending).
  • sort — The field to sort by (often a date field).
  • begin\_time — ISO 8601 datetime to start filtering from.
  • end\_time — ISO 8601 datetime to stop filtering at.
GET /v2021-02-25/accounts?limit=100&sort=updated_at&order=desc&begin_time=2024-01-01T00:00:00Z

Counting total records with HEAD

Every GET listing endpoint also supports the HEAD HTTP method, which returns a count of matching records without downloading the actual data:

HEAD /v2021-02-25/accounts?begin_time=2024-01-01T00:00:00Z

The response includes a Recurly-Total-Records header with the total count.

Rate limits

To keep the API fast and reliable for all customers, we apply rate limits to all requests. Your limit depends on whether you're using a sandbox or production account.

Rate limit tiers

Account typeLimitWhat counts
Sandbox400 requests per minuteAll requests
Production1,000 requests per minuteGET requests only — POST, PUT, and DELETE don't count

In production, you can create subscriptions, update accounts, and delete resources without worrying about rate limits — only reads are throttled.

How limits are calculated

The rate limit is measured over a rolling five-minute window. A production site could make 4,000 GET requests in one minute without hitting the limit, as long as it made fewer than 1,000 requests during the preceding four minutes.

Exceeding your limit

If you exceed your rate limit, the API returns a 429 Too Many Requests status code. If your business needs a higher limit, reach out to [email protected].

Monitoring your usage

Three response headers help you track your rate limit status:

HeaderDescription
X-RateLimit-LimitYour rate limit (requests per minute).
X-RateLimit-RemainingHow many requests you have left before the window resets.
X-RateLimit-ResetA Unix timestamp indicating when your request count resets.

What's next

FAQs

Do I have to specify an API version?

Yes. Every request must include an Accept header with a specific API version. Without it, the API will reject your request with a 406 error.

How often are new API versions released?

We release new versions as we add significant features or make breaking changes. Each version is supported for an extended period before sunset, giving you time to migrate.

Can I use the latest version automatically?

You can specify latest in your Accept header to always use the newest version. Keep in mind that your code could break if we introduce breaking changes — use this only if you're comfortable monitoring for API updates.

What happens if I request an old API version?

Once an API version reaches its sunset date, requests to that version return a 406 error with a list of supported versions. We give plenty of warning before sunsetting a version.

Do POST, PUT, and DELETE requests count against my rate limit in production?

No. In production, only GET requests are rate-limited. Write operations — creating, updating, or deleting data — don't count toward your limit.

I keep hitting the rate limit. Can I get a higher limit?

Yes, contact [email protected] or your account manager to discuss higher limits. We can also help you optimize your integration to use fewer requests.