Développeurs

API et webhooks

Standin s'ouvre à vos autres outils de deux façons : l'API, pour lire et écrire vos fiches depuis un script, Zapier ou Make ; les webhooks, pour être prévenu dès que quelque chose arrive. Les deux sont compris dans les offres Pro et Max.

Authentification

Créez une clé dans Standin, Réglages, onglet « Webhooks et API ». Elle s'affiche une seule fois : rangez-la comme un mot de passe. Chaque clé ouvre un seul CRM, celui où vous l'avez créée, et se révoque en un clic. Envoyez-la dans l'en-tête Authorization de chaque appel.

curl https://standin.site/api/v1/fiches \
  -H "Authorization: Bearer stn_VOTRE_CLE"

Chaque clé a droit à 120 appels par minute. Au-delà, la réponse est 429 avec l'en-tête Retry-After : attendez ce nombre de secondes.

Les messages d'erreur sont en anglais, ou en français si vous envoyez Accept-Language: fr.

Les appels

GET /api/v1/fiches

Liste les fiches, de la plus récente à la plus ancienne. Filtres : etape, modifie_depuis (date ISO) ; limite de 1 à 100 (50 par défaut). La réponse donne suivant : passez-le en curseur pour la page suivante ; null quand c'est fini.

curl "https://standin.site/api/v1/fiches?etape=devis_envoye&limite=20" \
  -H "Authorization: Bearer stn_VOTRE_CLE"

{
  "donnees": [
    {
      "id": "c4d2…",
      "titre": "Mme Durand",
      "etape": { "cle": "devis_envoye", "libelle": "Devis envoyé" },
      "valeurs": { "nom": "Mme Durand", "telephone": "06 12 34 56 78", "montant": 1250 },
      "prochaine_action": {
        "texte": "Relancer",
        "echeance": "2026-09-30T07:00:00.000Z", "echeance_locale": "2026-09-30T09:00", "fuseau": "Europe/Paris"
      },
      "notes": null,
      "cree_le": "2026-09-20T14:02:11.000Z",
      "modifie_le": "2026-09-27T09:12:44.000Z"
    }
  ],
  "suivant": "WyIyMDI2LTA5LTIw…"
}

GET /api/v1/fiches/{id}

Une fiche, avec son étape, ses valeurs par clé de champ, sa prochaine action et ses notes. L'échéance de la prochaine action est un vrai instant (echeance, en UTC), avec l'heure telle que vous la lisez (echeance_locale) et votre fuseau.

POST /api/v1/fiches

Crée une fiche. etape est facultative (première étape par défaut). Chaque valeur est vérifiée contre vos champs : rien n'est écrit si une seule est refusée. L'échéance de prochaine_action est une date ISO avec son fuseau (Z ou +02:00).

curl -X POST https://standin.site/api/v1/fiches \
  -H "Authorization: Bearer stn_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
    "etape": "nouveau",
    "valeurs": { "nom": "M. Martin", "telephone": "06 98 76 54 32" },
    "prochaine_action": { "texte": "Rappeler", "echeance": "2026-10-01T09:00:00Z" }
  }'

PATCH /api/v1/fiches/{id}

Modifie une fiche. Seul ce que vous envoyez change ; les valeurs se fusionnent avec celles de la fiche, et une valeur vide efface le champ. prochaine_action à null l'efface.

curl -X PATCH https://standin.site/api/v1/fiches/c4d2… \
  -H "Authorization: Bearer stn_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{ "etape": "gagne", "valeurs": { "montant": 1400 } }'

POST /api/v1/fiches/{id}/notes

Ajoute une note à l'historique de la fiche.

curl -X POST https://standin.site/api/v1/fiches/c4d2…/notes \
  -H "Authorization: Bearer stn_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{ "texte": "Appelé, rappeler lundi" }'

GET /api/v1/etapes

Les étapes du CRM, dans l'ordre du tableau.

GET /api/v1/champs

Les champs du CRM : clé, libellé, type, choix possibles. Les clés servent dans valeurs.

GET /api/v1/rdv

Les rendez-vous, du jour du au jour au (AAAA-MM-JJ, 30 jours par défaut). Chaque rendez-vous donne son vrai instant (debut, en UTC) et l'heure telle que vous la lisez (debut_local, avec fuseau).

curl "https://standin.site/api/v1/rdv?du=2026-10-01&au=2026-10-07" \
  -H "Authorization: Bearer stn_VOTRE_CLE"

{ "donnees": [ {
  "id": "…", "titre": "Visite chantier", "fiche_id": "c4d2…",
  "debut": "2026-10-02T12:00:00.000Z",
  "debut_local": "2026-10-02T14:00", "fuseau": "Europe/Paris",
  "details": "Code portail 4B"
} ] }

Les fiches à la corbeille n'apparaissent jamais dans l'API.

Tout ce que l'API écrit apparaît dans l'historique des fiches et dans le journal d'audit, signé « Un outil branché par l'API ». Les webhooks partent aussi.

Erreurs

Une erreur a toujours la même forme : un code stable, pour votre programme, et un message lisible, pour vous. Pour des valeurs refusées, la liste des champs et la raison de chacun.

HTTP 422
{
  "erreur": {
    "code": "valeurs_invalides",
    "message": "…",
    "champs": [ { "champ": "montant", "raison": "type" } ]
  }
}
  • 401 non_authentifie : Clé absente, mal formée ou inconnue.
  • 401 cle_revoquee : Cette clé a été révoquée.
  • 403 offre : L'offre du CRM ne comprend pas l'API (Pro ou Max).
  • 403 interdit : Action non permise.
  • 404 introuvable : Fiche introuvable dans ce CRM.
  • 405 methode : Méthode non prise en charge.
  • 400 requete_invalide : Requête invalide : le champ nommé est manquant ou mal formé.
  • 422 valeurs_invalides : Des valeurs sont refusées : champ inconnu, calculé, mauvais type ou choix absent de la liste.
  • 429 trop_de_requetes : Trop d'appels : 120 par minute et par clé.
  • 500 erreur_interne : Erreur de notre côté. Réessayez dans un instant.

Webhooks

Dans Réglages, onglet « Webhooks et API », ajoutez l'adresse https de votre outil et choisissez les événements. Standin y envoie un POST en JSON à chaque événement, signé avec un secret affiché une seule fois à la création.

Événements

  • fiche.creee : une fiche est créée
  • fiche.modifiee : ses valeurs ou ses notes changent
  • fiche.etape_changee : elle change d'étape (avec etape_precedente)
  • fiche.supprimee : elle part à la corbeille
  • devis.envoye : un devis part au client
  • devis.signe : le client accepte le devis en ligne
  • facture.creee : une facture ou un acompte est émis
  • facture.payee : une facture est payée, à la main ou en ligne
  • rdv.pris : un rendez-vous est pris
  • rdv.annule : un rendez-vous est supprimé
  • message.recu : un client écrit, sur n'importe quel canal

Le message envoyé

Tous les événements partagent la même enveloppe : id (unique, pour ignorer un doublon), type, version, cree_le, crm, donnees. La fiche est lue au moment de l'envoi. Des champs peuvent s'ajouter ; version ne change que si un champ existant change de sens.

POST https://votre-outil.example/standin
X-Standin-Event: fiche.etape_changee
X-Standin-Signature: t=1790000000,v1=5f2b…

{
  "id": "2b0c6c1e-…",
  "type": "fiche.etape_changee",
  "version": 1,
  "cree_le": "2026-09-27T09:12:44.120Z",
  "crm": { "id": "8f1e…" },
  "donnees": {
    "fiche": { "id": "c4d2…", "titre": "Mme Durand", "etape": { "cle": "gagne", "libelle": "Gagné" }, "valeurs": { … } },
    "etape_precedente": { "cle": "devis_envoye", "libelle": "Devis envoyé" }
  }
}

Vérifier la signature

L'en-tête X-Standin-Signature vaut t=<horodatage>,v1=<signature>. La signature est le HMAC-SHA256, en hexadécimal, de « horodatage.corps » avec votre secret. Refusez un horodatage de plus de 5 minutes : c'est la protection contre le rejeu.

import { createHmac, timingSafeEqual } from "node:crypto";

function verifier(secret, entete, corpsBrut) {
  const t = /t=(\d+)/.exec(entete)?.[1];
  const v1 = /v1=([0-9a-f]{64})/.exec(entete)?.[1];
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const attendu = createHmac("sha256", secret).update(`${t}.${corpsBrut}`).digest();
  return timingSafeEqual(attendu, Buffer.from(v1, "hex"));
}

Livraison

Répondez 2xx en moins de 10 secondes. Sinon, Standin réessaie trois fois, après 10 secondes, 45 secondes et 2 minutes, et ne suit pas les redirections. Le journal des 50 dernières livraisons et le bouton « Envoyer un test » sont dans les Réglages. Seules les adresses publiques en https sont acceptées.

Zapier et Make

Standin parle la langue des REST Hooks de Zapier : un Zap s'abonne à un événement quand on l'allume, se désabonne quand on le coupe, et Standin retire de lui-même un abonnement dont le Zap a disparu (réponse 410). Avec Make, pas d'application à installer : le module Webhooks reçoit les événements, le module HTTP écrit dans Standin.

GET /api/v1/moi

Teste une clé : rend le nom du CRM qu'elle ouvre. C'est l'appel de test de connexion de Zapier et de Make.

{ "donnees": { "cle": { "nom": "Zapier" }, "crm": { "id": "8f1e…", "nom": "Plomberie Durand" } } }

POST /api/v1/webhooks

Abonne une adresse à des événements. Mêmes règles que dans les Réglages : https public seulement. Le secret de signature n'est rendu qu'ici.

curl -X POST https://standin.site/api/v1/webhooks \
  -H "Authorization: Bearer stn_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://hooks.zapier.com/hooks/catch/…", "evenements": ["fiche.creee"] }'

HTTP 201
{ "donnees": { "id": "5a1c…", "url": "https://hooks.zapier.com/…", "evenements": ["fiche.creee"], "secret": "whsec_…" } }

DELETE /api/v1/webhooks/{id}

Retire un abonnement du CRM de la clé.

GET /api/v1/evenements/{type}/exemple

Un exemple de ce que l'événement enverra, dans un tableau : le dernier vrai s'il y en a un, sinon un exemple construit sur vos champs.

Make : ajoutez un module Webhooks, collez son adresse dans les Réglages de Standin, puis « Envoyer un test ». Pour écrire, un module HTTP avec l'en-tête Authorization.

Une question sur l'API ? Écrivez à contact@standin.site.