Aller à l'article
Aniq-UI

NorthstackRéférence de l'API

Référence de l'API

Chaque route que sert l'API, qui peut l'appeler, et comment fonctionnent la connexion, les espaces de travail, les permissions, la facturation, les clés d'API, les erreurs, les listes et les limites.

Pour le pack Full Stack

URL de base et format des réponses

Chaque route est servie sous le préfixe /api. En local, l'URL de base est http://localhost:8000/api. Sur un serveur, c'est l'adresse de votre API suivie de /api, la même valeur que le site et le tableau de bord lisent dans NEXT_PUBLIC_API_BASE_URL (Variables d'environnement). Les fichiers sont servis hors du préfixe : les fichiers de marque du kit sur /media/… et les fichiers téléversés sur /media/uploads/….

Les corps de requête sont en JSON, sauf les téléversements de fichiers. Chaque réponse arrive dans la même enveloppe :

Enveloppe
{
  "success": true,
  "data": { },
  "message": ""
}

data contient le résultat. message est un court code que remplissent certaines écritures, comme project_created ou invitation_sent, et est vide sinon. Les espaces de travail, projets et tâches sont désignés par leurs identifiants publics (org_forma, prj_01) ; les membres, invitations, clés et fichiers par leur numéro. Les textes des projets et des tâches portent les deux langues sous la forme { "en": { … }, "ar": { … } }.

La vérification de santé ne demande aucun jeton :

Terminal
curl http://localhost:8000/api/health
Réponse
{"success":true,"data":{"status":"ok","database":"up"},"message":""}

Tant que la base ne répond pas et ne contient pas ses tables, elle répond 503 avec "status":"unavailable" et "database":"down". La vérification de santé de l'image Docker lit ce statut, et Docker Compose ne démarre le site et le tableau de bord qu'une fois qu'elle passe.

Les navigateurs ne peuvent appeler l'API que depuis les adresses de CORS_ORIGIN. Non défini, il autorise http://localhost:3030 et http://localhost:3031, et en production l'API refuse de démarrer sans lui (problèmes de CORS).

Erreurs

Un échec garde l'enveloppe, avec success: false, data: null et le statut HTTP :

Erreur
{
  "success": false,
  "data": null,
  "message": "seat_limit_reached",
  "errors": { "email": ["…"] }
}
  • errors apparaît lors d'un échec de validation (400), avec les problèmes par champ.
  • Un champ inconnu dans un corps est refusé avec 400 : chaque corps n'accepte que les champs listés ci-dessous.
  • Quand l'API a une phrase pour l'erreur, message est cette phrase dans la langue de la requête (Accept-Language: ar pour l'arabe) : une connexion refusée, chaque 429, les inscriptions fermées, un compte protégé contre un changement de mot de passe ou d'e-mail, un secret de webhook manquant, un abonnement que Stripe n'a pas pu annuler, un rôle ou une permission de plateforme que l'appelant ne détient pas, et le mode maintenance en font partie.
  • Sinon, sur 401, 403 et 404, message est une phrase générale pour le statut, et sur 400, 402, 409, 410 et 503 c'est la raison sous forme de court code (seat_limit_reached, slug_taken, over_plan_limit, payment_declined, preview_expired, invitation_expired, payment_unavailable), qu'un client transforme en sa propre phrase. Un retour à une formule inférieure refusé pour cause d'usage porte aussi blockers.
  • 402 signifie un passage à une formule supérieure que le fournisseur de paiement n'a pas voulu débiter : payment_declined, payment_needs_action (la banque veut confirmer le paiement) ou payment_method_missing. La formule reste ce qu'elle était.
  • Tant que le personnel de la plateforme a le mode maintenance activé, chaque route hors de la courte liste de Maintenance mode répond 503 à quiconque n'est pas du personnel de la plateforme, avec la phrase dans message et code: "maintenance_mode".
  • 401 signifie pas de jeton, un jeton expiré, ou de mauvais identifiants. 403 signifie connecté sans la permission, ou une écriture dans un espace de travail suspendu. 404 répond aussi pour un espace de travail dont l'appelant n'est pas membre, si bien qu'un inconnu ne peut pas savoir quels espaces existent.
  • Une requête au-delà d'une limite répond 429 (Limites par adresse).

Connexion

  1. Connexion

    Terminal
    curl -X POST http://localhost:8000/api/auth/login \
      -H "Content-Type: application/json" \
      -d '{"email":"owner@northstack.example","password":"YOUR_PASSWORD"}'

    Mettez le mot de passe du seed de l'installation à la place de YOUR_PASSWORD, ou utilisez un compte à vous. data.access_token est le jeton, avec token_type Bearer, expires_in, et admin, le compte avec ses rôles de plateforme, ses permissions et ses espaces de travail.

  2. Appeler une route protégée

    Terminal
    curl http://localhost:8000/api/workspaces \
      -H "Authorization: Bearer YOUR_TOKEN"

    Cela liste les espaces de travail du compte avec son rôle dans chacun. Chaque route d'espace de travail prend ensuite l'identifiant public de l'espace dans son chemin :

    Terminal
    curl "http://localhost:8000/api/workspaces/org_forma/projects?limit=20" \
      -H "Authorization: Bearer YOUR_TOKEN"
  • remember: true signe un jeton pour 30 jours et remember: false un jeton pour 12 heures ; omis, le jeton dure JWT_EXPIRATION, 7d par défaut.
  • Un e-mail inconnu et un mauvais mot de passe répondent tous deux 401 avec le même message, après le même travail de hachage du mot de passe, si bien que ni la réponse ni son délai ne disent quels e-mails ont un compte.
  • Dix connexions échouées depuis une même adresse en 15 minutes répondent 429 jusqu'à ce que le plus ancien échec ait 15 minutes (RATE_LIMIT_LOGIN). Les connexions réussies ne sont pas comptées.
  • Les jetons sont sans état : POST /api/auth/logout répond aussitôt, et se déconnecter revient à ce que le client oublie son jeton.
MéthodeCheminQui peut l'appelerRôle
POST/api/auth/loginN'importe quiConnexion : email, password, en option remember
POST/api/auth/signupN'importe quiUn nouveau compte, connecté aussitôt et prêt pour l'onboarding : name (2 à 80 caractères), email, password (8 à 128) et acceptTerms (true). Un e-mail déjà pris répond 409 avec email_taken ; tant que le paramètre signups_enabled de la plateforme est désactivé, il répond 403
POST/api/auth/forgot-passwordN'importe quiemail, en option locale (en, ar). Envoie par e-mail un lien de réinitialisation valable une fois pendant une heure quand le compte existe, et répond pareil dans les deux cas
POST/api/auth/reset-passwordN'importe quitoken (issu du lien) et le nouveau password (8 à 128). Un lien utilisé ou expiré répond 401
POST/api/auth/logoutN'importe quiRépond { signedOut: true }
GET/api/auth/meTout compte connectéLe compte, ses rôles et permissions de plateforme, et ses espaces de travail
PATCH/api/auth/meTout compte connectéModifie firstName, lastName, email ou phone
PATCH/api/auth/me/preferencesTout compte connectétheme (system, light, dark), reducedMotion, locale (en, ar) et lastWorkspaceId, l'espace de travail que la prochaine connexion ouvre
PATCH/api/admins/profile/passwordTout compte connectéModifie le mot de passe du compte lui-même : current_password, password, password_confirmation

Espaces de travail et permissions

  • Les routes d'espace de travail commencent par /api/workspaces/:workspaceId, l'identifiant public de l'espace. À chaque requête, l'API vérifie que l'appelant y a une appartenance active (sinon 404) et détient la permission que nomme la route (sinon 403). Le rôle est celui de l'appartenance : une même personne peut être propriétaire d'un espace et admin d'un autre.
  • Un espace de travail contient quatre rôles (owner, admin, member, billing) et sa propre matrice de 14 permissions : workspace.read, workspace.update, workspace.delete, projects.read, projects.write, members.invite, members.remove, roles.manage, billing.read, billing.manage, keys.manage, audit.read, ai.read et ai.apply. Le propriétaire les détient toutes, et workspace.delete et roles.manage restent au propriétaire quoi que dise la matrice. Un changement de la matrice s'applique à la requête suivante.
  • Un espace de travail suspendu garde chaque GET et refuse toute autre méthode avec 403.
  • Un espace de travail en retard de paiement garde tout jusqu'à ce que BILLING_GRACE_DAYS (7 par défaut) soient écoulés ; ensuite il ne peut ni créer de projets, ni d'invitations ou de clés d'API (403), tandis que chaque lecture et chaque autre écriture continue de fonctionner.
  • Les routes de plateforme (/api/platform, /api/users, /api/admins, /api/roles, /api/settings) vérifient plutôt les permissions de plateforme du compte, accordées par les rôles de plateforme. Le seed crée Platform admin, avec les 21, et Support, qui lit chaque page de la plateforme et exporte les rapports. Une route qui liste plusieurs permissions en accepte n'importe laquelle.

Listes et pagination

Une liste
{ "data": [ ], "total": 12, "page": 1, "limit": 7, "totalPages": 2 }
  • Les projets, les projets archivés, l'activité, les conversations du chat et leurs messages, ainsi que les organisations et les utilisateurs de la plateforme, se paginent avec page et limit, 100 par page au plus. Les valeurs par défaut sont 7 projets, 12 événements, 20 conversations et 10 organisations ou utilisateurs.
  • Le personnel, les paramètres de la plateforme et les rôles de la plateforme se paginent avec page et page_count à la place (10 par défaut, 100 au plus). Les rôles de la plateforme ne se paginent que si les deux sont fournis ; sinon chaque rôle est renvoyé.
  • Les listes arrivent de la plus récente à la plus ancienne (projets, utilisateurs et organisations par leur dernière modification), avec l'identifiant pour départager, sauf si un sort est donné ; les rôles de la plateforme arrivent par nom. La liste des projets renvoie aussi counts par onglet.
  • Ce qui appartient à un seul espace de travail et s'affiche en entier répond sans pagination : les tâches d'un tableau, les membres, les invitations, les clés d'API, les fichiers d'un projet, les 36 dernières factures et les 8 dernières notifications.

Espaces de travail, membres et matrice de rôles

MéthodeCheminQui peut l'appelerRôle
GET/api/workspacesTout compte connectéLes espaces de travail du compte avec son rôle dans chacun, pour le sélecteur
GET/api/workspaces/slug-availabilityTout compte connecté?slug= : si l'adresse d'un espace de travail est libre, avec une suggestion quand elle ne l'est pas
POST/api/workspacesTout compte connectéOnboarding : name (2 à 80), slug (3 à 48 lettres minuscules, chiffres et tirets), region (europe, north_america, asia_pacific) et en option invitations, jusqu'à 20 { email, role }. L'appelant devient le propriétaire, sur un essai Starter aussi long que le trial_days de la plateforme. Un slug déjà pris répond 409 avec slug_taken, et tant que signups_enabled est désactivé, il répond 403
GET/api/workspaces/:workspaceIdUn membre avec workspace.readL'espace de travail : nom, adresse, formule, usage par rapport aux limites de la formule et ses paramètres. billingEmail vaut null sauf si l'appelant détient billing.read ou billing.manage
PATCH/api/workspaces/:workspaceIdUn membre avec workspace.updateModifie name, slug, locale (en, ar), timeZone (une zone IANA comme Europe/Berlin), domainConfigured, emailNotifications (les e-mails de facturation) ou weeklyDigest
DELETE/api/workspaces/:workspaceIdLe propriétaire de l'espace de travailconfirmName (le nom de l'espace de travail, saisi en entier) et le password du propriétaire. L'espace de travail est supprimé logiquement, et son abonnement Stripe est d'abord annulé ; si Stripe refuse, elle répond 409 et l'espace est conservé
GET/api/workspaces/:workspaceId/membersUn membre avec workspace.readLes membres avec leurs rôles. search, role
PATCH/api/workspaces/:workspaceId/members/:memberIdUn membre avec roles.manageModifie le role d'un membre (admin, member, billing). La ligne du propriétaire répond 403
DELETE/api/workspaces/:workspaceId/members/:memberIdUn membre avec members.removeRetire un membre. Le propriétaire ne peut pas être retiré, et un admin ne peut pas retirer un autre admin
POST/api/workspaces/:workspaceId/members/transfer-ownershipLe propriétaire de l'espace de travailmemberId et le password du propriétaire. Le membre devient le propriétaire et l'ancien propriétaire un admin
GET/api/workspaces/:workspaceId/rolesUn membre avec workspace.readLa matrice de rôles : chaque permission, en six groupes, et les rôles qui la détiennent
PUT/api/workspaces/:workspaceId/rolesLe propriétaire de l'espace de travailEnregistre la matrice : matrix, chaque permission associée aux rôles qui la détiennent. Une permission ou un rôle inconnu répond 400

Invitations

MéthodeCheminQui peut l'appelerRôle
GET/api/workspaces/:workspaceId/invitationsUn membre avec workspace.readstatus (pending, par défaut, ou all). Répond invitations et seats, les places utilisées et restantes sur la formule
POST/api/workspaces/:workspaceId/invitationsUn membre avec members.inviteInvite email comme role (admin, member, billing). Le lien est envoyé par e-mail et fonctionne 7 jours. Une formule pleine répond 409 avec seat_limit_reached ; already_member et already_invited sont refusés de la même façon
POST/api/workspaces/:workspaceId/invitations/:id/resendUn membre avec members.inviteUn nouveau lien, valable 7 jours de plus. Une fois par minute au plus (resend_too_soon), et cinq fois par invitation (resend_limit_reached)
DELETE/api/workspaces/:workspaceId/invitations/:idUn membre avec members.inviteRévoque une invitation
GET/api/invitations/:tokenN'importe quiCe qu'ouvre un lien d'invitation : le nom et l'adresse de l'espace de travail, le rôle, l'e-mail invité en partie masqué, et s'il est encore ouvert
POST/api/invitations/:token/acceptLe compte invité, connectéRejoint l'espace de travail. Un lien expiré ou révoqué répond 410 ; un compte dont l'e-mail n'est pas celui invité répond 403 ; une formule pleine répond 409 avec seat_limit_reached

Les e-mails d'invitation passent par les paramètres SMTP de l'API, ou dans son journal tant que SMTP_HOST est vide, lien compris.

Projets et fichiers

MéthodeCheminQui peut l'appelerRôle
GET/api/workspaces/:workspaceId/projectsUn membre avec projects.readLes projets avec counts par onglet. status (all, active, completed, ou un statut), state (in_progress, review, blocked, completed), search, ownerId, dueBefore (YYYY-MM-DD), sort (updated_at, due_date, name, progress), order (asc, desc), page, limit
GET/api/workspaces/:workspaceId/projects/archivedUn membre avec projects.readLes projets archivés, avec les mêmes filtres
GET/api/workspaces/:workspaceId/projects/ownersUn membre avec projects.readLes membres qui possèdent des projets, pour le filtre de responsable
GET/api/workspaces/:workspaceId/projects/:projectIdUn membre avec projects.readUn projet avec son responsable, son échéance, sa progression et le nombre de ses tâches
POST/api/workspaces/:workspaceId/projectsUn membre avec projects.writeCrée un projet : translations (en obligatoire, ar facultatif, chaque name jusqu'à 120 caractères et description jusqu'à 2000), et en option status, ownerId (un membre), dueDate (YYYY-MM-DD) et progress (0 à 100)
PATCH/api/workspaces/:workspaceId/projects/:projectIdUn membre avec projects.writeModifier n'importe lequel de ces champs
DELETE/api/workspaces/:workspaceId/projects/:projectIdUn membre avec projects.writeArchive un projet. Rien n'est supprimé
POST/api/workspaces/:workspaceId/projects/:projectId/restoreUn membre avec projects.writeRemet un projet archivé
GET/api/workspaces/:workspaceId/projects/:projectId/activityUn membre avec projects.readLes 100 derniers événements du projet
GET/api/workspaces/:workspaceId/projects/:projectId/filesUn membre avec projects.readLes fichiers du projet, du plus récent au plus ancien
POST/api/workspaces/:workspaceId/projects/:projectId/filesUn membre avec projects.writeJoint un fichier : file multipart, 10 Mo au plus. Sa taille compte dans le stockage de la formule
GET/api/workspaces/:workspaceId/projects/:projectId/files/:fileId/downloadUn membre avec projects.readL'url, le name et le mime du fichier

Créer un projet dans un espace de travail en retard de paiement dont le délai de grâce est terminé répond 403.

Tâches et tableau

Une tâche est listée et créée sous son projet, et modifiée par son propre identifiant sous l'espace de travail.

MéthodeCheminQui peut l'appelerRôle
GET/api/workspaces/:workspaceId/projects/:projectId/tasksUn membre avec projects.readLes tâches du tableau dans l'ordre des colonnes. assigneeId, priority, search
POST/api/workspaces/:workspaceId/projects/:projectId/tasksUn membre avec projects.writeCrée une tâche : translations (en obligatoire, chaque title jusqu'à 160 caractères et description jusqu'à 4000), et en option status (backlog, par défaut, in_progress, review, done), priority (low, normal, high), assigneeId (un membre) et dueDate
PATCH/api/workspaces/:workspaceId/tasks/:taskIdUn membre avec projects.writeModifier n'importe lequel de ces champs
POST/api/workspaces/:workspaceId/tasks/:taskId/moveUn membre avec projects.writeDéplace une carte : status (la colonne) et beforeId, la carte au-dessus de laquelle elle arrive, ou rien pour la fin de la colonne
DELETE/api/workspaces/:workspaceId/tasks/:taskIdUn membre avec projects.writeArchive une tâche

Une personne assignée qui n'est pas membre répond 400 avec assignee_not_member. Chaque changement écrit un événement dans la trace d'activité, comme task.moved avec les colonnes d'origine et d'arrivée.

Vue d'ensemble, activité, notifications et recherche

MéthodeCheminQui peut l'appelerRôle
GET/api/workspaces/:workspaceId/overviewUn membre avec workspace.readLa vue d'ensemble : les projets par statut, les membres et les invitations en attente, les événements de tâches par jour sur les sept derniers jours, la checklist de lancement, jusqu'à trois projets dont l'échéance tombe dans la période et les six derniers événements. period (7d, 30d, par défaut, 90d). Sans projects.read, le nombre de projets, le graphique et les projets à échéance reviennent à zéro ou vides
GET/api/workspaces/:workspaceId/activityUn membre avec audit.readLa trace d'activité, avec les personnes qui y figurent sous actors. action (une action comme task.moved, ou une famille se terminant par un point comme task.), actorId, from et to (YYYY-MM-DD), search, page, limit
GET/api/workspaces/:workspaceId/activity/exportUn membre avec audit.readLes mêmes filtres sous forme de fichier CSV (date, actor, action, subject, details), jusqu'à 5 000 lignes. Les cellules qui s'exécuteraient comme une formule de tableur sont échappées
GET/api/workspaces/:workspaceId/notificationsUn membre avec workspace.readLa cloche : les 8 derniers événements et combien sont plus récents que le dernier passage du lecteur
POST/api/workspaces/:workspaceId/notifications/readUn membre avec workspace.readMarque tout comme lu jusqu'à maintenant
GET/api/workspaces/:workspaceId/searchUn membre avec workspace.readq (2 à 100 caractères) : jusqu'à cinq projets, tâches et membres chacun. Les projets et les tâches n'apparaissent que pour un membre avec projects.read

Les derniers événements de la vue d'ensemble et la cloche montrent toute la trace à un appelant avec projects.read ou audit.read, seulement les événements billing. à un appelant avec billing.read et aucun des deux, et rien à tous les autres.

Facturation, son webhook et le paiement test

MéthodeCheminQui peut l'appelerRôle
GET/api/workspaces/:workspaceId/billingUn membre avec billing.readL'abonnement : formule, statut, prix, renouvellement, une annulation ou un retour à une formule inférieure en attente du renouvellement, le délai de grâce du retard de paiement, l'usage et tout paiement en cours
GET/api/workspaces/:workspaceId/billing/invoicesUn membre avec billing.readLes 36 dernières factures
GET/api/workspaces/:workspaceId/billing/invoices/:invoiceId/download-linkUn membre avec billing.readUn lien signé vers le PDF de la facture, valable cinq minutes, construit à partir de PUBLIC_API_URL
POST/api/workspaces/:workspaceId/billing/previewUn membre avec billing.manageCe que coûte le passage à planId (starter, pro, scale) : passage à une formule supérieure ou inférieure, quand il prend effet, le débit du jour (chargeTodayCents), la prochaine facture et d'éventuels blockers (places, requêtes d'API ou stockage au-dessus des limites de la formule plus petite). Le passage à une formule supérieure d'un abonnement Stripe en cours est tarifé par Stripe et répond chargesCardOnFile: true avec un quote qui garantit ce prix 30 minutes ; le paiement test calcule la différence au prorata du reste de la période. La formule actuelle répond 400 avec same_plan, sauf pour un premier paiement (un essai, un essai terminé ou un espace de travail annulé), où n'importe quelle formule est facturée à son prix plein
POST/api/workspaces/:workspaceId/billing/checkoutUn membre avec billing.manageplanId, en option locale et le quote de l'aperçu. Le passage à une formule supérieure d'un abonnement Stripe en cours est fait tout de suite et débité sur le moyen de paiement enregistré (upgraded: true), la date de renouvellement inchangée ; un débit refusé répond 402 avec payment_declined, payment_needs_action ou payment_method_missing, et un devis expiré ou étranger 409 avec preview_expired. Tout autre passage à une formule supérieure répond l'url du paiement hébergé et sa session. Un retour à une formule inférieure est planifié pour le renouvellement (scheduled: true), sur Stripe via un échéancier d'abonnement, ou refusé avec 409 over_plan_limit et les blockers
POST/api/workspaces/:workspaceId/billing/checkout/:sessionId/syncUn membre avec billing.readAprès le retour du paiement : relit la session chez le fournisseur et répond la session et le récapitulatif. La formule ne change qu'une fois que le fournisseur dit qu'elle est payée
POST/api/workspaces/:workspaceId/billing/keep-planUn membre avec billing.manageAnnule un retour à une formule inférieure planifié pour le renouvellement ; répond le récapitulatif. Si rien n'est planifié, répond 409 avec no_scheduled_change
POST/api/workspaces/:workspaceId/billing/portalUn membre avec billing.manageL'url du portail client de Stripe, pour le moyen de paiement ; url: null pour un espace de travail non facturé par Stripe
POST/api/workspaces/:workspaceId/billing/cancelUn membre avec billing.manageAnnule à la fin de la période. Un retour à une formule inférieure planifié pour le renouvellement est abandonné
POST/api/workspaces/:workspaceId/billing/resumeUn membre avec billing.manageGarde un abonnement qui avait été réglé pour être annulé
PATCH/api/workspaces/:workspaceId/billing/emailUn membre avec billing.manageModifie l'email de facturation
GET/api/billing/invoices/downloadToute personne qui détient le lien signé?token= : la facture en PDF. Un mauvais jeton répond 401 et un jeton expiré 403
POST/api/billing/webhooks/stripeStripeLes événements de Stripe, vérifiés avec STRIPE_WEBHOOK_SECRET contre l'en-tête Stripe-Signature ; une signature manquante ou fausse répond 400, de même que chaque envoi tant que STRIPE_WEBHOOK_SECRET est vide, avec un message qui le nomme. Les abonnements utilisent checkout.session.completed, invoice.paid, invoice.payment_failed et customer.subscription.deleted, chaque identifiant d'événement n'étant appliqué qu'une fois. Les commandes de licences arrivent sur la même route (Le paiement des licences)
GET/api/billing/simulator/:sessionIdUn membre avec billing.manage dans l'espace de travail de la sessionLa session du paiement test, pour la page de paiement propre au tableau de bord
POST/api/billing/simulator/:sessionId/completeUn membre avec billing.manage dans l'espace de travail de la sessionTest payment : la formule change comme si le fournisseur l'avait confirmée
POST/api/billing/simulator/:sessionId/cancelUn membre avec billing.manage dans l'espace de travail de la sessionQuitte le paiement test sans payer
  • Le paiement utilise Stripe Checkout quand STRIPE_SECRET_KEY est défini, et le paiement test intégré sinon, ou chaque fois que BILLING_PROVIDER=simulator. Le paiement test ne débite personne.
  • L'adresse de retour seule ne change jamais une formule : seuls le webhook signé, ou la session relue via sync, le font.
  • Le prix Stripe de chaque formule est créé à la première utilisation, avec la clé de recherche northstack_<plan>_usd_<cents>_month : rien n'est donc configuré d'abord dans Stripe.
  • Un paiement Stripe terminé pour un espace de travail qui a déjà un abonnement Stripe annule l'ancien, son temps inutilisé étant crédité. invoice.paid stocke une fois la facture de Stripe (les factures sont uniques par identifiant de facture du fournisseur), avec son montant et sa période, déplace la période de l'espace de travail vers celle qu'ouvre une facture, et lors d'un renouvellement applique un retour à une formule inférieure planifié pour lui.
  • Sur le paiement test, l'API renouvelle chaque période à son terme (une facture payée, les 30 jours suivants, un retour à une formule inférieure planifié appliqué) et met fin à celle réglée pour être annulée. Un essai qui arrive à son terme passe en retard de paiement, avec le délai de grâce. Les compteurs d'usage repartent de zéro à chaque période. Cela s'exécute à chaque lecture de la facturation et une fois par heure.
  • Pointez votre webhook Stripe vers https://<your API>/api/billing/webhooks/stripe avec les événements ci-dessus plus checkout.session.expired.

Clés d'API et API publique

MéthodeCheminQui peut l'appelerRôle
GET/api/workspaces/:workspaceId/api-keysUn membre avec keys.manageLes clés de l'espace de travail : nom, préfixe, portées, environnement, dernier usage et qui l'a créée. Jamais le secret
POST/api/workspaces/:workspaceId/api-keysUn membre avec keys.managename (2 à 60), scopes (un ou plusieurs parmi projects:read, projects:write, tasks:read, tasks:write) et environment (production, par défaut, ou demo). Répond la clé avec son secret, montré cette seule fois ; seul son hachage SHA-256 est conservé
DELETE/api/workspaces/:workspaceId/api-keys/:idUn membre avec keys.manageRévoque une clé. Elle cesse aussitôt de fonctionner
GET/api/v1/projectsUne clé d'API avec projects:readLes 100 projets de l'espace de travail les plus récemment modifiés
POST/api/v1/projectsUne clé d'API avec projects:writeCrée un projet, avec le même corps que celui du tableau de bord
PATCH/api/v1/projects/:projectIdUne clé d'API avec projects:writeModifie un projet, avec le même corps que celui du tableau de bord
GET/api/v1/projects/:projectId/tasksUne clé d'API avec tasks:readLes tâches d'un projet
POST/api/v1/projects/:projectId/tasksUne clé d'API avec tasks:writeCrée une tâche, avec le même corps que celui du tableau
Terminal
curl http://localhost:8000/api/v1/projects \
  -H "Authorization: Bearer nst_live_…"
  • Le secret d'une clé de production commence par nst_live_, celui d'une clé de démo par nst_demo_. Une clé de démo ne fonctionne que tant que l'API tourne en mode démo.
  • Aucune clé, une clé inconnue ou révoquée répond 401 ; une clé sans la portée de la route répond 403 ; un espace de travail suspendu refuse l'écriture.
  • Chaque route sauf la liste des projets s'exécute au nom du créateur de la clé : ce qu'elle crée est enregistré comme fait par lui, avec la validation, les événements d'activité et les limites de formule du tableau de bord. Elle répond 404 une fois que le créateur a quitté l'espace de travail, et les trois écritures répondent 403 une fois que le rôle du créateur ne détient plus projects.write.
  • Chaque appel compte dans les requêtes d'API de la formule, que lisent la page de facturation et les limites de la formule.

Vue d'ensemble de la plateforme et organisations

MéthodeCheminQui peut l'appelerRôle
GET/api/platform/overviewLe personnel avec platform.viewLes revenus mensuels récurrents et leur historique, la répartition des formules et les organisations par statut. range (30d, 90d, 6m, par défaut, 12m)
GET/api/platform/overview/exportÉquipe avec reports.exportChaque organisation sous forme de fichier CSV : organization, id, plan, status, seats, mrr_usd, created
GET/api/platform/organizationsLe personnel avec organizations.viewLes organisations. search (nom ou adresse), plan (starter, pro, scale), status (trialing, active, past_due, canceling, canceled, suspended), page, limit
GET/api/platform/organizations/:idLe personnel avec organizations.viewUne organisation, par son identifiant public
POST/api/platform/organizations/:id/suspendLe personnel avec organizations.managereason (3 à 300 caractères). L'espace de travail garde ses lectures et refuse toute écriture. Un espace déjà suspendu répond 409
POST/api/platform/organizations/:id/reactivateLe personnel avec organizations.manageLève une suspension

Utilisateurs, personnel, rôles et paramètres de la plateforme

MéthodeCheminQui peut l'appelerRôle
GET/api/usersPersonnel avec users.viewChaque compte. search, role (owner, admin, member ou billing pour un rôle d'espace de travail détenu quelque part, staff pour un rôle de plateforme, none pour les comptes sans espace de travail), page, limit
GET/api/users/deletedPersonnel avec users.viewLes comptes supprimés, avec les mêmes filtres
GET/api/users/statisticPersonnel avec users.viewLes totaux : comptes, supprimés, personnel, sans espace de travail, nouveaux ces 30 derniers jours
GET/api/users/deleted/:usernamePersonnel avec users.viewUn compte supprimé
GET/api/users/:usernamePersonnel avec users.viewUn compte
POST/api/usersPersonnel avec users.createCrée un compte : first_name, last_name, email, password (8 à 128), en option phone
PATCH/api/users/:usernamePersonnel avec users.updateModifie first_name, last_name, email ou phone. Un nouvel e-mail est protégé comme ci-dessous
PATCH/api/users/:username/change-passwordPersonnel avec users.updateDéfinit un nouveau password (8 à 128), protégé comme ci-dessous
DELETE/api/users/:usernamePersonnel avec users.deleteDéplace un compte vers la liste des supprimés. Un compte qui possède un espace de travail répond 409 avec user_owns_workspace tant que la propriété n'a pas changé de main
POST/api/users/deleted/:username/restorePersonnel avec users.restoreRamène un compte supprimé
GET/api/adminsPersonnel avec admins.viewChaque compte avec ses rôles de plateforme. email, name (prénom, nom ou nom d'utilisateur), phone, une ligne correspondant à l'un quelconque des critères donnés, page, page_count
GET/api/admins/statisticsPersonnel avec admins.viewLes totaux de la page du personnel
GET/api/admins/:idPersonnel avec admins.viewUn compte, par identifiant ou nom d'utilisateur
POST/api/adminsPersonnel avec admins.createAjoute un compte du personnel : first_name, last_name, email, password et password_confirmation (6 caractères ou plus), en option phone, phone_code, profile_picture
PATCH/api/admins/:idPersonnel avec admins.editModifie ces champs ; un nouveau mot de passe ou e-mail est protégé comme ci-dessous
PATCH/api/admins/:id/rolesPersonnel avec admins.assign_rolesDéfinit les rôles de plateforme d'un compte : role_ids. Chaque rôle accordé ou retiré ne doit contenir que des permissions que l'appelant détient lui-même, sinon la réponse est 403 (role_outranks_caller). Son tableau de bord ouvert en est informé aussitôt
DELETE/api/admins/:idPersonnel avec admins.deleteRetire un compte. Un compte qui possède un espace de travail répond 409
PATCH/api/admins/profilePersonnel avec admins.editModifie le profil du membre du personnel connecté lui-même
GET/api/rolesPersonnel avec roles.viewLes rôles de plateforme. name, guard_name, created_from, created_to, page, page_count
GET/api/roles/statisticsPersonnel avec roles.viewLes totaux de la page des rôles
GET/api/roles/selectPersonnel avec roles.viewL'identifiant et le nom de chaque rôle, pour un sélecteur
GET/api/roles/permissionsPersonnel avec roles.viewChaque permission de plateforme, groupée par domaine
GET/api/roles/:idPersonnel avec roles.viewUn rôle avec ses permissions
POST/api/rolesPersonnel avec roles.createAjoute un rôle : name. Un nom déjà utilisé répond 409
PUT/api/roles/:idPersonnel avec roles.editRenommer un rôle : name
POST/api/roles/:id/permissionsPersonnel avec roles.assign_permissionsDéfinit les permissions d'un rôle, par nom. L'appelant ne peut donner que des permissions qu'il détient, et ne modifier qu'un rôle qui n'en contient aucune qui lui manque, sinon la réponse est 403 (permission_outranks_caller). Tous ceux qui le détiennent en sont informés aussitôt
DELETE/api/roles/:idPersonnel avec roles.deleteSupprime un rôle. Un rôle que quelqu'un détient répond 400
GET/api/settingsPersonnel avec settings.viewLes paramètres de la plateforme. search, category, page, page_count
GET/api/settings/:keyPersonnel avec settings.viewUn paramètre
PATCH/api/settings/:keyPersonnel avec settings.editModifie un paramètre : value
DELETE/api/settings/:keyPersonnel avec settings.editSupprimer un paramètre

La protection des mots de passe et des e-mails : un appelant autre que le compte lui-même ne peut définir son mot de passe ou changer son e-mail que s'il est Platform admin ou détient chaque permission de plateforme que détient le compte ; sinon l'API répond 403. L'e-mail est aussi protégé, car une réinitialisation du mot de passe y est envoyée.

La protection des rôles : personne ne peut accorder, retirer ou relever un rôle de plateforme au-delà de ses propres permissions, si bien que admins.assign_roles ou roles.assign_permissions seul ne mène jamais au rôle Platform admin.

Les 21 permissions de plateforme sont platform.view, reports.export, organizations.view, organizations.manage, users.view, users.create, users.update, users.delete, users.restore, admins.view, admins.create, admins.edit, admins.delete, admins.assign_roles, roles.view, roles.create, roles.edit, roles.delete, roles.assign_permissions, settings.view et settings.edit.

Paramètres publics et mode maintenance

MéthodeCheminQui peut l'appelerRôle
GET/api/public-settingsN'importe quimaintenanceMode et trialDays (le trial_days de la plateforme, 14 quand il n'est pas défini) : ce que l'onboarding indique comme durée d'essai, et si le tableau de bord affiche son écran de maintenance. Ouvert pendant la maintenance

Tant que le paramètre de plateforme maintenance_mode vaut true, chaque requête de quiconque n'est pas du personnel de la plateforme (un compte détenant platform.view) répond 503, avec code: "maintenance_mode" et le message « The platform is closed for maintenance. Please try again shortly. » Un jeton absent ou faux reçoit le même 503. Ces routes restent ouvertes à tous :

  • GET /api/health et GET /api/public-settings ;
  • POST /api/auth/login et POST /api/auth/logout, où la connexion refuse encore quiconque n'est pas du personnel avec le 503 une fois les identifiants corrects ;
  • POST /api/billing/webhooks/stripe et le téléchargement signé des factures ;
  • le point de terminaison MCP, qui garde sa propre clé, et GET /api/demo/status ;
  • le POST /api/contact du site et chaque route /api/licenses, pour que le formulaire de contact et le paiement des licences continuent de fonctionner.

Tout le reste est fermé aux non-membres du personnel, y compris l'inscription, la récupération du mot de passe, les invitations, l'onboarding, l'API publique sous /api/v1, les fichiers téléversés et l'assistant. La liste est back-end/src/common/constants/maintenance.constants.ts.

Le formulaire de contact

MéthodeCheminQui peut l'appelerRôle
POST/api/contactN'importe quiname (2 à 120), email, topic (licensing, setup, product), message (20 à 4000 caractères), clientToken (8 à 64 lettres, chiffres, _ ou -) et le champ caché website. Répond { id }
  • Un clientToken répété renvoie l'identifiant du premier message au lieu d'en stocker un second : une nouvelle tentative est donc sans risque.
  • Un champ website rempli est traité comme un robot : la réponse a le même aspect, et rien n'est stocké.
  • Chaque adresse peut en envoyer cinq par heure ; le suivant répond 429.
  • Les messages sont stockés dans la table contact_messages et transférés à CONTACT_INBOX quand il est défini.

Le paiement des licences

MéthodeCheminQui peut l'appelerRôle
GET/api/licenses/checkout/optionsN'importe quiLes moyens de paiement (card, paypal), le provider qui prend chacun (stripe, paypal ou simulator), et testMode, vrai quand aucun ne déplace d'argent réel
POST/api/licenses/checkoutN'importe quilicense (single, studio), email, name (2 à 120), method (card, paypal), en option locale (en, ar), et clientToken. Répond order, l'identifiant de la commande, et url, la page où payer. Une page de paiement qui ne peut pas s'ouvrir répond 503 avec payment_unavailable
GET/api/licenses/orders/:idQuiconque détient l'identifiant de la commandeLa commande : référence, licence, montant, e-mail, nom, moyen, fournisseur, status (pending, paid, cancelled, failed), test, et licenseKey une fois payée
POST/api/licenses/orders/:id/confirmQuiconque détient l'identifiant de la commandeL'acheteur revient de Stripe ou de PayPal : demande au fournisseur si le paiement a abouti, puis répond la commande
POST/api/licenses/orders/:id/cancelQuiconque détient l'identifiant de la commandeL'acheteur a quitté la page de paiement sans payer
POST/api/licenses/orders/:id/simulateQuiconque détient l'identifiant de la commandeLe Pay ou le Cancel du paiement test : outcome (pay, cancel). Une commande prise par Stripe ou PayPal répond 404
  • Le prix est celui du serveur lui-même, issu de back-end/src/modules/licenses/constants/license-offers.ts ; le navigateur n'en envoie jamais un.
  • Une carte va vers Stripe Checkout quand STRIPE_SECRET_KEY est défini, PayPal vers PayPal quand PAYPAL_CLIENT_ID et PAYPAL_CLIENT_SECRET sont définis, et l'un comme l'autre vers le paiement test sinon. En mode démo, un fournisseur disposant de clés live n'est jamais proposé.
  • Une commande est payée une seule fois, par celui qui arrive le premier entre le checkout.session.completed de Stripe sur POST /api/billing/webhooks/stripe, le confirm du retour, ou le Pay du paiement test. Celui-là seul émet la clé de licence et envoie le reçu par e-mail. checkout.session.expired marque la commande comme échouée.
  • L'identifiant de la commande est une longue chaîne aléatoire que seuls portent les liens de retour de l'acheteur. Un clientToken répété répond la première commande. Chaque adresse peut démarrer dix commandes par heure.

Fichiers téléversés et médias

MéthodeCheminQui peut l'appelerRôle
POST/api/helpers/uploadTout compte connectéStocke une image : file multipart (10 Mo au plus), path pour le dossier et for pour le préréglage de taille (profile, cover, logo, ou default). Répond les adresses par taille : original, de 1920 pixels de large au plus, et une copie redimensionnée, toutes en JPEG. Un fichier qui n'est pas une image lisible répond 400

Les images et les fichiers de projet vont dans le bucket Cloudflare R2 quand ses cinq variables R2_* sont définies, et dans MEDIA_UPLOAD_DIR sinon, servis à PUBLIC_MEDIA_URL suivi de /uploads/….

Tout ce que l'API sert sous /media porte X-Content-Type-Options: nosniff, et un fichier qui n'est ni une image raster, ni un PDF, ni du texte brut, ni de l'audio ou de la vidéo (un fichier HTML ou SVG, par exemple) est envoyé avec Content-Disposition: attachment, si bien qu'il se télécharge au lieu de s'ouvrir comme une page à l'adresse de l'API. Les fichiers d'un bucket R2 sont servis par le bucket, avec le type qu'ils avaient au téléversement.

Limites par adresse

RouteLimiteVariable
POST /api/auth/login10 connexions échouées par 15 minutesRATE_LIMIT_LOGIN
POST /api/auth/signup10 par heureAucune
POST /api/auth/forgot-password5 par 15 minutesAucune
POST /api/auth/reset-password10 par 15 minutesAucune
POST /api/contact5 par heureAucune
POST /api/licenses/checkout10 par heureAucune
POST …/invitations/:id/resendUne fois par minute, cinq fois par invitationAucune

Une requête au-delà d'une limite répond 429, avec une phrase qui nomme ce qui a été limité et combien de temps attendre, comme « Too many sign-ups from this address. Wait an hour, then try again. » Les compteurs vivent dans la mémoire de l'API : un redémarrage les efface. Derrière un reverse proxy, définissez TRUST_PROXY avec le nombre de proxies devant l'API, sinon chaque visiteur est compté comme l'unique adresse du proxy.

L'assistant IA, ses conversations et ses propositions

Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.

La route de streaming de l'assistant, sa liste de modèles, les conversations enregistrées et les propositions de tâches.

Serveur MCP

Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.

Le point de terminaison MCP pour les agents de code, comment il est autorisé et quel espace de travail il lit.

Mises à jour de permissions en direct via socket.io

Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.

Le namespace socket.io que le tableau de bord écoute, son événement et comment une connexion est autorisée.

Routes du mode démo

Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.

Les routes qui n'existent que pour un build de démo publique.

Bloqué sur une étape ?

Trouvez une solution avant de tout recommencer.

Dépannage

Préférences des Cookies

Nous utilisons des cookies pour améliorer votre expérience de navigation, analyser le trafic du site et personnaliser le contenu. En cliquant sur "Accepter Tout", vous consentez à notre utilisation des cookies pour l'analyse et la publicité personnalisée.