Référence API · Router

Une API unique pour 40+ modèles IA, avec Guard anti-exfiltration.

Router remplace api.openai.com par une URL unique qui route vers Anthropic, OpenAI, Google, Cohere, Mistral et plus. Guard filtre les PII, secrets et tokens avant l'envoi. Facturation unique en CAD.

Version
0.109.0
Base URL
router.signalorange.ca
Authentification
Bearer token
Formats
JSON · SSE
Authentification

Bearer token sur chaque requête

Générez une clé API depuis votre tableau de bord Meridian, puis passez-la dans l'en-tête Authorization de chaque requête.

headers · auth
Authorization: Bearer $ROUTER_API_KEY\nContent-Type: application/json
  1. 1 Connectez-vous à votre tableau de bord Meridian: https://meridian.signalorange.ca/login.
  2. 2 Paramètres → Clés API → Nouvelle clé. Donnez-lui un nom (ex. production), puis copiez-la immédiatement — elle ne sera plus affichée.
  3. 3 Stockez-la comme variable d'environnement (ROUTER_API_KEY), dans un gestionnaire de secrets, ou dans votre .env local.
Endpoints

Référence par fonctionnalité

Extraite automatiquement depuis la spec OpenAPI servie à /api/router/docs/spec.json. Toute modification dans les contrôleurs se reflète ici dès la prochaine requête.

API Keys

GET /api/router/v1/api_keys

List API keys for the authenticated organization

Returns all active + revoked keys belonging to your organization. The secret token is never returned.

Réponses
  • 200 API keys
POST /api/router/v1/api_keys

Create a new API key

Creates a new API key attached to the authenticated organization + the user associated with the calling key. Response includes the **raw token** in the `key` field — **this is the only time it is returned.** Store it immediately. A standard-scope calling key cannot create super_admin keys.

Corps de la requête application/json
  • name string requis — Human-friendly identifier
  • expires_at string — Optional — ISO-8601 expiration date
  • scope string
Réponses
  • 201 Created
  • 403 Scope escalation blocked
  • 422 Validation error
DELETE /api/router/v1/api_keys/{id}

Revoke an API key (soft delete)

Sets is_active=false on the key. Audit history is preserved; the key can no longer authenticate any request.

Paramètres
  • id path integer requis —
Réponses
  • 200 Revoked
  • 404 Not found
PATCH /api/router/v1/api_keys/{id}

Update an API key (name, expires_at only)

Only `name` and `expires_at` are mutable via the API. Scope and user_id are immutable.

Paramètres
  • id path integer requis —
Corps de la requête application/json
  • expires_at string
  • name string
Réponses
  • 200 Updated
  • 404 Not found
  • 422 Validation error

Audit

GET /api/router/v1/audit

List recent Guard audit entries

Returns the most recent Guard audits for the authenticated organization, newest first. Supports pagination + filtering. ## Query parameters - `limit` — max rows (default 50, cap 500) - `offset` — skip N (for pagination) - `halted_only` — `true` to only return blocked requests - `min_severity` — `critical|high|medium|low`; at least one detection at or above this level - `from` — ISO-8601 lower bound on inserted_at (inclusive) - `to` — ISO-8601 upper bound (exclusive)

Paramètres
  • limit query integer — Default 50, max 500
  • offset query integer —
  • halted_only query boolean —
  • min_severity query string —
  • from query string — ISO-8601 datetime
  • to query string — ISO-8601 datetime
Réponses
  • 200 Audit entries
GET /api/router/v1/audit/{request_id}

Get a Guard audit entry by request_id

Returns the Guard audit row for a specific Router request. `request_id` is the `generation_id` returned in the chat/completions response (available at `result.guard.request_id`) or the `stream-...`/`halt-...` id generated internally for streaming or halted requests. 404 if not found or if the audit belongs to a different organization.

Paramètres
  • request_id path string requis — The Router generation_id / audit request_id
Réponses
  • 200 Audit entry with detections
  • 404 Audit not found

Billing

GET /api/router/v1/billing/balance

Current credit balance

Returns your organization's prepaid credit balance in CAD cents.

Réponses
  • 200 Balance
GET /api/router/v1/billing/models

List available models

Returns every model routable through Router for your organization, with provider and pricing tier. Unrestricted organizations (default) see the whole synced OpenRouter catalog; restricted organizations only see their platform models.

Réponses
  • 200 Models
GET /api/router/v1/billing/usage

Usage summary

Returns aggregated usage and a per-model breakdown for the current organization.

Réponses
  • 200 Usage

Chat

POST /api/v1/chat/completions

Chat completions (OpenAI-compatible)

Generate a chat completion. Drop-in replacement for `POST https://api.openai.com/v1/chat/completions`. Routes the request through Meridian's Router with Guard anti-exfiltration enabled. Supports `auto` model selection (Router picks the cheapest model meeting your quality bar) or an explicit model id (e.g. `claude-sonnet-4`, `gpt-5`). Set `stream: true` to receive server-sent events with OpenAI-compatible `chat.completion.chunk` payloads terminated by `data: [DONE]`.

Corps de la requête application/json
  • messages array requis — Conversation messages, oldest first. `content` can be a string or an array of parts (vision multimodal).
  • max_tokens integer
  • model string — Model id (e.g. `claude-sonnet-4`, `gpt-5`) or `auto`
  • no_retention boolean — When `true`, Router skips prompt persistence (Guard audit) and asks the provider not to retain or train on the request (`provider.data_collection = deny`). Models that cannot guarantee this are rejected with HTTP 400 instead of being served. Same effect via the `X-No-Retention: true` header.
  • response_format object — Set `{"type": "json_object"}` for JSON mode, or `{"type": "json_schema", "json_schema": {"name": ..., "schema": {...}}}` for structured outputs. `json_schema` is enforced natively on OpenAI/Anthropic models and server-validated (HTTP 422 `schema_validation_failed`) on the others.
  • response_format.json_schema object — Required when `type` is `json_schema`
  • response_format.type string
  • stream boolean — When `true`, the response is streamed as Server-Sent Events with OpenAI-compat chunks
  • strict boolean — When `true`, disables Router's automatic model fallback. If the requested model is unavailable, the request fails (HTTP 502) instead of silently falling back to an alternative.
  • system string — System prompt (alternative to embedding in messages)
  • temperature number
  • tool_choice any — How the model picks tools: `"none"`, `"auto"`, `"required"`, or `{"type": "function", "function": {"name": "..."}}`
  • tools array — Array of tool/function definitions available to the model (OpenAI-compat). `{"type": "web_search"}` and `{"type": "fetch"}` are Router server tools: executed by the Router during the conversation, reported in `tool_executions`.
Réponses
  • 200 Completion result (non-streaming) or SSE stream (streaming)
  • 402 Insufficient credits
  • 403 AI not enabled for organization
  • 429 Rate limited
  • 502 Upstream provider error
POST /api/v1/chat/completions/estimate

Estimate cost of a chat completion (preflight, no upstream call)

Returns the expected CAD cost of a chat completion without actually calling the upstream model. Uses a `char_count/4` heuristic for prompt tokens and the request's `max_tokens` as the completion budget. Useful for UI budget checks or for clients that need to price per request before consenting to the actual call. Pricing reflects the organization's current markup + FX rate.

Corps de la requête application/json
  • messages array requis
  • max_tokens integer
  • model string
  • system string
Réponses
  • 200 Estimate

Classify

POST /api/v1/classify

Classify text against labels (~typesafe/jev-latest)

Deterministic classification with scores. `single` returns probabilities summing to 1; `multi` returns independent 0..1 scores; `binary` answers a yes/no question (`score` = probability of yes). Billed at the real upstream cost of the Jev decisions call.

Corps de la requête application/json
  • input string requis
  • mode string requis
  • model string requis
  • options array — 1..255 entries. Required in single/multi mode.
  • question string — Requis en mode `binary` : question fermée (oui/non) posée sur `input`. La réponse donne `answer` (booléen) et `score` = probabilité de « oui ». Ignoré en mode single/multi.

Exemple

{
  "input": "Disjoncteur QO120 20 A 1 pôle",
  "mode": "binary",
  "model": "~typesafe/jev-latest",
  "question": "Ce produit est-il un disjoncteur ?"
}
Réponses
  • 200 Classification result

Embeddings

POST /api/v1/embeddings

Create embeddings (OpenAI-compatible)

Generate vector embeddings for a string or a list of strings. Drop-in replacement for `POST https://api.openai.com/v1/embeddings`. Default model is `openai/text-embedding-3-small`. Specify `model` explicitly to use another embeddings model (e.g. `openai/text-embedding-3-large`, `cohere/embed-multilingual-v3.0`).

Corps de la requête application/json
  • input any requis — String or array of strings to embed
  • model string — Embeddings model id
Réponses
  • 200 Embeddings result
  • 402 Insufficient credits
  • 403 AI not enabled for organization
  • 429 Rate limited
  • 502 Upstream provider error

Models

GET /api/v1/models

List available models (OpenAI-compatible)

Returns the Router model catalog for your organization in OpenAI's list format. Use this endpoint from SDKs that call `client.models.list()`; the richer `/billing/models` endpoint stays available with Meridian-specific fields (tier, display_name, etc.). By default every synced OpenRouter model is listed. An organization can restrict its Router surface to its platform models (`/router/settings/ai`) — restricted orgs only see platform-active models here. Beyond the OpenAI fields (`id`, `object`, `created`, `owned_by`), each entry carries `context_length` (tokens, `null` when unknown), `pricing` (input/output CAD per 1M tokens with your org's markup + FX applied, `null` when the model is unpriced) and `supported_parameters` (what Router accepts for this model).

Réponses
  • 200 Model list

Tools

POST /api/v1/tools/fetch

Fetch a URL as raw text (Artemis enrichment)

Fetches a public `http(s)` URL server-side and returns its integral raw text (tags stripped, never summarized — numbers and units kept as-is), truncated at `max_chars`. HTML yields `title` + absolute `images`; PDFs yield `text` + `pages`. A distant 4xx/5xx returns `200` with the distant `status` and `text: ""`. Optional enrichment: `main_content` keeps only the main content in `text`; `structured_data` adds `structured_data.products[]` read from the received HTML; `document_links` adds the page's PDF links (spec sheets, guides, certificates); `highlights` adds verbatim passages for `query`; `summary` adds a schema-conformant object built from the page only. Without these parameters the response is identical to the legacy one. Enriched results are cached ~24 h (a cache hit is free) and `billing.cost_cad` sums transfer + Exa + LLM. The summary never fails the fetch: at worst `summary: null` with `summary_error`.

Corps de la requête application/json
  • url string requis — Public http(s) URL to fetch
  • document_links boolean — Ajoute `document_links: [{url, text}]` : liens PDF de toute la page (pas seulement du contenu principal), chemin en `.pdf` ou `type="application/pdf"`. `url` absolue (résolue contre `final_url`), sans fragment ni doublon ; `text` = texte du lien, sinon `title` ou `aria-label`, sinon `null`. Ordre de la page, 50 au plus ; `[]` pour un PDF lu directement ou une page distante en erreur.
  • highlights object — Ajoute `highlights: [string]` : passages copiés mot pour mot, les plus pertinents pour `query`.
  • highlights.query string requis — Ce que les passages doivent couvrir
  • highlights.max_chars integer — Total maximal de caractères des passages
  • main_content boolean — Contenu principal seulement dans `text` (sans navigation, en-tête, pied de page, barres latérales ni bandeau de témoins). Exa /contents, sinon extraction locale.
  • max_chars integer — Max characters of returned text (default 200000)
  • render_js boolean — JS rendering is NOT supported (true → 400)
  • structured_data boolean — Ajoute `structured_data.products[]` lus dans le HTML reçu (JSON-LD avec @graph et ProductGroup/hasVariant, microdonnées, RDFa, OpenGraph) : {name, brand, mpn, sku, model, product_id, gtins, description, url, image, variants[]}. GTIN en chiffres seulement ; variantes seulement dans `variants`.
  • summary object — Ajoute `summary` conforme à `schema` (JSON Schema strict, racine `object`). Un nouvel essai au plus ; ensuite `summary: null` et `summary_error`. Le fetch n'échoue jamais à cause du résumé.
  • summary.schema object requis — JSON Schema strict de la sortie
  • summary.query string — Ce que le résumé doit couvrir

Exemple

{
  "document_links": true,
  "highlights": {
    "max_chars": 1500,
    "query": "ampérage pouvoir de coupure dimensions"
  },
  "main_content": true,
  "max_chars": 20000,
  "structured_data": true,
  "summary": {
    "query": "Caractéristiques techniques du disjoncteur",
    "schema": {
      "additionalProperties": false,
      "properties": {
        "amperage_a": {
          "type": [
            "number",
            "null"
          ]
        },
        "interrupting_rating_ka": {
          "type": [
            "number",
            "null"
          ]
        },
        "poles": {
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "required": [
        "amperage_a",
        "poles",
        "interrupting_rating_ka"
      ],
      "type": "object"
    }
  },
  "url": "https://www.exemple-distributeur.ca/produits/qo120"
}
Réponses
  • 200 Fetched page
POST /api/v1/tools/web_search

Web search (Artemis enrichment)

Runs a server-side web search and returns ranked results (`url`, `title`, `snippet`) plus a `billing` cost computed like LLM usage (provider USD cost through the org markup + FX). The backend is env-configurable; without a key the stub backend returns zero results.

Corps de la requête application/json
  • query string requis
  • country string — Country code hint (default ca)
  • lang string — Optional result language hint
  • max_results integer — Number of results (1..10, default 8)
Réponses
  • 200 Search results

Besoin d'un SDK ou d'une clé API ?

Router est compatible avec les SDK OpenAI officiels (Python, Node, Go) — changez simplement base_url. Pour un accès, écrivez-nous.

[email protected] →