Skip to content
Docs · 2026-05-25

TL;DR — Base URL is https://api.jusinfer.com. Auth is Bearer token — either a long-lived jinf_ API key or a short-lived Firebase JWT. Inference endpoints are /v1/chat/completions and /v1/responses, both OpenAI-compatible. Rate limits are 60 RPM per key, 600 RPM per tenant.

jusInfer API reference

The jusInfer gateway is a thin OpenAI-compatible proxy in front of a model selector. Everything except /admin/* is open via CORS to browser callers and accepts CORS preflights for https://jusinfer.com, https://*.jusinfer.com, and http://localhost:*.

Base URL: https://api.jusinfer.com

Authentication

Two surfaces:

  • jinf_ keys — long-lived bearer tokens for code agents / CLIs. Mint at /developer.
  • Firebase JWT — short-lived ID token for first-party browser sessions on jusinfer.com. Used by the dashboard.

Both go in the Authorization header:

Authorization: Bearer <jinf_… or JWT>

Inference endpoints

POST /v1/chat/completions

OpenAI Chat Completions. Schema is the standard one — messages, tools, stream, etc. Add anything OpenAI accepts and it'll be forwarded if the underlying model supports it.

Request:

{
  "model": "jusInfer-auto",
  "messages": [
    {"role": "system", "content": "You are concise."},
    {"role": "user", "content": "Write a haiku about gradients."}
  ],
  "stream": false,
  "temperature": 0.7
}

Response (non-stream):

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1779000000,
  "model": "jusInfer-auto",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "..."},
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 23,
    "completion_tokens": 17,
    "total_tokens": 40,
    "cost": 0.000086
  }
}

usage.cost is in USD and is always present on jusInfer responses, even when the upstream model doesn't report cost — we compute it from token counts × per-model rate.

POST /v1/responses

OpenAI Responses API. Same auth, similar shape. Use this if your harness prefers the newer surface.

Request:

{
  "model": "jusInfer-auto",
  "input": "Summarize the Goldilocks zone."
}

The gateway translates input into chat-style messages internally; the underlying selection logic is identical.

Identity / onboarding

POST /v1/onboard (JWT only)

Idempotent first-time setup. Creates a tenant for a Firebase user if they don't have one. The dashboard calls this on every sign-in.

// → 200
{
  "tenant_id": "ten_...",
  "user_id": "usr_...",
  "is_new": false,
  "balance": 0
}

GET /v1/keys/self

Returns the calling identity — works with both auth surfaces. Useful for client introspection.

{
  "auth_kind": "jcg",
  "user": {"id": "usr_...", "email": "..."},
  "tenant": {"id": "ten_...", "name": "...", "balance": 1000000},
  "key": {"token_hash": "...", "name": "VS Code on macbook", "created_at": 1779000000}
}

Key management (JWT only)

MethodPathWhat
POST/v1/keysMint a new jinf_ key. Body: { name?, client_label?, expires_in_days? }. Returns plaintext once.
GET/v1/keysList your keys (without plaintext).
DELETE/v1/keys/:hashRevoke.
POST/v1/keys/:hash/rotateRevoke + mint replacement preserving name/label/scope.

Usage

MethodPathWhat
GET/v1/usage/me?days=30Per-day usage for the calling user.
GET`/v1/usage/tenant?days=30&group_by=dayuser

Tenant & invites (JWT only)

MethodPathWhat
GET/v1/tenantTenant info + balance.
POST/v1/tenant/renameRename.
GET/v1/tenant/membersList members + caps.
POST/v1/tenant/members/:id/capSet per-user soft monthly cap.
POST/v1/tenant/members/:id/removeRemove member (owner only).
POST/v1/tenant/transfer-ownershipTransfer to another member.
POST/v1/tenant/invitesSend Resend invite email.
GET/v1/tenant/invitesList pending invites.
DELETE/v1/tenant/invites/:idCancel pending invite.
POST/v1/tenant/invites/:id/resendResend.
POST/v1/invites/acceptAccept invite with token (email-match guard).

Billing

MethodPathWhat
GET/v1/billing/packsList credit packs ($5/$10/$25/$50).
GET/v1/billing/purchasesHistory — includes presentment currency when not USD.
POST/v1/billing/checkoutCreate Stripe Checkout for a pack.
GET/v1/billing/seatsSeat-sub status + entitlement check ({ok:true} or {ok:false, code}).
POST/v1/billing/seats/checkoutCreate seat subscription.
POST/v1/billing/seats/updateChange seat count.
POST/v1/billing/seats/cancelCancel at period end.

Store

MethodPathWhat
POST/v1/store/preorderReserve a pre-order. No auth required; if JWT supplied, links to user. Body: {product_id, product_name, email, size, qty}.

Errors

All errors are JSON with code (machine-readable) and error (human):

{ "code": "INSUFFICIENT_CREDITS", "error": "Wallet has $0.01; this call needs $0.02." }

Common codes:

CodeStatusMeaning
MISSING_TOKEN401No Authorization header
INVALID_KEY401jinf_ key unknown / revoked / expired
INVALID_TOKEN401JWT verification failed
NEEDS_ONBOARD401Valid JWT but no tenant — call POST /v1/onboard
JWT_REQUIRED403Endpoint requires JWT, not jinf_
OWNER_REQUIRED403Endpoint requires tenant owner
SEAT_REQUIRED403Multi-member tenant needs seat subscription
INSUFFICIENT_CREDITS402Wallet empty; top up
USER_CAP_EXCEEDED402Per-user soft cap reached this month
RATE_LIMIT42960/min per key, 600/min per tenant
INVALID_EMAIL / INVALID_SIZE / ALREADY_RESERVED400/409Store endpoint validation
UPSTREAM_ERROR502Upstream model temporarily unavailable

Rate limits

  • Per key: 60 requests per minute
  • Per tenant: 600 requests per minute

Raisable per-tenant by request — DM us once you're consistently bumping the cap.

CORS

Allowed origins:

  • https://jusinfer.com
  • https://www.jusinfer.com
  • https://jusinfer-bd8e5.web.app
  • https://jusinfer-bd8e5.firebaseapp.com
  • http://localhost:3000
  • http://localhost:5173

/admin/* is not CORS-enabled — server-to-server only.

Versioning

The gateway uses path-level versioning (/v1/...). Breaking changes get /v2/.... usage.cost and other extensions stay backwards-compatible.


Agent-readable raw markdown: /docs/api-reference.md