Point de terminaison API https://northerninference.ca/v1 Utilisez ceci comme URL de base dans chaque intégration.

Libre-service pour agents d'IA

Comment un agent d'IA demande l'accès à un compte Inférence Nordique, obtient l'approbation du titulaire et gère lui-même ses clés d'inférence au moyen d'une API documentée.

Inférence Nordique est une API d'IA souveraine canadienne pour les équipes du gouvernement, de la défense, de la santé et des secteurs réglementés, y compris les organisations relevant du Programme des marchandises contrôlées. Chaque route comporte une résidence des données au Canada conforme à la LPRPDE, un chemin exact vers les derniers modèles de pointe et à poids ouverts, ainsi qu'un registre de chaîne de possession par requête.

En quoi consiste le libre-service pour agents

Un agent d'IA peut demander l'accès à un compte Inférence Nordique, obtenir l'approbation du titulaire du compte, puis gérer lui-même les clés d'inférence de ce compte. Lorsque l'exploitant a activé les paiements des agents, l'agent peut aussi lancer l'ajout d'une carte ou un achat de crédits que le titulaire termine sur Stripe. L'agent ne détient jamais le mot de passe du titulaire, une session de navigateur ni les données d'une carte. Le titulaire garde le contrôle : rien n'est accordé tant que la personne à qui appartient l'adresse courriel n'a pas approuvé la demande, et rien n'est facturé à moins que le titulaire ne paie sur Stripe.

L'API des agents se trouve sous https://northerninference.ca/api/agent/v1/. Elle utilise deux justificatifs distincts, et aucun ne remplace l'autre :

JustificatifPréfixeCe qu'elle fait
Justificatif de gestionni_mgmt_Gère le compte au moyen de /api/agent/v1/ : lit le compte, crée, liste, modifie, fait pivoter et révoque des clés d'inférence et, avec les portées de paiement, lance l'ajout d'une carte et des achats de crédits que le titulaire termine. Il ne peut pas appeler de modèles.
Clé d'inférenceni_live_Appelle les modèles sur l'API compatible avec OpenAI et avec Anthropic à l'adresse https://northerninference.ca/v1. Elle ne peut pas modifier le compte.

La description lisible par machine de chaque point de terminaison de cette page est agent-openapi.yaml (OpenAPI 3.1). Un résumé destiné aux agents se trouve dans llms.txt.

Les étapes

  1. Générez un vérificateur PKCE aléatoire et son défi S256.
  2. Envoyez POST /api/agent/v1/enrollments avec l'adresse courriel du titulaire, une étiquette pour votre agent, les portées souhaitées et le défi.
  3. Le titulaire reçoit un courriel, ouvre la page d'approbation et approuve. Un nouveau titulaire commence par choisir un mot de passe et accepter les documents juridiques.
  4. Interrogez GET /api/agent/v1/enrollments/{id} jusqu'à ce que le statut soit approved.
  5. Envoyez POST /api/agent/v1/enrollments/{id}/claim avec le vérificateur. La réponse contient le justificatif ni_mgmt_, affiché une seule fois.
  6. Créez une clé d'inférence avec POST /api/agent/v1/keys. Le secret ni_live_ est affiché une seule fois.
  7. Alimentez le compte : lancez un achat de crédits avec POST /api/agent/v1/billing/topups. Inférence Nordique envoie le lien Stripe au titulaire par courriel, et celui-ci paie sur Stripe.
  8. Interrogez l'achat jusqu'à ce qu'il soit payé, puis appelez les modèles avec la clé ni_live_.

1. Générer un vérificateur et un défi

Le vérificateur est une chaîne aléatoire de 43 à 128 caractères parmi A-Z a-z 0-9 - . _ ~. Gardez-le secret : c'est lui qui prouve que la réclamation provient de l'agent qui a fait la demande. Le défi est le SHA-256 du vérificateur, encodé en base64url sans remplissage, toujours de 43 caractères.

CODE_VERIFIER=$(openssl rand -hex 32)
CODE_CHALLENGE=$(printf %s "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
echo "$CODE_CHALLENGE"

La même chose en Python :

import base64, hashlib, secrets

code_verifier = secrets.token_urlsafe(64)  # 86 characters
code_challenge = base64.urlsafe_b64encode(
    hashlib.sha256(code_verifier.encode("ascii")).digest()
).rstrip(b"=").decode("ascii")

2. Demander l'accès

Envoyez un en-tête Idempotency-Key de 8 à 200 caractères ASCII imprimables. Répéter la même demande avec la même clé renvoie la même inscription et n'envoie pas de second courriel. La même clé avec une demande différente est refusée avec 409 idempotency_key_reused.

curl -sS https://northerninference.ca/api/agent/v1/enrollments \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "email": "owner@example.org",
    "agent_label": "Release notes agent",
    "scopes": ["account:read", "keys:read", "keys:write"],
    "code_challenge": "'"$CODE_CHALLENGE"'",
    "code_challenge_method": "S256",
    "account_name": "Example Org"
  }'

agent_label compte de 1 à 80 caractères et est montré au titulaire. account_name est facultatif et sert seulement à nommer un nouveau compte. La réponse est 202 Accepted et a la même forme, que l'adresse ait déjà un compte ou non :

{
  "enrollment_id": "0b5c1d2e-7a54-4f55-9d3e-2c7f1d6a8e10",
  "status": "pending",
  "expires_at": "2026-10-13T15:04:05+00:00",
  "agent_label": "Release notes agent",
  "scopes": ["account:read", "keys:read", "keys:write"],
  "owner_action": "Nothing is granted until the owner of this email address approves the request from the email Northern Inference sends them. Poll status_url, then claim.",
  "status_url": "/api/agent/v1/enrollments/0b5c1d2e-7a54-4f55-9d3e-2c7f1d6a8e10",
  "claim_url": "/api/agent/v1/enrollments/0b5c1d2e-7a54-4f55-9d3e-2c7f1d6a8e10/claim"
}

La demande reste ouverte pendant 24 heures. Une seule demande par adresse courriel peut être en attente à la fois.

3. Le titulaire approuve

Inférence Nordique envoie au titulaire un lien à usage unique vers /agent-approve.html. La page présente l'étiquette de l'agent et ce que permet chaque portée. Rien ne se produit au chargement de la page : le titulaire doit cliquer. Un nouveau titulaire choisit un mot de passe et accepte les versions en vigueur des Conditions d'utilisation, de la Politique de confidentialité et de la Politique d'utilisation acceptable. Un titulaire existant ouvre d'abord une session et passe la vérification à deux facteurs si elle est configurée. Le titulaire peut aussi refuser. L'agent ne peut pas approuver sa propre demande.

4. Interroger le statut

curl -sS https://northerninference.ca/api/agent/v1/enrollments/$ENROLLMENT_ID

La réponse contient les mêmes champs qu'à l'étape 2. status vaut pending, approved, declined, expired ou claimed. Interrogez au plus toutes les quelques secondes : le point de terminaison de statut accepte 240 appels par heure par adresse IP. Arrêtez-vous à declined ou expired et présentez une nouvelle demande si le titulaire le souhaite toujours.

5. Réclamer le justificatif

curl -sS -X POST https://northerninference.ca/api/agent/v1/enrollments/$ENROLLMENT_ID/claim \
  -H "Content-Type: application/json" \
  -d '{"code_verifier": "'"$CODE_VERIFIER"'"}'
{
  "credential": "ni_mgmt_...",
  "token_type": "Bearer",
  "credential_id": "5f0e3c1a-9b1d-4c0e-8a55-61c7d0f2b3a4",
  "key_prefix": "ni_mgmt_AbCdEfGh",
  "scopes": ["account:read", "keys:read", "keys:write"],
  "expires_at": "2027-01-10T15:09:41+00:00",
  "note": "Shown once. Northern Inference keeps only a hash and cannot show it again."
}

Conservez le justificatif immédiatement. Inférence Nordique n'en garde qu'une empreinte et ne l'affiche qu'une seule fois; une seconde réclamation répond 409 already_claimed sans aucun secret. Un justificatif dure 90 jours. Les portées ne peuvent pas être élargies par la suite : pour en obtenir davantage, présentez une nouvelle demande.

6. Gérer les clés

Envoyez le justificatif sous la forme Authorization: Bearer ni_mgmt_....

export NI_MGMT=ni_mgmt_YOUR_CREDENTIAL

# Read the account (account:read)
curl -sS https://northerninference.ca/api/agent/v1/account \
  -H "Authorization: Bearer $NI_MGMT"

# List keys (keys:read)
curl -sS https://northerninference.ca/api/agent/v1/keys \
  -H "Authorization: Bearer $NI_MGMT"

# Create a key (keys:write). Idempotency-Key is required.
curl -sS https://northerninference.ca/api/agent/v1/keys \
  -H "Authorization: Bearer $NI_MGMT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "release-notes-agent",
    "allowed_privacy_tiers": ["managed_canadian_cloud"],
    "max_rpm": 60,
    "max_budget_cents": 500
  }'

Une première création répond 201 avec les paramètres de la nouvelle clé et, une seule fois, le secret dans key :

{
  "id": "c9d8e7f6-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
  "key_prefix": "ni_live_AbCd",
  "name": "release-notes-agent",
  "allowed_privacy_tiers": ["managed_canadian_cloud"],
  "max_rpm": 60,
  "max_budget_cents": 500,
  "...": "other key settings",
  "key": "ni_live_...",
  "secret_already_issued": false
}

Si la réponse est perdue, une nouvelle tentative avec le même Idempotency-Key et le même corps répond 200 avec les paramètres de la clé et "secret_already_issued": true. Elle ne renvoie jamais le secret de nouveau et ne crée jamais de seconde clé. Pour récupérer l'accès, faites pivoter la clé.

# Change settings (keys:write). Only the fields you send change.
curl -sS -X PATCH https://northerninference.ca/api/agent/v1/keys/$KEY_ID \
  -H "Authorization: Bearer $NI_MGMT" \
  -H "Content-Type: application/json" \
  -d '{"max_rpm": 30}'

# Rotate (keys:write). Idempotency-Key is required. The new key keeps the old
# key's settings. The old key keeps working for 24 hours, then expires.
curl -sS -X POST https://northerninference.ca/api/agent/v1/keys/$KEY_ID/rotate \
  -H "Authorization: Bearer $NI_MGMT" \
  -H "Idempotency-Key: $(uuidgen)"

# Revoke a key (keys:write)
curl -sS -X DELETE https://northerninference.ca/api/agent/v1/keys/$KEY_ID \
  -H "Authorization: Bearer $NI_MGMT"

# End this credential (any scope)
curl -sS -X DELETE https://northerninference.ca/api/agent/v1/credential \
  -H "Authorization: Bearer $NI_MGMT"

Un agent peut définir le nom d'une clé, ses niveaux de confidentialité autorisés (managed_canadian_cloud pour les routes canadiennes du Niveau 3, provider_api pour le Niveau 4), sa liste de routes autorisées, ses limites de débit (max_rpm, max_tpm), son plafond de dépenses (max_budget_cents), son mode de rétention zéro des données (enforce, prompt ou allow) et, à la création, une date d'expiration. Les clés de fournisseur apportées par le client et les commutateurs d'affichage propres à chaque clé restent au titulaire, dans le portail.

7. Appeler les modèles

Utilisez la clé ni_live_ exactement comme dans le guide curl :

curl https://northerninference.ca/v1/chat/completions \
  -H "Authorization: Bearer $NI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"ROUTE_ID","messages":[{"role":"user","content":"hi"}],"max_tokens":20}'

Copiez la route exacte depuis https://northerninference.ca/api/billing/models (aucune clé requise) ou GET /v1/models.

Approvisionnement

Un compte créé par un agent démarre sans crédit, et l'inférence exige un solde approvisionné. Un agent qui détient les portées de paiement peut lancer l'approvisionnement, mais le titulaire le termine toujours sur Stripe. Inférence Nordique envoie le lien Stripe au titulaire par courriel. L'agent ne reçoit jamais le lien et ne voit ni ne saisit jamais les données d'une carte. Si les paiements des agents sont désactivés sur ce service, les appels de facturation répondent 403 agent_billing_disabled et les portées de paiement ne peuvent pas être demandées.

Les portées de paiement sont billing:read (voir si un mode de paiement est configuré, ainsi que les paiements), billing:setup (commencer l'ajout d'un mode de paiement) et billing:topup (commencer un achat de crédits). Demandez celles dont vous avez besoin lorsque vous demandez l'accès; le titulaire voit chacune en langage clair.

Commencer un achat de crédits

curl -sS https://northerninference.ca/api/agent/v1/billing/topups \
  -H "Authorization: Bearer $NI_MGMT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount_cents": 2500}'

amount_cents est le montant de crédits à acheter, un nombre entier à partir de 2500 (25,00 $ CA) jusqu'à 500 $ CA par défaut. N'envoyez rien d'autre : un corps de requête contenant un champ de carte est refusé. Le titulaire reçoit un courriel indiquant les crédits, les frais de service et le total, avec un bouton pour payer sur Stripe. La réponse est 201 :

{
  "payment_id": "165d9622-8413-4ac1-9d89-22e199b6b8ca",
  "display_status": "open_unpaid",
  "session_id": "cs_live_...",
  "expires_at": "2026-10-13T03:39:38+00:00",
  "currency": "cad",
  "amount_cents": "2500",
  "fee_cents": "225",
  "charge_cents": "2725",
  "replayed": false,
  "delivery": "owner_email"
}

Les champs monétaires sont des chaînes décimales exactes. charge_cents correspond aux crédits plus les frais de service avant taxes, que Stripe ajoute sur sa page. La réponse ne contient aucun lien de paiement : n'en cherchez pas. delivery indique ce qu'est devenu le courriel :

deliverySignification
owner_emailLe courriel a été envoyé au titulaire du compte.
email_failedL'achat existe, mais le courriel n'a pas pu être envoyé. Répétez exactement la même requête avec le même Idempotency-Key pour réessayer l'envoi. Aucun deuxième achat n'est créé.
sendingUne autre requête l'envoie en ce moment. Vérifiez de nouveau sous peu.
not_sentAucun courriel n'a été envoyé et aucun ne le sera, car l'achat a pris fin avant. Lancez-en un nouveau.

Une nouvelle tentative avec le même Idempotency-Key et le même corps de requête renvoie 200 avec le même achat et n'envoie pas de deuxième courriel. La même clé avec un corps différent est refusée avec 409 idempotency_key_reused.

Interroger l'achat

curl -sS https://northerninference.ca/api/agent/v1/billing/topups/$PAYMENT_ID \
  -H "Authorization: Bearer $NI_MGMT"

Cet appel exige billing:read et lit les propres registres d'Inférence Nordique, jamais Stripe; vous pouvez donc l'interroger toutes les quelques secondes. display_status vaut open_unpaid tant que le titulaire n'a pas payé, puis processing, puis succeeded avec credited: true une fois les crédits ajoutés au solde. expired_unpaid signifie que le lien a pris fin sans paiement (les liens durent 60 minutes par défaut); lancez un nouvel achat si le titulaire en veut encore un. last_attempt_failed: true signifie que la carte du titulaire a été refusée et que le lien est toujours ouvert. GET /api/agent/v1/account indique ensuite le nouveau available_balance_cents.

Ajoutez un mode de paiement

curl -sS -X POST https://northerninference.ca/api/agent/v1/billing/setup-sessions \
  -H "Authorization: Bearer $NI_MGMT" \
  -H "Idempotency-Key: $(uuidgen)"

# Poll it (billing:read). status: open, processing, completed or expired.
curl -sS https://northerninference.ca/api/agent/v1/billing/setup-sessions/$SETUP_ID \
  -H "Authorization: Bearer $NI_MGMT"

Cet appel exige billing:setup et envoie au titulaire un courriel avec un bouton pour ajouter une carte sur Stripe. Ni l'agent ni Inférence Nordique ne voit le numéro de la carte, et l'ajout d'une carte ne la débite pas. La réponse et les règles de livraison sont les mêmes que pour un achat. Les agents ne peuvent pas activer la recharge automatique ni débiter une carte enregistrée : chaque achat est terminé par le titulaire.

Lire l'état de la facturation

curl -sS https://northerninference.ca/api/agent/v1/billing \
  -H "Authorization: Bearer $NI_MGMT"

Cet appel exige billing:read et affiche le solde, les conditions de recharge, les achats ouverts, les 10 derniers paiements et la carte enregistrée (marque, quatre derniers chiffres et expiration). La carte est lue en direct auprès de Stripe, dans la limite de 4 lectures par heure et par compte; pour savoir si une opération est terminée, interrogez donc les points d'accès de l'achat ou de l'ajout de carte, pas celui-ci.

Ce que le titulaire voit après Stripe

Stripe renvoie le titulaire vers https://northerninference.ca/agent-payment.html, une page temporaire qui indique si le paiement a été reçu, est en cours de traitement ou a expiré. La page est destinée au titulaire, pas à l'agent. Elle pose à Inférence Nordique une seule question sur la session Stripe et n'affiche ni montant, ni nom, ni carte. L'agent doit plutôt interroger les points d'accès ci-dessus.

Portées

PortéeCe qui est indiqué au titulairePermet
account:readVoir les détails de votre compte et votre soldeGET /account
keys:readDresser la liste de vos clés APIGET /keys
keys:writeCréer, modifier, faire pivoter et révoquer des clés APIPOST /keys, PATCH /keys/{id}, POST /keys/{id}/rotate, DELETE /keys/{id}
billing:readVoir si un mode de paiement est configuré, ainsi que vos paiementsGET /billing, GET /billing/topups/{id}, GET /billing/setup-sessions/{id}
billing:setupCommencer l'ajout d'un mode de paiement, que vous complétez vous-même sur StripePOST /billing/setup-sessions
billing:topupCommencer un achat de crédits, que vous payez vous-même sur StripePOST /billing/topups

Les portées de paiement ne peuvent être demandées que lorsque les paiements des agents sont activés. Sinon, la demande est refusée avec 422 scope_not_available.

Mettre fin à son propre justificatif avec DELETE /credential exige un justificatif valide, mais aucune portée particulière.

Limites et durées

LimiteValeur
Demandes d'inscription, tous appelants confondus5 par heure
Demandes d'inscription par adresse courriel5 par heure
Demandes d'inscription par adresse IP10 par heure
Adresses courriel distinctes par adresse IP1 par 24 heures
Demande en attente du titulaire24 heures, une par adresse courriel
Justificatif de gestion90 jours
Tentatives de réclamation10 par inscription et 30 par adresse IP, par période de 10 minutes
Enregistrements d'idempotence7 jours
Nouveaux liens de paiement10 par heure et par identifiant, et 30 par jour et par compte
Liens de paiement ouverts3 recharges et 3 ajouts de carte par compte
Durée de vie d'un lien de paiement60 minutes par défaut
Recharge maximale d'un agent500 $ CA par défaut, jamais au-dessus du maximum de la plateforme
Lectures en direct de la carte enregistrée4 par heure et par compte

Un appel limité répond 429 avec un en-tête Retry-After exprimé en secondes. Respectez-le. La désactivation des nouvelles inscriptions d'agents refuse les nouvelles demandes d'inscription, les vérifications d'état, les approbations et les récupérations avec 403 agent_registration_disabled, mais ne coupe pas un identifiant déjà émis. L'exploitant peut aussi suspendre tout l'accès des agents : chaque appel avec un identifiant ni_mgmt_ répond alors 403 agent_access_blocked jusqu'à la fin de la suspension, et l'identifiant n'est pas révoqué. Depuis une même adresse IP, une deuxième adresse courriel distincte dans un délai de 24 heures répond 429 agent_enrollment_ip_email_limit.

Erreurs

Les erreurs utilisent l'enveloppe d'erreur de la plateforme : le statut HTTP, un objet error contenant code, message, ni_request_id et ni_guidance, et le même identifiant de requête dans l'en-tête X-NI-Request-ID. Appuyez-vous sur le statut et sur error.code.

Étaterror.codeSignification et marche à suivre
401credential_requiredAucun justificatif porteur n'a été envoyé.
401wrong_credential_classLe jeton n'est pas un justificatif ni_mgmt_, par exemple une clé d'inférence.
401invalid_credentialJustificatif inconnu, expiré ou révoqué. Présentez une nouvelle demande.
401invalid_code_verifierLe vérificateur ne correspond pas au défi. Envoyez le vérificateur d'origine.
403insufficient_scopeLe justificatif n'a pas reçu la portée requise par l'appel. Présentez une nouvelle demande qui la réclame.
403agent_registration_disabledLes nouvelles inscriptions d'agents sont désactivées sur ce service.
403agent_access_blockedL'exploitant a suspendu tout l'accès des agents. Votre identifiant n'est pas révoqué; réessayez plus tard.
403agent_billing_disabledLes paiements des agents sont désactivés sur ce service.
404enrollment_not_foundCette inscription n'existe pas.
404not_foundCette clé n'existe pas dans ce compte.
404payment_not_foundAucune recharge de ce type pour ce compte.
404setup_not_foundAucun ajout de carte de ce type pour ce compte.
409idempotency_key_reusedCette clé a déjà servi pour une demande différente. Utilisez une nouvelle clé.
409enrollment_already_pendingUne demande pour cette adresse attend déjà son titulaire. Interrogez celle-là ou attendez qu'elle expire.
409request_in_progressUne requête portant ce Idempotency-Key est encore en cours de traitement. Réessayez sous peu avec la même clé.
409checkout_not_createdLa page de paiement associée à cette clé n'a pas pu être créée à temps. Réessayez avec un nouveau Idempotency-Key.
409checkout_not_availableUn achat ne peut pas être lancé pour ce compte en ce moment.
409account_unavailableLe compte n'est pas disponible pour la facturation, par exemple parce qu'il est en cours de suppression.
409not_approvedRéclamation avant l'approbation, ou après un refus ou une expiration. Vérifiez le statut.
409already_claimedLe justificatif a déjà été émis et ne sera plus jamais affiché. Présentez une nouvelle demande.
422invalid_scopesPortée inconnue, ou aucune portée. Le message énumère les portées disponibles.
422scope_not_availableUne portée de paiement a été demandée alors que les paiements des agents sont désactivés. Demandez les autres portées.
422amount_out_of_rangeamount_cents est hors de la plage permise. Le message l'indique.
422unsupported_currencySeule la devise du compte est prise en charge. Omettez currency ou envoyez cad.
422invalid_agent_labelagent_label doit compter de 1 à 80 caractères.
422invalid_code_challengecode_challenge doit être le SHA-256 du vérificateur, encodé en base64url sans remplissage, de 43 caractères.
422invalid_idempotency_keyIdempotency-Key doit compter de 8 à 200 caractères ASCII imprimables.
429rate_limitTrop d'appels. Attendez le délai indiqué par Retry-After.
429billing_rate_limitedTrop de liens de paiement ont été demandés. Attendez Retry-After.
429too_many_open_checkoutsLe compte a déjà le nombre maximal de liens de paiement ouverts. Attendez qu'un lien soit payé ou expire.
429card_read_limitedLa carte enregistrée a été lue trop souvent. Interrogez plutôt l'achat ou l'ajout de carte.
429agent_enrollment_busyTrop de demandes d'inscription, tous appelants confondus, cette heure-ci. Réessayez après le délai indiqué par Retry-After.
429agent_enrollment_ip_email_limitCette adresse IP a déjà demandé l'accès pour une autre adresse courriel au cours des 24 dernières heures.
502payment_provider_unavailableStripe a refusé de créer la page de paiement. Réessayez avec un nouveau Idempotency-Key.
503payment_provider_unavailableLe résultat est inconnu. Réessayez avec le même Idempotency-Key; cela ne peut pas créer deux pages de paiement.
503payment_provider_not_configuredLes paiements ne sont pas configurés sur ce service.
503approval_email_failedLe courriel d'approbation n'a pas pu être envoyé et la demande a été annulée. Réessayez avec un nouvel en-tête Idempotency-Key.

Pour les titulaires de compte

Un agent ne peut que demander. C'est vous qui décidez, et vous voyez exactement ce qu'il veut avant de décider.

Pour aller plus loin


Vous constatez un problème? Écrivez à support at northerninference dot ca.

↑