Skip to Content
Conventions

Conventions de l’API

Règles transversales à toutes les ressources de la v1.

SujetRègle
FormatJSON UTF-8. Les requêtes avec un corps portent Content-Type: application/json.
IDsUUID publics. Les IDs numériques internes ne sont jamais exposés.
DatesISO 8601. Instants en UTC (2026-07-08T09:30:00Z) ; dates calendaires YYYY-MM-DD.
Base URLVersionnée dans le path : https://api.kinmu.app/v1 · Dev : https://api.dev.kinmu.app/v1.

Pagination (curseur)

Toutes les listes paginent par curseur :

  • ?limit= (défaut 25, max 100) · ?cursor=<opaque>.
  • Réponse : { "data": [...], "meta": { "next_cursor": "…"|null, "has_more": true|false } }.
  • Pour la page suivante, renvoyez cursor=<meta.next_cursor>. has_more=false ou next_cursor=null → fin.
curl "https://api.kinmu.app/v1/employees?limit=50&cursor=eyJpZCI6MTIzfQ" \ -H "Authorization: Bearer kinmu_sk_live_…"

Le cursor est opaque : ne le construisez pas et ne le parsez pas, renvoyez-le tel quel.

Synchronisation incrémentale (updated_since)

Toutes les listes acceptent ?updated_since=<ISO 8601> pour ne récupérer que ce qui a changé depuis cet instant (polling incrémental pour la BI et les ERP).

curl "https://api.kinmu.app/v1/employees?updated_since=2026-07-01T00:00:00Z" \ -H "Authorization: Bearer kinmu_sk_live_…"

Conservez l’instant de votre dernière synchronisation et utilisez-le comme updated_since à la suivante. Le pattern complet est décrit dans le guide BI.

Erreurs

Toutes les erreurs suivent la RFC 9457 (application/problem+json) :

{ "type": "https://docs.kinmu.app/errors/invalid_scope", "title": "Scope insuficiente", "status": 403, "code": "invalid_scope", "detail": "La API key no tiene el scope requerido: org:empleados:read.", "errors": { "required_scope": "org:empleados:read" } }

Programmez contre le champ code (stable), pas contre title/detail.

Table des codes

codeHTTPQuand
unauthenticated401Clé absente, invalide, révoquée ou expirée.
invalid_scope403La clé n’a pas le scope requis (errors.required_scope).
subscription_inactive403L’abonnement de l’entreprise est suspendu ou absent.
addon_disabled403L’addon Public API n’est pas actif pour l’entreprise.
validation_failed422Corps ou paramètres invalides (errors avec le détail par champ).
not_found404La ressource n’existe pas ou appartient à une autre entreprise.
conflict409Conflit d’état (p. ex. décider une absence déjà décidée).
idempotency_conflict409L’Idempotency-Key a été réutilisée avec un corps différent.
rate_limited429Limite par minute dépassée (voir Retry-After).
quota_exceeded429Quota mensuel épuisé.
billing_required402Le plan ne permet pas l’action (p. ex. création d’un salarié sans siège disponible).
internal_error500Erreur interne.

Isolation multitenant. Demander une ressource d’une autre entreprise renvoie 404 (not_found), jamais un 403 qui révélerait son existence.

Limites de débit et quota

Chaque réponse (2xx et 4xx) inclut :

HeaderSignification
X-RateLimit-LimitLimite par minute de la clé.
X-RateLimit-RemainingRequêtes restantes dans la fenêtre courante.
X-RateLimit-ResetTimestamp Unix de réinitialisation de la fenêtre.
X-Kinmu-Quota-RemainingRequêtes restantes sur le quota mensuel.

Limites : live 120/min, test 30/min. Quota mensuel : live 10.000 + 1.000×empleados_activos (max 100 000) ; test 5.000.

Au-delà de la limite par minute → 429 rate_limited avec Retry-After: <secondes>. Quota épuisé → 429 quota_exceeded. Réessayez avec un backoff en respectant Retry-After.

import time, requests def call_with_retry(session, method, url, **kwargs): for attempt in range(5): resp = session.request(method, url, **kwargs) if resp.status_code != 429: return resp wait = int(resp.headers.get("Retry-After", 2 ** attempt)) time.sleep(wait) resp.raise_for_status() return resp

Surveillez X-RateLimit-Remaining et X-Kinmu-Quota-Remaining pour espacer vos requêtes avant de recevoir un 429.

Idempotence

Sur les méthodes qui écrivent (POST / PATCH / DELETE), vous pouvez envoyer Idempotency-Key: <unique> :

curl -s -X POST "https://api.kinmu.app/v1/check-ins" \ -H "Authorization: Bearer kinmu_sk_live_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 3f9a…-uuid" \ -d '{ "employee_id": "…", "type": "in", "timestamp": "2026-07-08T08:00:00Z" }'

La première requête est exécutée et sa réponse est mise en cache 24 h ; un renvoi avec le même corps retourne la réponse d’origine (sans ré-exécution). Réutiliser la même clé avec un corps différent409 idempotency_conflict.

La création de webhook est la seule exception : son secret copy-once n’est jamais mis en cache.

Last updated on