Skip to main content
QuotaMint is a plain HTTPS JSON API. There is no SDK to install and no generated client to trust — anything that can send an HTTP POST and parse JSON can integrate. This page shows the same working pattern in several languages and calls out where each language will try to hurt you. The pattern has four steps. Get them right once, in one place, and every call site stays safe:
  1. Read the key and base URL from the environment, never from source code.
  2. Normalize credit amounts to a decimal at the boundary. Amounts arrive as JSON numbers with up to six decimal places. That wire format round-trips exactly for every value QuotaMint can send, but the moment you add 0.1 twice in a floating-point type you are doing money math in binary. Convert to a decimal string (or your language’s decimal type) immediately after parsing, and keep it that way until you display it.
  3. Mint and persist the idempotency key before the first HTTP attempt. The key identifies the billable unit of work — not the network attempt. Details and the crash scenario are in idempotency and retries.
  4. Retry unknown outcomes with the same key, never a new one. A timeout or 503 means the decision may have committed. Only the idempotency key makes replaying it safe.
The machine-readable OpenAPI 3.0 contract lives at openapi/quotamint-runtime.yaml in the main repository. Generate or validate against it rather than hand-copying shapes.

The language-independent handler

Whatever the language, the decision logic is this pseudocode:
Two responses look similar and mean different things: a 200 with allowed: false is a normal product outcome; a 429 with no Retry-After header is the workspace hitting its monthly event allowance, and retrying cannot help until the plan changes.

Node.js (and Bun, Deno)

Two JavaScript traps this snippet avoids:
  • JSON.parse gives you binary doubles. 0.1 + 0.2 !== 0.3. Convert credits to strings before accumulating; String(v) or Intl.NumberFormat on a raw float is display-only.
  • JavaScript Date.now()-derived keys are not stable. Do not build idempotency keys from anything that changes between attempts.

Python

Python notes:
  • Keep requests timeouts below 10s so a stuck connection cannot hang a worker; the server-side decision budget is 5 seconds, so a healthy runtime always answers first.

Go

Go’s encoding/json decodes numbers into float64, which is the mistake to avoid. Decode into json.Number (or json.RawMessage), or use github.com/shopspring/decimal.

Java

Using raw string matching for allowed keeps the sample dependency-free; in production parse with Jackson into typed fields and map creditsUsed/creditsRemaining to BigDecimal.

PHP

The CURLOPT_HEADERFUNCTION comment matters: to read Retry-After you must capture response headers explicitly; the sketch above shows where.

Ruby

C# (.NET)

JsonElement.GetDecimal() parses the JSON number as an exact decimal, which is exactly what you want here; avoid GetDouble() for credit fields.

Rust

Two serializations meet here: serde_json’s default number decoding is f64, and the pivot is to keep credit fields as serde_json::Number (or String) and parse them into rust_decimal::Decimal with the serde-with-arbitrary-precision feature. f64 is the bug.
In real code deserialize the success body with rust_decimal::Decimal for creditsUsed / creditsRemaining, and return a typed denial struct instead of raw Value.

Curl for anything else

For a language not shown above — or for a shell script, cron job, or postgres psql extension — ,the plain curl form from the quickstart is the whole API:

What is identical everywhere

  • The endpoint, method, and JSON shape come from the OpenAPI document, not from any SDK.
  • One key per billable unit, persisted before the first attempt, reused on every retry. See idempotency and retries.
  • Credit amounts are decimal JSON numbers. Normalize to your language’s decimal type at the edge.
  • Denials (allowed: false) are 200. Retry classification by status is in errors and denial reasons.
  • The environment is in the key (qm_test_ vs qm_live_), never in the body — see test and live environments.
  • Send X-Request-ID on every call so support can trace a request end to end.