Client Configuration¶
TangoClient is the entry point for every API call. This guide covers the constructor, environment variables, retry semantics, error handling, and how to plug in a custom fetch.
For per-method signatures, see API_REFERENCE.md. For webhook receivers, see WEBHOOKS.md. For response shaping, see SHAPES.md.
Constructor¶
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({
apiKey: process.env.TANGO_API_KEY, // optional if TANGO_API_KEY is set in env
baseUrl: "https://tango.makegov.com", // default
timeoutMs: 30_000, // default
retries: 3, // default
retryBackoffMs: 250, // default
});
Options¶
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | reads TANGO_API_KEY env | Tango API key. Sent as X-API-KEY header. |
baseUrl | string | https://tango.makegov.com | API base URL. Override for staging/local. |
timeoutMs | number | 30000 | Per-request timeout in milliseconds. Aborts with TangoTimeoutError. |
timeout | number | — | Ergonomic shorthand for timeoutMs (also in ms). If both are supplied, timeoutMs wins. |
retries | number | 3 | Number of retry attempts on retryable failures. Set to 0 to disable. Total attempts = retries + 1. |
retryBackoffMs | number | 250 | Initial backoff between retries (ms). Doubles each retry, capped at 10s. |
fetchImpl | typeof fetch | global fetch | Custom fetch implementation. Useful for proxies, instrumentation, or runtimes without a global fetch. |
Environment variables¶
| Env var | Purpose |
|---|---|
TANGO_API_KEY | Default API key when apiKey is not passed to the constructor. |
TANGO_BASE_URL | Default base URL when baseUrl is not passed. Falls through to https://tango.makegov.com if neither is set. |
Retry semantics¶
The client retries failed requests automatically. A request is retried when:
- The HTTP status is
5xx(any server error), - The status is
408(Request Timeout) or429(Too Many Requests), - Or the request fails at the network layer (DNS, connection refused, fetch network error, abort due to client-side timeout).
Other 4xx statuses (400, 401, 403, 404, …) are not retried — they're surfaced as the appropriate Tango* error immediately.
Backoff math¶
- First retry:
retryBackoffMs(default 250ms) - Second retry:
retryBackoffMs * 2 - Third retry:
retryBackoffMs * 4 - Each wait is capped at 10 seconds.
If the response includes a Retry-After header (typical on 429 and 503), the client honors that value instead of computing its own backoff:
- A delta-seconds value (
Retry-After: 5) → waits 5 seconds. - An HTTP-date value (
Retry-After: Wed, 21 Oct 2026 07:28:00 GMT) → waits until that time. - The honored wait is still capped at 10 seconds.
To disable retries entirely (e.g. for smoke tests or one-shot scripts where you'd rather see the raw failure):
const client = new TangoClient({
apiKey: process.env.TANGO_API_KEY,
retries: 0,
});
Error handling¶
All Tango errors extend TangoAPIError. Import them from the package root:
import {
TangoClient,
TangoAPIError,
TangoAuthError,
TangoNotFoundError,
TangoValidationError,
TangoRateLimitError,
TangoTimeoutError,
} from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
try {
const entity = await client.getEntity("ABCDEF123456");
console.log(entity);
} catch (err) {
if (err instanceof TangoNotFoundError) {
console.warn("No such entity");
} else if (err instanceof TangoValidationError) {
console.error("Bad request:", err.message, err.responseData);
} else if (err instanceof TangoAuthError) {
console.error("Check your API key");
} else if (err instanceof TangoRateLimitError) {
// The client already retried `retries` times before giving up.
console.error("Rate limited; back off harder");
} else if (err instanceof TangoTimeoutError) {
console.error("Request timed out; consider raising timeoutMs");
} else if (err instanceof TangoAPIError) {
console.error("API error:", err.statusCode, err.message);
} else {
throw err;
}
}
Every TangoAPIError carries:
message: string— human-readable; for 400s, the SDK extracts the firstdetail/message/error/ field-error from the response body when present.statusCode?: number— HTTP status (or408for client-side timeouts).responseData?: unknown— parsed JSON body of the error response (when the server returned JSON).
The client also throws TangoAPIError when an HTTP 200 response body contains { "error": "..." } — the Tango API occasionally signals errors in 200 payloads.
Custom fetch¶
Pass a custom fetchImpl to instrument requests, route through a proxy, or run in a non-Node runtime:
import { TangoClient } from "@makegov/tango-node";
const tracedFetch: typeof fetch = async (input, init) => {
const start = Date.now();
const res = await fetch(input, init);
console.log(`${init?.method ?? "GET"} ${input} → ${res.status} (${Date.now() - start}ms)`);
return res;
};
const client = new TangoClient({
apiKey: process.env.TANGO_API_KEY,
fetchImpl: tracedFetch,
});
Targeting staging or local¶
Point baseUrl at the host you want:
const client = new TangoClient({
apiKey: process.env.TANGO_API_KEY,
baseUrl: "http://localhost:8000",
});
The trailing slash on baseUrl is optional; the client normalizes it.