Skip to main content
The Reval API exposes your store’s subscription data so you can pull it into your BI, your data warehouse or your own automations, and lets you act on them: pause, cancel, skip, change products and address. It is GraphQL, and every key sees and operates only the store that generated it.
Queries are in the sections below; actions are under Actions. The full list of types and fields is in the schema reference, and there are recipes for the most common cases. To learn what happens without polling, see the webhooks.

Authentication

Keys are generated in Reval → Integrations in your Shopify admin. Name each key after the tool that will use it (“Triple Whale”, “Looker”) and save it right away: it is shown in full exactly once. Afterwards the list only shows its prefix. Send the key on every request as a Bearer token:
If your client cannot set Authorization, the X-Reval-Api-Key header is equivalent.
  • A revoked key stops working immediately. Requests get 401 with code UNAUTHENTICATED.
  • Reval stores only a hash of the key. If you lose it, revoke it and generate another.
  • You can have up to 25 active keys per store, each with a name of up to 60 characters. The list shows each key’s last use, so you know which ones to revoke.
  • When you generate a key you choose read and write or read-only. A read-only key queries everything but cannot run actions (see Actions). The type cannot be changed later: revoke and generate another.
Responses include your customers’ personal data (email, address, phone, tax id). Treat keys like a password: never commit them to public code or share them over chat.

First query

The endpoint supports introspection, so any GraphQL client (GraphiQL, Insomnia, Postman, Altair) shows you the full schema with every field’s description. This page is the overview; the schema is the reference.
  • Only POST with a JSON body { "query", "variables", "operationName" } is accepted: one operation per request, no batching and no GET.
  • The endpoint answers CORS, so a browser tool can call it. Do not do that from your storefront: the key would be exposed to anyone who opens the page source.

What you can query

Objects that exist in Shopify carry their Shopify GID so you can join them against the Admin API: shopifyOrderId, shopifyCustomerId, shopifyVariantId, shopifyProductId. Mercado Pago identifiers (mercadoPagoPreapprovalId, mercadoPagoPaymentId) let you reconcile against your MP account; credentials are never exposed.

Conventions

  • Amounts (Money) are strings with two decimals: "18500.00". The currency is the currency field on the same object.
  • Dates (DateTime) are ISO-8601 in UTC: "2026-11-02T13:00:00.000Z".
  • Enums are upper-case: ACTIVE, PAUSED, CANCELLED, MONTHS, PERCENT, DYNAMIC_BOX.
  • Reval ids are opaque; always use the one the API returned.

Pagination

Every list is a Shopify-style connection: ask for first items and continue with after using the previous page’s endCursor.
  • nodes is the shortcut when you do not need each row’s cursor.
  • totalCount counts every row matching the filter, not just the page.
  • reverse: true flips the order (oldest first).
  • Nested lists (subscription.orders, customer.subscriptions) paginate the same way.

Filters

Each list takes a filter with the most used fields:
For an incremental warehouse sync, request subscriptions(filter: { updatedAfter: "<last run>" }, sortKey: UPDATED_AT, reverse: true) and orders(filter: { createdAfter: "<last run>" }).

Limits

Limits exist so a heavy integrator can never affect the checkout or the charges. When a query crosses one, the response says which: Depth counts model objects: subscriptions › items › plan › group is four levels. edges, node, nodes and pageInfo do not count. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (epoch seconds) so your client can pace itself.

Errors

Errors follow the GraphQL format, with an extensions.code your code can switch on:
Business rules of the actions (invalid state, minimum commitment, archived plan, a Mercado Pago refusal) are not errors: they come back in userErrors with 200. See Actions.

Actions

Beyond reading, the API lets you act on your store’s subscriptions with the same actions the merchant has in the admin: pause, resume, cancel, skip the next delivery, change products and quantities, update the address and generate a portal link. It also lets you build checkout links with several products and the customer’s details already filled in, so a bot can close the sale with a ready link. They are GraphQL mutations on the same endpoint. Every action has exactly the admin’s effects: Mercado Pago is updated first (if it refuses, nothing changes in Reval), price and shipping are recomputed when they change, the same events fire to Klaviyo, Flow and your webhooks, and the subscription’s timeline names “API (key name)” as the author.

Read-only keys

When you generate a key in Reval → Integrations you choose read and write or read-only. A read-only key can run any query, but every mutation answers 403 with the code FORBIDDEN_READ_ONLY. Use it for dashboards and reports; keep read-write keys for the automations that actually act.

Idempotency

Actions move real charges and shipments, so a retry (a timeout, a crashed worker) must not repeat them. Send an Idempotency-Key header with a unique identifier per operation (a UUID). If the same key arrives again with the same body within 24 hours, the API returns the original answer without running anything and sets the header Idempotency-Replayed: true. If it arrives with a different body, it answers 422 with IDEMPOTENCY_KEY_REUSED: that is a bug on your side, not a second operation.
The header is optional, but without it a retry can skip two cycles or cancel twice.

Business rejections: userErrors

A mutation never fails with a GraphQL error for a business rule. It answers 200 with a payload carrying the object or a userErrors list with a code your code can switch on, and the subscription stays as it was:

Available mutations

All return { subscription, userErrors }, except subscriptionPortalLink and checkoutLinkCreate, which return { url, expiresAt, userErrors }. Pause from a support bot
Cancel with a reason and a note
Change products
Portal link for a retention email

Examples

Active subscriptions with their products and next charge
One customer with their whole history
This month’s cancellations, with reason
Published plans and boxes