Revvly
Docs
Guide

Reference everything by your own id.

Set externalId once at creation — on a client, on a subscription — and every call after that uses your own identifiers. No lookup table, no stored Revvly ids, nothing to keep in sync.

Give this prompt to an integration agent

You are integrating external identifiers with Revvly usage reporting.
Set a client's externalId on createClient and a subscription's externalId on
createSubscription (both public GraphQL, both require the WRITE capability) to the
caller's stable account/subscription id — the dashboard's internal provisioning flow
is only needed for migrated or otherwise advanced subscriptions. Then report usage
using externalSubscriptionId and variableSlug, never both external and internal ids
for one resource. Discover available variable slugs with
GET https://api.revvly.ai/api/v1/variables.
POST https://api.revvly.ai/api/v1/events requires a stable eventId and raw-body HMAC;
duplicate events return DUPLICATE and invalid references are per-event REJECTED results.
REST usage mutations at https://api.revvly.ai/api/v1/usage* require an Idempotency-Key
and return regular HTTP errors for invalid references. Keep credentials server-side.

01Why bother

Every resource in Revvly has an internal id, but you already have your own — an account id, a subscription id in your billing system. Setting externalId once lets your integration speak in its own vocabulary from then on, instead of maintaining a lookup table that can drift out of sync with Revvly.

02Set it on a Client

Pass externalId on createClient (public GraphQL, requires the WRITE capability) — unique per tenant, up to 100 characters. From then on, query client(externalId: "...") instead of client(id: "...") to fetch that client plus its region, subscriptions, invoices, and paymentSummary.

03Set it on a Subscription

Pass externalId on createSubscription (public GraphQL, requires the WRITE capability) — unique per tenant, and editable later if your own identifier ever changes. The same API key you use for usage reporting below can provision the subscription and set its externalId in one call, right after creating the client. The dashboard's subscription wizard (createSubscriptionWithPricing, on the internal JWT-authed API) still exists for migrations and other advanced authoring the public mutation deliberately leaves out — historical backfill, billing schedules, discounts, legacy catalog-version pins.

04Report usage without ever reading a Revvly id

Usage events accept externalSubscriptionId in place of subscriptionId, and variableSlug in place of variableId — supply exactly one of each pair. Combined with the externalId you set at creation, a usage-reporting integration never has to store a single Revvly-issued id.

05What happens when a reference does not resolve

On the single-item usage endpoints (POST https://api.revvly.ai/api/v1/usage and friends), a bad reference is a normal HTTP error: 404 if the external id or slug does not resolve, 400 if you supply both or neither of a pair, 403 if it resolves but sits outside your key's scope. On the batch event-ingestion endpoint (POST https://api.revvly.ai/api/v1/events) the same failures do not fail the call — each bad event comes back as a per-event REJECTED result inside a 202 response, so one bad reference never blocks the rest. POST https://api.revvly.ai/api/v1/usage/batch is a batch too, but reports per-item outcomes as numeric HTTP-style status codes (200, 400, 404, …) rather than the REJECTED string.

06Prefer to sync Revvly's ids instead

If you would rather cache ids in your own database, GET https://api.revvly.ai/api/v1/subscriptions and GET https://api.revvly.ai/api/v1/variables are Bearer-authenticated discovery endpoints — not HMAC-signed — filtered to your key's scope, with keyset pagination via cursor / nextCursor. GET https://api.revvly.ai/api/v1/subscriptions/by-external/:externalId resolves the same summary by the id you set in step 3, for a one-off lookup instead of a full sync.

A worked example

Loopline never stores a Revvly id.

One account id, set once, carries the whole integration — creation, usage reporting, a typo that fails safely, and two different lookups later.

  1. 01
    Your own account id
    Loopline, your SaaS, already tracks customers by acct_4471 in its own database. Nothing about Revvly needs to enter that system.
  2. 02
    Create the subscription
    Right after creating the client, the same backend calls createSubscription (public GraphQL) with clientExternalId: 'acct_4471', bundleId, and externalId: 'acct_4471'. Revvly hands back its own id, but your metering integration never has to store it.
  3. 03
    Usage happens
    A user on that account makes 1,500 API calls. Your metering job reports it with externalSubscriptionId: 'acct_4471' and variableSlug: 'api-calls' — the same two strings you already had.
  4. 04
    A typo in one event
    One event in the batch carries variableSlug: 'api-call' (singular, a typo). It comes back REJECTED in the batch response; the other 1,499 events post normally, and you fix the slug on the next run.
  5. 05
    Support looks it up
    Someone needs to check the account's Revvly status without touching your database. GET https://api.revvly.ai/api/v1/subscriptions/by-external/acct_4471 resolves the subscription directly from the id everyone already has memorized.
  6. 06
    The client side, too
    The billing contact for that account is queried the same way — no Revvly id needed: client(externalId: "acct_4471") returns the client, its region, invoices, and outstanding balance in one call.