Developers
API and webhooks
Standin opens up to your other tools in two ways: the API, to read and write your records from a script, Zapier or Make; and webhooks, to be notified the moment something happens. Both are included in the Pro and Max plans.
Authentication
Create a key in Standin, under Settings, "Webhooks & API" tab. It's shown only once: store it like a password. Each key opens a single CRM, the one where you created it, and can be revoked in one click. Send it in the Authorization header of every call.
curl https://standin.site/api/v1/fiches \
-H "Authorization: Bearer stn_YOUR_KEY"Each key gets 120 calls per minute. Beyond that, the response is 429 with a Retry-After header: wait that many seconds.
Error messages are in English, or in French if you send Accept-Language: fr.
Endpoints
GET /api/v1/fiches
Lists records, newest first. Filters: etape, modifie_depuis (ISO date); limite from 1 to 100 (50 by default). The response includes suivant: pass it as curseur to get the next page; null when you're done.
curl "https://standin.site/api/v1/fiches?etape=devis_envoye&limite=20" \
-H "Authorization: Bearer stn_YOUR_KEY"
{
"donnees": [
{
"id": "c4d2…",
"titre": "Mrs. Johnson",
"etape": { "cle": "devis_envoye", "libelle": "Quote sent" },
"valeurs": { "nom": "Mrs. Johnson", "telephone": "(555) 123-4567", "montant": 1250 },
"prochaine_action": {
"texte": "Follow up",
"echeance": "2026-09-30T14:00:00.000Z", "echeance_locale": "2026-09-30T09:00", "fuseau": "America/Chicago"
},
"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}
One record, with its stage, its values by field key, its next action and its notes. The next action due date is a true instant (echeance, in UTC), with the time as you read it (echeance_locale) and your time zone.
POST /api/v1/fiches
Creates a record. etape is optional (first stage by default). Each value is checked against your fields: nothing is written if a single one is rejected. The prochaine_action due date is an ISO date with its offset (Z or -05:00).
curl -X POST https://standin.site/api/v1/fiches \
-H "Authorization: Bearer stn_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"etape": "nouveau",
"valeurs": { "nom": "Mr. Miller", "telephone": "(555) 987-6543" },
"prochaine_action": { "texte": "Call back", "echeance": "2026-10-01T09:00:00Z" }
}'PATCH /api/v1/fiches/{id}
Updates a record. Only what you send changes; values are merged with the record's, and an empty value clears the field. Setting prochaine_action to null clears it.
curl -X PATCH https://standin.site/api/v1/fiches/c4d2… \
-H "Authorization: Bearer stn_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "etape": "gagne", "valeurs": { "montant": 1400 } }'POST /api/v1/fiches/{id}/notes
Adds a note to the record's history.
curl -X POST https://standin.site/api/v1/fiches/c4d2…/notes \
-H "Authorization: Bearer stn_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "texte": "Called, call back Monday" }'GET /api/v1/etapes
The CRM's stages, in board order.
GET /api/v1/champs
The CRM's fields: key, label, type, allowed options. The keys are what you use in valeurs.
GET /api/v1/rdv
Appointments from day du to day au (YYYY-MM-DD, 30 days by default). Each appointment gives its actual instant (debut, in UTC) and the time as you read it (debut_local, with fuseau).
curl "https://standin.site/api/v1/rdv?du=2026-10-01&au=2026-10-07" \
-H "Authorization: Bearer stn_YOUR_KEY"
{ "donnees": [ {
"id": "…", "titre": "Site visit", "fiche_id": "c4d2…",
"debut": "2026-10-02T19:00:00.000Z",
"debut_local": "2026-10-02T14:00", "fuseau": "America/Chicago",
"details": "Gate code 4B"
} ] }Records in the trash never appear in the API.
Everything the API writes shows up in the record history and in the audit log, signed "A tool connected through the API". Webhooks fire too.
Errors
An error always has the same shape: a stable code, for your program, and a readable message, for you. For rejected values, the list of fields and the reason for each.
HTTP 422
{
"erreur": {
"code": "valeurs_invalides",
"message": "…",
"champs": [ { "champ": "montant", "raison": "type" } ]
}
}401non_authentifie: Missing, malformed or unknown key.401cle_revoquee: This key has been revoked.403offre: The CRM's plan doesn't include the API (Pro or Max).403interdit: Action not allowed.404introuvable: Record not found in this CRM.405methode: Method not supported.400requete_invalide: Invalid request: the named field is missing or malformed.422valeurs_invalides: Some values were rejected: unknown field, computed field, wrong type or option not in the list.429trop_de_requetes: Too many calls: 120 per minute per key.500erreur_interne: Error on our side. Please try again in a moment.
Webhooks
In Settings, "Webhooks & API" tab, add your tool's https address and pick the events. Standin sends it a JSON POST for each event, signed with a secret shown only once, when you create it.
Events
fiche.creee: a record is createdfiche.modifiee: its values or notes changefiche.etape_changee: it moves to another stage (with etape_precedente)fiche.supprimee: it goes to the trashdevis.envoye: a quote is sent to the clientdevis.signe: the client accepts the quote onlinefacture.creee: an invoice or deposit invoice is issuedfacture.payee: an invoice is paid, manually or onlinerdv.pris: an appointment is bookedrdv.annule: an appointment is deletedmessage.recu: a client writes, on any channel
The message sent
Every event shares the same envelope: id (unique, so you can ignore a duplicate), type, version, cree_le, crm, donnees. The record is read at send time. Fields may be added; version only changes if an existing field changes meaning.
POST https://your-tool.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": "Mrs. Johnson", "etape": { "cle": "gagne", "libelle": "Won" }, "valeurs": { … } },
"etape_precedente": { "cle": "devis_envoye", "libelle": "Quote sent" }
}
}Verifying the signature
The X-Standin-Signature header is t=<timestamp>,v1=<signature>. The signature is the hex HMAC-SHA256 of "timestamp.body" with your secret. Reject a timestamp older than 5 minutes: that's your replay protection.
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"));
}Delivery
Respond with a 2xx in under 10 seconds. Otherwise Standin retries three times, after 10 seconds, 45 seconds and 2 minutes, and doesn't follow redirects. The log of the last 50 deliveries and the "Send a test" button are in Settings. Only public https addresses are accepted.
Zapier and Make
Standin speaks Zapier's REST Hooks: a Zap subscribes to an event when it's turned on, unsubscribes when it's turned off, and Standin removes on its own a subscription whose Zap is gone (410 response). With Make, there's no app to install: the Webhooks module receives events, and the HTTP module writes to Standin.
GET /api/v1/moi
Tests a key: returns the name of the CRM it opens. It's the connection test call for Zapier and Make.
{ "donnees": { "cle": { "nom": "Zapier" }, "crm": { "id": "8f1e…", "nom": "Johnson Plumbing" } } }POST /api/v1/webhooks
Subscribes an address to events. Same rules as in Settings: public https only. The signing secret is returned only here.
curl -X POST https://standin.site/api/v1/webhooks \
-H "Authorization: Bearer stn_YOUR_KEY" \
-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}
Removes a subscription from the key's CRM.
GET /api/v1/evenements/{type}/exemple
An example of what the event will send, in an array: the latest real one if there is one, otherwise an example built from your fields.
Make: add a Webhooks module, paste its address in Standin's Settings, then "Send a test". To write, use an HTTP module with the Authorization header.
A question about the API? Write to contact@standin.site.