Metering quickstart

Create a meter and ingest reproducible usage from your server.

Prerequisites

Use a staging merchant key with the required meter/usage access and a customer belonging to that merchant. A meter counts consumption; a price and subscription determine how it is billed. Ingesting an event does not itself mean a payment was taken.

Create a meter with REST

This Node.js example includes the /v2 base path and checks HTTP errors. Store secrets in environment variables on your server.

const apiKey = process.env.REVKEEN_API_KEY;
if (!apiKey) throw new Error("Set REVKEEN_API_KEY to a staging merchant secret");
async function request(path, options = {}) {
  const response = await fetch(`https://staging-api.revkeen.com/v2${path}`, {
    ...options,
    headers: { "x-api-key": apiKey, "Content-Type": "application/json" },
  });
  if (!response.ok) throw new Error(`RevKeen request failed (${response.status})`);
  return response.json();
}
const meter = await request("/meters", {
  method: "POST",
  body: JSON.stringify({ name: "API calls", event_name: "api_call", aggregation: "count" }),
});
console.log(meter);

For sum, max, or last, select a numeric value_key or the supported arithmetic value_expression. For count_unique, set unique_count_key. Filters determine which events match. Inspect a small sample before enabling billing.

Ingest with the published TypeScript helper

Install @revkeen/sdk@1.20260822.1541. This release has usage.ingest; it does not have the complete regenerated meter/event-query surface.

import { RevKeenClient } from "@revkeen/sdk";
const apiKey = process.env.REVKEEN_API_KEY;
const customerId = process.env.REVKEEN_CUSTOMER_ID;
if (!apiKey || !customerId) throw new Error("Set staging key and customer UUID");
const client = new RevKeenClient({ apiKey, baseUrl: "https://staging-api.revkeen.com/v2" });
const result = await client.usage.ingest({
  events: [{
    name: "api_call",
    customer_id: customerId,
    quantity: 1,
    idempotency_key: "request_8b742e_completed",
    metadata: { environment: "staging" },
  }],
});
console.log(result);

Replace the sample key with a stable identifier derived from your own business event. Persist it before sending. A retry of that event must retain the same key and payload. Up to 1,000 events can be submitted per request; inspect each result rather than treating the HTTP status as all-or-nothing success.

OutcomeWhat to do
ingestedRecord the accepted event identifier.
duplicateReconcile the original event; do not submit a new key to force acceptance.
skippedInspect why the event was not billable or matched.
failedCorrect the reported validation/input problem; retain an audit trail.

All-duplicate results can return 200; mixed results can return 207. A missing idempotency key or malformed quantity is rejected. Retry transport failures with bounded backoff and the original identity, and honour Retry-After for rate limits.

Limits

LimitValueWhen exceeded
Request body5 MiBThe whole request is rejected with 413. Split the batch.
metadata / properties per event16 KiB, measured as UTF-8 JSONThat event is failed at its own index; the other events in the request are still processed.
Events per request1,000The request is rejected with 400.
Request rate1,000 write requests per minute per merchant, shared by usage events, meters and meter prices, whatever the number of events in each429 with Retry-After in seconds. Wait that long, then retry with the same idempotency keys.

Time and customer identity

Use the real occurrence timestamp in RFC 3339 format, not the retry time. Billing periods use [start, end) boundaries. Customer UUID, external customer reference, and optional subscription/meter filters serve different purposes; do not send another merchant's identifiers.

A percentage-priced meter interprets its input quantity as minor currency units. A count meter counts events. Agree the unit with the meter configuration before ingestion; never interchange currency, minor units, and consumption quantities.

Next: Inspect usage and invoice provenance.

Owner: david · Reviewed 5 Sep 2026

On this page