Consuming the API
Call a Farther Shore gateway route with a subscriber key and handle stable denials.
Subscribers call the Farther Shore business gateway, not your direct backend origin. The gateway resolves the subscriber, plan, environment, route, limits, and backend, then signs and forwards an admitted request.
Send the subscriber key
The default business API-key header is x-api-key. If the business contract
sets a different authHeader, use that exact header instead.
async function createJob(apiKey: string, input: unknown) {
const response = await fetch("https://<business-gateway-host>/v1/jobs", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": apiKey,
},
body: JSON.stringify(input),
});
if (response.ok) return response.json();
const body = await response.json().catch(() => ({}));
throw new BusinessApiError(response.status, body);
}
Use a test key and preview gateway for preview environments and a live key for Main. Do not send a runtime token, CLI credential, or provider secret to a business route.
Handle a denial as data
Denied requests return a stable machine-readable code. Usage-limit denials
also include an _fs envelope that tells a client what kind of limit fired and
what reaction is appropriate:
{
"error": "Too many requests in flight.",
"code": "concurrency_limit_exceeded",
"_fs": {
"limitClass": "concurrency",
"reaction": "queue",
"limitOrigin": "platform",
"retrySafe": true,
"mustModify": false,
"decisionId": "dec_8a91…",
"requestId": "req_2c7f…",
"envelopeVersion": 1
}
}
Branch on _fs.limitClass, _fs.reaction, retrySafe, and mustModify; do not
infer the remedy only from the HTTP status.
| Limit class | Typical response |
|---|---|
rate, concurrency, adaptive | Honor Retry-After; retry the same request only when retrySafe is true |
capacity | Reduce or change the request before retrying |
quota, spend | Upgrade, top up, or wait for the applicable reset; blind retries do not help |
async function handleDeny(response: Response) {
const body = await response.json().catch(() => ({}));
const detail = body._fs;
if (!detail) throw new Error(body.code ?? `HTTP ${response.status}`);
if (detail.retrySafe) {
const seconds = Number(response.headers.get("retry-after") ?? 1);
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
return { retry: true };
}
if (detail.reaction === "upgrade") return { upgrade: true };
if (detail.mustModify) return { modifyRequest: true };
return { code: body.code, decisionId: detail.decisionId };
}
Always bound retries, add jitter, and preserve the operation's own idempotency key when retrying a write.
Upstream responses
An admitted request normally returns your backend's response status, body, and
safe headers. Farther Shore consumes internal signing and metering headers; they
are not an application API. A 503 origin_unavailable means the selected
environment has no usable backend binding or tunnel connection. It is an
operator problem, not a subscriber authentication failure.
Use the denial requestId or decisionId when correlating a subscriber report
with platform and backend diagnostics. Never include API keys or runtime tokens
in logs.