Authentification et conventions
Cette page décrit les règles communes à tous les endpoints de l'API REST Ormuz : authentification, format des identifiants, réponses et gestion des erreurs.
URL de base
Les contrats REST métier sont exposés sous le préfixe https://api.ormuz.io/v1/. L’échange d’une clé API contre un bearer token utilise l’endpoint séparé POST https://api.ormuz.io/api/token.
| Surface | Préfixe |
|---|---|
| Token pour clé API | https://api.ormuz.io/api/token |
| API REST publique | https://api.ormuz.io/v1/ |
Authentification
L'API utilise une authentification en deux étapes. Vous échangez d'abord votre clé API contre un token JWT à courte durée de vie, puis vous envoyez ce token dans l'en-tête Authorization de toutes vos requêtes.
Étape 1 — Obtenir un token
POST https://api.ormuz.io/api/token Content-Type: application/json
{
"api_key": "ormuz_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}Réponse 200
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
}Le token contient sa propre expiration JWT. La configuration standard est de 24 heures, mais un d éploiement peut utiliser une durée plus courte. Votre client doit donc se fier à l’expiration du token et obtenir un nouveau token lorsque nécessaire. Une clé API révoquée, suspendue ou expirée ne permet plus d’obtenir un token valide.
Étape 2 — Utiliser le token
GET https://api.ormuz.io/v1/invoices Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
L'en-tête Authorization est obligatoire sur tous les endpoints /v1/ à l'exception des chemins publics listés ci-dessous.
Chemins sans authentification
Ces endpoints n'exigent pas de token — ils sont accessibles sans en-tête Authorization.
| Chemin | Usage |
|---|---|
/v1/extension-assets/* | Ressources de présentation publiques déclarées par les extensions. |
/v1/extension-webhooks/* | Réception des webhooks entrants des providers. Chaque extension applique son propre contrat d’authentification ou de vérification. |
/v1/journey-access/validate | Validation de la capacité d’accès temporaire à un parcours utilisateur. |
/v1/approval-requests/assignments/* | Actions effectuées depuis une capacité d’approbation destinée à un assignment précis. |
Erreurs d'authentification
| Message | Cause |
|---|---|
Missing bearer token | En-tête Authorization absent ou mal formé. |
Invalid bearer token | Token invalide, signature incorrecte ou expiré. |
API key is not active or unknown | La clé associée au token a été révoquée, suspendue ou n’existe plus. |
API key has expired | La clé API a une date d'expiration dépassée. |

Permissions
Chaque clé API porte un ou plusieurs permission sets. Chaque set associe une portée — compte ou marchand — à une liste de permissions de la forme ressource:action, par exemple invoice:read ou company:write.
Un permission set peut être limité à un marchand précis. Les permissions de niveau compte sont déclarées sur un set sans merchant_id. Une clé ne peut lire ou modifier que les ressources couvertes par ses sets. Lorsqu’une ressource appartient à un marchand hors périmètre, l’API masque son existence et répond normalement comme pour une ressource absente.
Un 403 explicite est retourné quand la clé est valide mais qu'une action spécifique (par exemple invoice:write) n'est pas accordée.
Identifiants
Les ressources Ormuz qui utilisent un identifiant canonique suivent la forme prefix_hex. Le préfixe identifie le type d’objet et la partie hexadécimale contient 32 caractères représentant 16 octets générés aléatoirement. Certaines ressources directement adossées à un service externe, comme un endpoint webhook sortant, peuvent exposer l’identifiant fourni par ce service.
cmp_0123456789abcdef0123456789abcdef // Company inv_0123456789abcdef0123456789abcdef // Invoice pci_0123456789abcdef0123456789abcdef // Process instance evt_0123456789abcdef0123456789abcdef // Event occurrence
Traitez tous les identifiants comme opaques : ne leur attribuez ni ordre, ni date de création, ni sémantique au-delà du préfixe documenté. Les identifiants canoniques générés par Ormuz utilisent des préfixes et une partie hexadécimale en minuscules.
| Préfixe | Objet | Préfixe | Objet |
|---|---|---|---|
acc_ | Compte | prd_ | Définition de processus |
mer_ | Marchand | pdr_ | Révision de processus |
cmp_ | Company | pci_ | Instance de processus |
ctc_ | Contact | pua_ | Action utilisateur |
ord_ | Commande | pln_ | Launcher |
inv_ | Facture | apk_ | Clé API (identité publique de la ressource) |
pay_ | Paiement | evt_ | Événement |
psp_ | Paiement PSP | frm_ | Formulaire |
Format des requêtes
Toutes les requêtes avec un corps doivent envoyer du JSON avec l'en-tête Content-Type: application/json. Les corps malformés retournent un 400.
Le paramètre merchant_id est requis dans la plupart des requêtes de création. Il doit contenir l'identifiant du marchand (mer_...). L'API le résout en interne et retourne 400 si le marchand est introuvable.
Envoyez uniquement les champs documentés par le contrat de l’endpoint. Un champ supplémentaire ne doit jamais être utilisé comme mécanisme de persistance implicite : s’il ne fait pas partie du contrat public, ne supposez ni qu’il sera conservé ni qu’il sera renvoyé.
Metadata
Tout champ nommé metadata suit le même contrat Ormuz : une map plate dont les clés sont des chaînes non vides et les valeurs uniquement des string, nombres finis ou booléens. Les objets imbriqués, tableaux et valeurs null sont interdits.
Une map contient au maximum 50 clés, une clé mesure au plus 64 caractères, une valeur texte au plus 2 048 octets UTF-8, et la représentation JSON complète au plus 16 384 octets. Un dépassement retourne 400 ; l'API ne tronque jamais silencieusement.
À la création, metadata est optionnel et peut être null. Sur une mise à jour de ressource, les clés fournies sont fusionnées superficiellement avec la map existante ; les clés absentes sont conservées et null est refusé. Pour remplacer la map ou supprimer une clé, utilisez respectivement PUT /v1/<resource>/:id/metadata et DELETE /v1/<resource>/:id/metadata/:key.
La metadata est une surface non protégée : elle n'embarque aucune annotation de subtype ou de classification. Dans un processus, écrire une donnée protégée dans une clé de metadata constitue donc une déclassification explicite et demande le même consentement que les autres baisses de protection. Elle ne remplace jamais un stockage de secrets.
Le concepteur peut néanmoins conserver le type d'une valeur jusqu'à l'écriture : un binding ou une expression vers un common.amount persiste son entier JSON, alors qu'un template produit toujours une chaîne. Le subtype est ensuite effacé. Le node Get metadata valuepermet de réaffirmer un type scalaire attendu à la lecture ; il valide la valeur sans la convertir.
La metadata ne doit pas porter de donnée système dont Ormuz dépend pour son comportement. Un JSON structuré de provider ou de configuration doit porter un nom explicite, par exemple provider_metadata, config ou raw_response.
Format des réponses
Objet unique
Toute réponse représentant un objet unique inclut un champ object qui identifie son type.
{
"id": "inv_0123456789abcdef0123456789abcdef",
"object": "invoice",
"merchant_id": "mer_0123456789abcdef0123456789abcdef",
"status": "issued",
"settlement_status": "unpaid",
"amount_including_tax": 125000,
"currency": "eur",
"created_at": "2026-06-18T10:15:30.000Z",
"updated_at": "2026-06-18T10:15:30.000Z"
}Liste
Les endpoints de liste retournent une enveloppe stable avec object: "list", un tableau data, un booléen has_more et unnext_cursor opaque.
{
"object": "list",
"data": [
{ "id": "inv_0123456789abcdef0123456789abcdef", "object": "invoice" },
{ "id": "inv_fedcba9876543210fedcba9876543210", "object": "invoice" }
],
"has_more": true,
"next_cursor": "eyJ2IjoxLCJvIjoyMH0"
}Dates
Les champs publics de type date/heure sont exposés au format ISO 8601 UTC. Par exemple :
{
"created_at": "2026-06-18T10:15:30.000Z"
}Montants
Les montants typés common.amount sont des entiers exprimés dans l’unité mineure de la devise. Pour EUR, 125000 représente donc 1 250,00 €. Ne supposez pas qu’une unité mineure vaut toujours un centième : son exposant dépend de la devise.
Pagination
Les listes potentiellement volumineuses utilisent une pagination par cursor opaque. Le client ne calcule jamais une position lui-même : il renvoie simplement lenext_cursor reçu dans la page précédente.
| Paramètre | Défaut | Maximum | Description |
|---|---|---|---|
limit | 10 | 100 | Nombre maximal d'items à retourner. |
cursor | — | — | Cursor opaque retourné par next_cursor. Ne le décodez pas et ne le modifiez pas. |
GET /v1/invoices?limit=20&cursor=eyJ2IjoxLCJvIjoyMH0
Si has_more est true, utilisez next_cursortel quel pour la requête suivante. Lorsqu'il vaut false,next_cursor vaut null.
Idempotence des écritures
Les créations et commandes à effet métier qui peuvent être rejouées en cas d'incertitude réseau acceptent un header Idempotency-Key. Utilisez une valeur opaque unique par intention métier et réutilisez exactement la même clé lorsque vous ne savez pas si la première requête a abouti.
POST /v1/invoices Authorization: Bearer … Idempotency-Key: invoice-import-2026-09-27-0042 Content-Type: application/json
Ormuz conserve le premier résultat pendant 24 heures. La même clé avec la même requête rejoue ce résultat ; la réponse contient alors Idempotent-Replayed: true. Réutiliser la même clé avec un payload différent retourne 409. La présence du header et son caractère obligatoire ou optionnel sont déclarés opération par opération dans OpenAPI.
Erreurs
Les erreurs utilisent une enveloppe stable. type décrit la famille d'erreur, code fournit un identifiant machine, etrequest_id permet de corréler un appel avec l'observabilit é Ormuz. Les erreurs de validation ajoutent param et des détails structurés.
{
"error": {
"type": "invalid_request",
"code": "invalid_request",
"message": "body.currency: must be an uppercase 3-letter ISO 4217 code",
"param": "body.currency",
"details": {
"issues": [
{
"code": "invalid_format",
"path": "body.currency",
"message": "must be an uppercase 3-letter ISO 4217 code"
}
]
},
"request_id": "4e36d289-9fd4-44af-86ec-a32f2a6e9350",
"correlation_id": "4e36d289-9fd4-44af-86ec-a32f2a6e9350"
}
}| Code HTTP | Signification |
|---|---|
400 | Corps de requête invalide, champ manquant ou valeur incorrecte. |
401 | Token absent, invalide ou expiré, ou clé API devenue inactive. Renouvelez le token s’il a expiré ; une clé révoquée, suspendue ou expirée doit être corrigée côté configuration avant toute nouvelle tentative. |
403 | Permission manquante pour cette action. Le message indique quelle permission est requise. |
404 | Ressource introuvable — ou accessible mais non autorisée pour ce marchand. |
409 | Conflit d'état : ressource déjà dans cet état, doublon sur une contrainte d'unicité, ou configuration ambiguë nécessitant une sélection explicite. |
500 | Erreur interne. Ne rejouez automatiquement une écriture que si son contrat rend le rejeu sûr ou idempotent ; sinon diagnostiquez l’état de l’opération avant une nouvelle tentative. |