API REST & Intégrations
Intégrez AVIA ERP via l'API REST du portail, les endpoints publics et la synchronisation avec le site marketing.
Architecture
L'API métier est exposée par avcore sur le portail portal.aviaerp.com. Le site marketing aviaerp.com proxie les routes publiques /api/v1/public/* vers le portail pour éviter les problèmes CORS côté navigateur.
Portail ERP (API principale) : https://portal.aviaerp.com/api/v1/
Landing (proxy public) : https://aviaerp.com/api/v1/public/
Landing (routes internes) : https://aviaerp.com/api/erp-sync
https://aviaerp.com/api/paddle/webhookAuthentification
Les appels authentifiés utilisent un JWT obtenu via POST /api/v1/auth/login (e-mail + mot de passe ou SSO selon tenant). Incluez le token dans l'en-tête :
Authorization: Bearer <access_token>
X-Tenant: erppro
Content-Type: application/jsonLes intégrations serveur-à-serveur (sync landing, clés internes SaaS) utilisent X-API-Key avec la clé partagée SAAS_INTERNAL_API_KEY / LANDING_SYNC_API_KEY configurée des deux côtés.
Clés API
Pour une intégration tierce (pas une session portail), créez une clé depuis Paramètres → Clés API — réservé aux rôles admin / super-admin. Le secret n'est affiché qu'une seule fois, à la création :
Authorization: Bearer avia_live_<prefixe>_<secret>
X-Tenant-ID: <votre_tenant>Une clé est cantonnée à un seul tenant (aucun tenant par défaut pour un appelant tiers) et porte des scopes — une paire par module acheté, module:read / module:write (l'écriture couvre la lecture), plus rules et webhooks pour ces deux surfaces hors modules facturés. Les droits réellement accordés sont le plus étroit entre les scopes de la clé et les rôles de son porteur — un scope ne fait que restreindre, jamais accorder plus que ce que le porteur a déjà. L'expiration est obligatoire, jusqu'à 1 an ; une clé révoquée ou expirée refuse immédiatement (cle_api_invalide). Une clé est refusée d'emblée si la requête porte un en-tête Origin — jamais utilisable depuis un navigateur.
La limite de débit est par clé (pas par utilisateur), en-têtes X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset sur chaque réponse, 600 req/min par défaut.
Endpoints publics
Exemples d’endpoints accessibles sans session utilisateur (selon déploiement) :
| Route | Usage |
|---|---|
GET /api/v1/public/subscription-plans | Plans tarifaires affichés sur /tarifs |
POST /api/contact | Formulaire contact (landing Next.js) |
POST /api/demo | Demande de démonstration |
Synchronisation ERP → landing
Le portail pousse périodiquement tenant, plans et métadonnées vers POST /api/erp-sync sur le landing. Configurez l'URL dans Paramètres → Accès portail :
URL sync (prod) : https://aviaerp.com/api/erp-sync
URL sync (local) : http://localhost:3030/api/erp-sync
Health check : GET .../api/erp-sync/healthLa clé LANDING_SYNC_API_KEY doit être identique sur le portail et dans .env.production du landing.
Webhooks
Paddle — configurez le webhook vers https://aviaerp.com/api/paddle/webhook pour les événements de transaction et d'abonnement.
Événements métier — abonnez-vous depuis Paramètres → Webhooks du portail à l'un des ~27 événements du catalogue (création de document, changement de statut, étapes d'approbation — la liste complète s'interroge sur GET /settings/webhooks/events et est documentée dans la section webhooks: du contrat OpenAPI). Chaque livraison est signée et porte :
X-Avia-Event: invoice.created
X-Avia-Delivery-Id: 6f1e2c3a-... # stable meme apres une relivraison manuelle
X-Avia-Timestamp: 1755792000
X-Avia-Webhook-Version: 2026-08-19
X-Avia-Signature: sha256=<hmac> # deux valeurs separees par une virgule pendant une rotationLa signature est un HMAC-SHA256 sur <timestamp>.<corps brut> avec le secret de l'abonnement — vérifiez-la et refusez tout ce qui dépasse une fenêtre de 5 minutes. Régénérez le secret à tout moment depuis l'écran de l'abonnement (Régénérer le secret) : l'ancien continue de signer en plus du nouveau pendant 24h (double signature ci-dessus), donc aucune livraison en vol n'échoue pendant une rotation. Une livraison en échec est reprise avec un backoff quadratique et peut être rejouée manuellement depuis le journal des livraisons (POST .../webhooks/{id}/deliveries/{did}/retry).
SDK TypeScript
@aviaerp/sdk (sdk/typescript/ dans le dépôt) enveloppe les types générés (openapi-typescript) d'un client HTTP typé (openapi-fetch) : nouvelle tentative automatique sur 429 qui respecte Retry-After, erreurs typées {code, params, message}, aides de filtre reprenant la syntaxe du CRUD générique, pagination itérable, et un utilitaire verifyWebhookSignature (Web Crypto, aucun secret serveur exposé à un navigateur). C'est aujourd'hui un paquet de workspace privé, pas encore publié sur un registre — consommé par copie du dossier en attendant.
import { createAviaClient } from "@aviaerp/sdk"
const client = createAviaClient({
baseUrl: "https://portal.aviaerp.com",
apiKey: process.env.AVIA_API_KEY!,
tenantId: "erppro",
})
const { data, error } = await client.GET("/api/v1/sales-orders", {
params: { query: { status: "eq.confirme", page_size: 20 } },
})Référence complète (OpenAPI)
Toutes les routes au-delà des trois montrées ici — plus de 1000 chemins, générés depuis le code, jamais écrits à la main — se parcourent module par module, avec recherche, paramètres, schéma de réponse et un exemple de requête pour chacune :