Développeurs
Dix-sept opérations sur dix chemins, cinq événements sortants et une spécification OpenAPI 3.1 publique que Make et n8n importent tout seuls. Tout est ici : chaque paramètre un par un, des exemples qui fonctionnent tels quels, et la liste de ce que l'API ne fait pas.
Spécification OpenAPI 3.1, sans clé
https://app.blastack.com/api/openapi.json
Racine de l'API
https://app.blastack.com/api/v1
Collez la première adresse dans l'importateur de n8n ou de Make et les nœuds apparaissent seuls. Zapier ne lit pas OpenAPI : c'est précisément pour cela que ses étapes sont écrites à part, plus bas.
En un coup d'œil
Huit informations. Avec elles, la requête s'écrit sans lire plus loin.
| Quoi | Valeur | Remarque |
|---|---|---|
| Racine de l'API | https://app.blastack.com/api/v1 | Elle vit dans l'application, pas sur ce site commercial. Une seule adresse, et elle ne change pas. |
| Spécification | https://app.blastack.com/api/openapi.json | Publique et sans clé, pour qu'un importateur puisse la lire avant même d'avoir des identifiants. |
| Authentification | Authorization: Bearer blsk_<prefix>_<secret> | Dans l'en-tête, jamais dans l'adresse. Les adresses finissent dans le journal du serveur, dans celui du proxy devant lui et dans l'historique de qui l'a essayée à la main. |
| Format | application/json; charset=utf-8 | Du JSON à l'aller comme au retour. Ni XML ni formulaire. |
| Limite | 120 req/min · RateLimit-Remaining | Par clé et par minute. Chaque réponse indique combien il en reste et quand le compteur repart. |
| Pagination | page=1 · per_page=50 · ≤ 200 | La première page est la 1, pas la 0. Demander plus de deux cents est ramené à deux cents au lieu d'être refusé. |
| Erreurs | { error: { status, code, message } } | Toujours le même objet, avec un code stable pensé pour écrire une condition dessus. |
| Environnement de test | — | Il n'y en a pas. On travaille contre la production, d'où l'intérêt de commencer avec une clé en lecture seule. |
curl https://app.blastack.com/api/v1/people?per_page=1 \
-H "Authorization: Bearer blsk_a1b2c3d4e5f6_YOUR_SECRET"Ce qui existe
Les trois fonctionnent. Ce qui manque est plus bas, dans sa propre section et nommé à voix haute.
Pour que votre SIRH crée les personnes, les change de service et les désactive sans que personne ne le recopie à la main. C'est la moitié qui compte vraiment pour un service informatique : le jour où vous vous séparez de quelqu'un, le compte se désactive tout seul.
Filtres sur userName et externalId, pagination et modification partielle. Le service et l'adresse de travail sont lus, donc qui entre par là naît avec son service et son site déjà renseignés. La sortie désactive, elle ne supprime pas.
Entrer avec le compte de l'entreprise depuis Entra ID, Google Workspace ou Okta. Cela cohabite avec le code d'accès, par lequel entre la partie de l'effectif sans messagerie professionnelle.
On la configure en collant l'adresse de découverte du fournisseur, et elle est vérifiée auprès de lui avant d'être enregistrée. Les domaines de messagerie sont vérifiés par DNS. Il n'y a ni SAML ni LDAP.
Publier depuis le programme qui sait déjà que la ligne 3 s'arrête jeudi, désactiver qui sort du SIRH, et être appelé par nous quand quelque chose arrive au lieu de devoir demander toutes les cinq minutes.
Du JSON sur HTTPS, une clé d'API en en-tête, des portées par clé, des erreurs à code stable et des événements sortants signés. C'est ce que documente le reste de cette page.
Automatisation
Les trois ne se montent pas de la même façon, et le dire épargne l'après-midi qu'on perd à le découvrir. Make et n8n lisent la spécification et se configurent presque seuls ; Zapier ne la lit pas, donc là-bas chaque appel s'écrit à la main. Les trois marchent ; le travail n'est pas le même.
| Outil | Lit-il la spécification ? | Déclencheur conseillé |
|---|---|---|
| n8n | Oui, en entier | Nœud « Webhook » + POST /webhooks |
| Make | Oui, dans l'éditeur d'applications propres | « Custom webhook » + POST /webhooks |
| Zapier | Non | « Catch Hook » + POST /webhooks |
Le chemin le plus court des trois. On crée un identifiant d'en-tête, on colle l'adresse de la spécification dans l'importateur, et il reste un nœud par opération avec ses paramètres déjà en place.
Étapes
À savoir
Le nœud de webhook répond 200 avant d'exécuter la suite du flux, ce qui est exactement ce qu'il faut ici : nous abandonnons au bout de dix secondes et cela compte comme un échec.
Le module HTTP générique suffit à tout, et qui va monter beaucoup de scénarios peut charger la spécification dans l'éditeur d'applications propres et obtenir un module par opération.
Étapes
À savoir
Make facture à l'opération : un scénario qui interroge toutes les cinq minutes brûle huit mille opérations par mois pour ne presque rien trouver. Avec le webhook, on en dépense une par événement.
Zapier n'importe pas OpenAPI. On le monte avec les étapes génériques de webhooks, ou en construisant une intégration privée sur leur plateforme de développement, où chaque point d'entrée se déclare à la main.
Étapes
À savoir
Leurs déclencheurs par interrogation dépensent une tâche à chaque passage, qu'ils trouvent quelque chose ou non. Le « Catch Hook » ne dépense que quand il s'est vraiment passé quelque chose.
Clés
Aujourd'hui nous les émettons à la main et nous vous disons quelles portées elles portent. Il n'y a pas d'écran en libre-service et c'est dit plus bas, parmi ce qui manque. Chaque clé est liée à une entreprise, et aucune route ne lit un identifiant d'entreprise dans la requête : il n'y a nulle part où se tromper.
Dites-nous à quoi elle sert et ce qu'elle doit pouvoir faire, et nous l'émettons avec ces portées et aucune autre. Elle est montrée une seule fois : nous n'en gardons qu'une empreinte, donc une clé perdue se révoque et se réémet.
Dans l'en-tête d'autorisation, jamais dans l'adresse. Les adresses finissent dans le journal du serveur, dans celui du proxy devant lui et dans l'historique de qui l'a essayée à la main.
Dans votre gestionnaire de secrets, pas dans le dépôt. Elle commence par un préfixe reconnaissable précisément pour que les détecteurs de secrets l'attrapent si elle s'échappe.
L'API relève du module d'identité d'entreprise, celui qui ouvre aussi l'authentification unique et le provisioning. Si l'entreprise ne l'a pas souscrit, la réponse le dit avec ces mots-là et non par une erreur générique.
| Portée | Ce qu'elle ouvre |
|---|---|
| people:read | Lire l'effectif et les services et sites auxquels une publication peut être adressée. C'est tout ce dont un tableau de bord a besoin. |
| people:write | Créer, modifier et désactiver des personnes. Désactiver ferme leurs sessions : cela ne vient donc pas en cadeau avec la lecture. |
| announcements:read | Lire ce qui a été publié et qui a confirmé une lecture obligatoire. C'est séparé de la portée des personnes : une liste de noms et de postes, c'est l'annuaire, et le texte des publications ne l'est pas. |
| announcements:write | Publier sur le panneau d'affichage. La file de relecture de l'entreprise est respectée : une clé ne saute le circuit d'approbation de personne. |
| metrics:read | Les indicateurs agrégés. Personne n'y apparaît nommément. |
| webhooks:read | Voir les adresses enregistrées et le journal des livraisons. C'est ce qui répond à « pourquoi rien n'arrive » sans ouvrir de ticket. |
| webhooks:write | Enregistrer, modifier et supprimer des adresses d'événement sortant. La plus délicate de la liste : elle décide à quel serveur d'internet nous envoyons le contenu de vos publications. |
Points d'entrée
Groupées par famille. La colonne de la portée est celle à regarder au moment de demander la clé : si elle manque, la réponse dit laquelle il fallait et lesquelles la vôtre porte.
| Méthode | Chemin | Portée | Ce que cela fait |
|---|---|---|---|
| GET | /people | people:read | L'effectif, avec son service, son site et l'identifiant que chaque personne porte dans votre SIRH. Dix-sept paramètres, dont le filtre sur la date de dernière modification, qui est celui qui permet de synchroniser tous les quarts d'heure sans tout retélécharger. |
| GET | /people/{id} | people:read | Une personne précise, cherchée par notre identifiant ou par le vôtre. De quoi rafraîchir une fiche sans parcourir toute la liste. |
| POST | /people | people:write | Crée quelqu'un. C'est pour quand votre SIRH ne parle pas SCIM ; s'il le parle, préférez SCIM, qui gère aussi les sorties. Le service et le site se donnent par leur nom et sont créés s'ils n'existent pas. |
| PATCH | /people/{id} | people:write | Ne change que les champs envoyés. Un champ omis n'est pas touché : une synchronisation qui ne connaît que le poste ne peut effacer le site de personne. |
| DELETE | /people/{id} | people:write | Désactive ; ne supprime jamais. Les sessions sont fermées sur-le-champ, donc qui part un vendredi est dehors ce vendredi. Ce qu'il a publié reste. |
| GET | /audiences | people:read | Les services et les sites qui existent, avec combien de personnes dans chacun. C'est de là que sortent les noms auxquels une publication peut être adressée, et le filtre des groupes vides est celui qui trouve un mappage de provisioning cassé. |
| GET | /announcements | announcements:read | Tout ce qui a été publié, avec les lectures et les confirmations de chaque élément. Les brouillons et les refusés sont inclus pour qu'un tableau de bord puisse dessiner l'entonnoir entier. |
| GET | /announcements/{id} | announcements:read | Une publication précise. C'est l'étape suivante de l'identifiant renvoyé par une publication ou apporté par un événement sortant. |
| POST | /announcements | announcements:write | Publie sur le panneau d'affichage. Il faut dire qui signe et il n'y a pas de valeur par défaut. Si cette personne ne peut pas publier sans relecture, la publication entre dans la file et la réponse le dit. |
| GET | /announcements/{id}/acknowledgements | announcements:read | Qui a confirmé une lecture obligatoire et qui ne l'a pas fait, avec nom et heure. C'est la seule liste nominative de toute l'API, et elle l'est parce que c'est justement l'objet de la lecture obligatoire : un acte volontaire, signé et daté que l'on peut montrer à une inspection. |
| GET | /metrics | metrics:read | L'effectif du jour, les arrivées, les publications et la portée par publication et par service. Les mêmes chiffres que l'écran d'analyse, calculés par le même code. |
| GET | /webhooks | webhooks:read | Vos adresses enregistrées, chacune avec sa santé : échecs consécutifs, ce que votre serveur a répondu la dernière fois et, si nous l'avons mise en pause, pourquoi. |
| POST | /webhooks | webhooks:write | Enregistre une adresse et les événements qu'elle veut. La réponse apporte le secret de signature, et c'est la seule fois où il se voit. |
| GET | /webhooks/{id} | webhooks:read | Une adresse précise, avec sa santé. |
| PATCH | /webhooks/{id} | webhooks:write | Change ce que vous envoyez. Remettre l'adresse en actif lève aussi la pause appliquée après des échecs répétés et remet le compteur à zéro. |
| DELETE | /webhooks/{id} | webhooks:write | La supprime avec son historique. Pour cesser de recevoir un moment sans perdre l'historique, il vaut mieux la désactiver. |
| GET | /webhooks/{id}/deliveries | webhooks:read | Tout ce que nous avons tenté de vous envoyer : tentatives, ce que vous avez répondu et quand a lieu la suivante. L'identifiant est le même que celui parti dans l'en-tête : il se recoupe avec vos propres journaux. |
Paramètres
Aucune liste n'est abrégée : ce sont celles que le serveur vérifie. Un paramètre absent d'ici n'existe pas, et l'écrire renvoie une erreur qui nomme ceux que ce point d'entrée accepte au lieu de l'ignorer en silence.
La colonne de droite est en anglais à dessein. Elle vient du catalogue dont la spécification est également générée : c'est donc mot pour mot ce que n8n et Make affichent dans leurs nœuds. La traduire ici reviendrait à avoir deux versions qui, un jour, diraient des choses différentes.
people:read
L'effectif, avec son service, son site et l'identifiant que chaque personne porte dans votre SIRH. Dix-sept paramètres, dont le filtre sur la date de dernière modification, qui est celui qui permet de synchroniser tous les quarts d'heure sans tout retélécharger.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| page | entiermin. 1 | 1 | 2 | Page to return. The first page is 1, not 0. | |
| per_page | entiermin. 1 · max. 200 · hors bornes, la valeur est ramenée au lieu d'échouer | 50 | 100 | How many items per page. Anything above 200 is clamped to 200 rather than rejected: asking for more is a reasonable thing to want. | |
| sort | texte | created_at · updated_at · name · email | created_at | Field to sort by. Defaults to created_at. | |
| order | texte | asc · desc | asc | Sort direction. | |
| fields | texte · plusieurs, séparés par des virgules | external_id · email · name · job_title · department · center · role · status · language · created_at · updated_at | external_id,department,status | Comma-separated list of fields to return. `id` is always included. Use it to avoid pulling personal data you do not need. | |
| status | texte · plusieurs, séparés par des virgules | active · invited · disabled | active | Only people in these states. Several may be given. | |
| role | texte · plusieurs, séparés par des virgules | owner · admin · gestor_personas · responsable_local · informatico · editor · revisor · analista · employee | Only people with these roles. Several may be given. | ||
| department | texte · plusieurs, séparés par des virgules | Maintenance,Quality | Department name, or several separated by commas. Case-insensitive: your directory writing MANTENIMIENTO is not an error. | ||
| center | texte · plusieurs, séparés par des virgules | Site name, or several separated by commas. Case-insensitive. | |||
| no_department | booléen | Only people with no department. These are the ones who never see a targeted announcement, so this is the filter that finds a broken provisioning mapping. | |||
| language | texte · plusieurs, séparés par des virgules | es · ca · en · pt · fr · it · de · sv · nl · pl · ro · cs | Only people who picked this reading language. | ||
| texte | Exact email address, case-insensitive. | ||||
| external_id | texte | Exact external_id, as sent by your HR system over SCIM. | |||
| q | texte | garcia | Free text over name, email and job title. Case-insensitive, matches anywhere in the value. | ||
| updated_since | date ISO 8601 | 2026-08-01T00:00:00Z | Only people changed at or after this instant. This is the one that lets you sync every fifteen minutes without pulling two thousand rows every time. | ||
| created_since | date ISO 8601 | Only people added at or after this instant. | |||
| created_until | date ISO 8601 | Only people added before this instant. |
people:read
Une personne précise, cherchée par notre identifiant ou par le vôtre. De quoi rafraîchir une fiche sans parcourir toute la liste.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | a3f1… | Blastack id (a uuid) or the person's external_id from your HR system. A Blastack id is always a uuid and yours almost never is, so they cannot be confused; if one ever were, ours wins. |
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| fields | texte · plusieurs, séparés par des virgules | external_id · email · name · job_title · department · center · role · status · language · created_at · updated_at | external_id,department,status | Comma-separated list of fields to return. `id` is always included. Use it to avoid pulling personal data you do not need. |
people:write
Crée quelqu'un. C'est pour quand votre SIRH ne parle pas SCIM ; s'il le parle, préférez SCIM, qui gère aussi les sorties. Le service et le site se donnent par leur nom et sont créés s'ils n'existent pas.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| nameObligatoire | textelongueur max. 120 | Ana García | Full name, as it should appear on the wall. | ||
| textelongueur max. 200 | Work email. Optional: most of the workforce this product is for has none, and they get in with an invite code instead. Unique within the company. | ||||
| external_id | textelongueur max. 200 | EMP-0042 | The id this person has in your system. Store it and you can cross both lists later without matching names. | ||
| job_title | textelongueur max. 120 | Job title. | |||
| department | textelongueur max. 80 | Department name. Created if it does not exist. Without one, this person only ever sees company-wide announcements. | |||
| center | textelongueur max. 80 | Site name. Created if it does not exist. | |||
| role | texte | admin · gestor_personas · responsable_local · informatico · editor · revisor · analista · employee | employee | What they can do. `owner` cannot be given from the API: a key pasted in a cron job must not be able to mint an account that can cancel the subscription. | |
| status | texte | active · invited · disabled | active | `active` can sign in; `invited` is created but not counted as signed up yet; `disabled` is created already deactivated, which is what a backfill of former staff needs. | |
| language | texte | es · ca · en · pt · fr · it · de · sv · nl · pl · ro · cs | Reading language. Leave it out and they read in the company's, which is what you want unless you actually know. |
people:write
Ne change que les champs envoyés. Un champ omis n'est pas touché : une synchronisation qui ne connaît que le poste ne peut effacer le site de personne.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | a3f1… | Blastack id (a uuid) or the person's external_id from your HR system. A Blastack id is always a uuid and yours almost never is, so they cannot be confused; if one ever were, ours wins. |
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| name | textelongueur max. 120 | Full name. | |||
| textelongueur max. 200 | Work email. | ||||
| external_id | textelongueur max. 200 | The id this person has in your system. | |||
| job_title | textelongueur max. 120 | Job title. | |||
| department | textelongueur max. 80 | Department name. Created if it does not exist. | |||
| center | textelongueur max. 80 | Site name. Created if it does not exist. | |||
| role | texte | admin · gestor_personas · responsable_local · informatico · editor · revisor · analista · employee | What they can do. `owner` cannot be given from the API. | ||
| status | texte | active · invited · disabled | Their state. `disabled` also closes their sessions. | ||
| language | texte | es · ca · en · pt · fr · it · de · sv · nl · pl · ro · cs | Reading language. |
people:write
Désactive ; ne supprime jamais. Les sessions sont fermées sur-le-champ, donc qui part un vendredi est dehors ce vendredi. Ce qu'il a publié reste.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | a3f1… | Blastack id (a uuid) or the person's external_id from your HR system. A Blastack id is always a uuid and yours almost never is, so they cannot be confused; if one ever were, ours wins. |
people:read
Les services et les sites qui existent, avec combien de personnes dans chacun. C'est de là que sortent les noms auxquels une publication peut être adressée, et le filtre des groupes vides est celui qui trouve un mappage de provisioning cassé.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| type | texte | all · departments · centers | all | Return only departments, only sites, or both. | |
| q | texte | Free text over the name. Case-insensitive. | |||
| with_people | booléen | Only groups that have at least one active person. A department with nobody in it is almost always an old name left behind, and it is the usual cause of an announcement that reaches no one. | |||
| sort | texte | name · people | name | Field to sort by. Defaults to name. | |
| order | texte | asc · desc | asc | Sort direction. |
announcements:read
Tout ce qui a été publié, avec les lectures et les confirmations de chaque élément. Les brouillons et les refusés sont inclus pour qu'un tableau de bord puisse dessiner l'entonnoir entier.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| page | entiermin. 1 | 1 | 2 | Page to return. The first page is 1, not 0. | |
| per_page | entiermin. 1 · max. 200 · hors bornes, la valeur est ramenée au lieu d'échouer | 50 | 100 | How many items per page. Anything above 200 is clamped to 200 rather than rejected: asking for more is a reasonable thing to want. | |
| sort | texte | published_at · created_at · updated_at · title | published_at | Field to sort by. Defaults to published_at. | |
| order | texte | asc · desc | asc | Sort direction. | |
| fields | texte · plusieurs, séparés par des virgules | title · body · status · kind · language · audience · community · section · author · notify · comments_enabled · pinned · acknowledgements · reads · published_at · created_at · updated_at · url | external_id,department,status | Comma-separated list of fields to return. `id` is always included. Use it to avoid pulling personal data you do not need. | |
| status | texte · plusieurs, séparés par des virgules | draft · pending_review · published · rejected · scheduled · archived | published,scheduled | Only these states. Several may be given. `scheduled` means it is written and waiting for its hour. | |
| author | texte | Who signs it: our id, their email or their external_id. Any of the three. | |||
| audience_type | texte | all · departments · centers | Only announcements aimed this way. | ||
| department | texte · plusieurs, séparés par des virgules | Only announcements aimed at these departments, by name. Several may be given. | |||
| center | texte · plusieurs, séparés par des virgules | Only announcements aimed at these sites, by name. | |||
| community | texte | Only announcements in this community, by id or by name. | |||
| requires_acknowledgement | booléen | Only required reading, or only the rest. This is the filter a compliance report is built on. | |||
| pinned | booléen | Only pinned announcements, or only the rest. | |||
| q | texte | Free text over title and body. Case-insensitive. | |||
| published_since | date ISO 8601 | Published at or after this instant. | |||
| published_until | date ISO 8601 | Published before this instant. | |||
| created_since | date ISO 8601 | Written at or after this instant. | |||
| updated_since | date ISO 8601 | Changed at or after this instant. |
announcements:read
Une publication précise. C'est l'étape suivante de l'identifiant renvoyé par une publication ou apporté par un événement sortant.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | The announcement id. |
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| fields | texte · plusieurs, séparés par des virgules | title · body · status · kind · language · audience · community · section · author · notify · comments_enabled · pinned · acknowledgements · reads · published_at · created_at · updated_at · url | external_id,department,status | Comma-separated list of fields to return. `id` is always included. Use it to avoid pulling personal data you do not need. |
announcements:write
Publie sur le panneau d'affichage. Il faut dire qui signe et il n'y a pas de valeur par défaut. Si cette personne ne peut pas publier sans relecture, la publication entre dans la file et la réponse le dit.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| bodyObligatoire | textelongueur max. 8000 | The text. Plain text; line breaks are kept. | |||
| authorObligatoire | texte | EMP-0042 | Who signs it: our id, their email or their external_id. Must be an active person in this company. | ||
| title | textelongueur max. 160 | Headline. | |||
| audience | objet | Who it goes to. Leave it out and it goes to everyone. Names work as well as ids, case-insensitively, because your ERP has 'Maintenance' and not a uuid of ours. Nothing is created here: an unknown name is a typo in a script, and the reply tells you which one it was. | |||
| audience.type | texte | all · departments · centers | all | Aim at everyone, at departments or at sites. | |
| audience.ids | liste | ["Maintenance","Quality"] | Department or site names, or their ids. Required unless type is `all`. | ||
| community | texte | Which community it belongs to, by id or by name. Leave it out and it goes on the main wall, which everybody sees. The author has to belong to the community, or be posting to the default one: an API key is not a way into a community its signer is not in. | |||
| section | texte | Which section it belongs to, by id or by name. It must belong to the same community. | |||
| publish_at | date ISO 8601 | 2026-09-01T06:00:00Z | Publish later, at this instant. It must be in the future. The reply comes back with `status: scheduled` and the wall shows it when the hour arrives. Leave it out to publish now. Note this means two clocks are involved — yours and ours — so if your system already schedules, prefer calling us at the right moment. | ||
| requires_acknowledgement | booléen | false | Required reading: everyone it reaches gets a notification with a confirm button, and who confirmed is on record. Only signers who can publish without review may ask for it. | ||
| notify | booléen | true | Whether it makes a sound. Written the right way round on purpose: the screen has a 'publish without notifying' checkbox because a form that loses a field should still notify, but here you write the whole JSON and a field called `silent` reads wrong at three in the morning. Default is true. | ||
| comments_enabled | booléen | true | Whether people can comment on it. | ||
| pinned | booléen | false | Keep it at the top of the wall. | ||
| language | texte | es · ca · en · pt · fr · it · de · sv · nl · pl · ro · cs | What language the text is written in. Leave it out and the company's is used. Getting this right matters: a Catalan original labelled as Spanish is shown to a Spanish reader without the 'not translated' notice that tells them nothing is broken. |
announcements:read
Qui a confirmé une lecture obligatoire et qui ne l'a pas fait, avec nom et heure. C'est la seule liste nominative de toute l'API, et elle l'est parce que c'est justement l'objet de la lecture obligatoire : un acte volontaire, signé et daté que l'on peut montrer à une inspection.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | The announcement id. |
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| page | entiermin. 1 | 1 | 2 | Page to return. The first page is 1, not 0. | |
| per_page | entiermin. 1 · max. 200 · hors bornes, la valeur est ramenée au lieu d'échouer | 50 | 100 | How many items per page. Anything above 200 is clamped to 200 rather than rejected: asking for more is a reasonable thing to want. | |
| state | texte | all · acknowledged · pending | all | Everyone, only those who confirmed, or only those still pending. | |
| department | texte · plusieurs, séparés par des virgules | Only people in these departments, by name. | |||
| center | texte · plusieurs, séparés par des virgules | Only people at these sites, by name. | |||
| sort | texte | name · acknowledged_at | name | Field to sort by. Defaults to name. | |
| order | texte | asc · desc | asc | Sort direction. |
metrics:read
L'effectif du jour, les arrivées, les publications et la portée par publication et par service. Les mêmes chiffres que l'écran d'analyse, calculés par le même code.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| period_days | entiermin. 1 · max. 365 | 30 | 90 | How many days back the period covers. Applies to every figure with a period, including the reach lists. | |
| include | texte · plusieurs, séparés par des virgules | workforce · announcements · reach_by_announcement · reach_by_department | workforce,announcements | Which blocks to compute, comma-separated. Leave it out for all of them. `reach_by_announcement` is the expensive one: skip it if your dashboard only draws the headline figures. |
webhooks:read
Vos adresses enregistrées, chacune avec sa santé : échecs consécutifs, ce que votre serveur a répondu la dernière fois et, si nous l'avons mise en pause, pourquoi.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| page | entiermin. 1 | 1 | 2 | Page to return. The first page is 1, not 0. | |
| per_page | entiermin. 1 · max. 200 · hors bornes, la valeur est ramenée au lieu d'échouer | 50 | 100 | How many items per page. Anything above 200 is clamped to 200 rather than rejected: asking for more is a reasonable thing to want. | |
| event | texte | announcement.published · announcement.pending_review · announcement.acknowledged · person.created · person.deactivated | Only endpoints subscribed to this event. | ||
| active | booléen | Only live endpoints, or only the switched-off and paused. |
webhooks:write
Enregistre une adresse et les événements qu'elle veut. La réponse apporte le secret de signature, et c'est la seule fois où il se voit.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| urlObligatoire | textelongueur max. 500 | https://hooks.example.com/blastack | Where we POST. https only, no credentials, no fragment. | ||
| eventsObligatoire | liste | announcement.published · announcement.pending_review · announcement.acknowledged · person.created · person.deactivated | ["announcement.published"] | Which events this endpoint wants. At least one. | |
| name | textelongueur max. 120 | Zapier · switchboard | What it is for, in your words. It is the only thing that lets you delete the right one six months from now. | ||
| secret | textelongueur max. 200 | Your own signing secret, if you would rather set it than have one generated. At least 32 characters. | |||
| active | booléen | true | Start delivering straight away. |
webhooks:read
Une adresse précise, avec sa santé.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | The webhook endpoint id. |
webhooks:write
Change ce que vous envoyez. Remettre l'adresse en actif lève aussi la pause appliquée après des échecs répétés et remet le compteur à zéro.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | The webhook endpoint id. |
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| url | textelongueur max. 500 | Where we POST. https only. | |||
| events | liste | announcement.published · announcement.pending_review · announcement.acknowledged · person.created · person.deactivated | Which events this endpoint wants. At least one. | ||
| name | textelongueur max. 120 | What it is for. | |||
| active | booléen | Switch delivery on or off. Turning it on clears a pause. | |||
| rotate_secret | booléen | Generate a new signing secret and return it once in this reply. |
webhooks:write
La supprime avec son historique. Pour cesser de recevoir un moment sans perdre l'historique, il vaut mieux la désactiver.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | The webhook endpoint id. |
webhooks:read
Tout ce que nous avons tenté de vous envoyer : tentatives, ce que vous avez répondu et quand a lieu la suivante. L'identifiant est le même que celui parti dans l'en-tête : il se recoupe avec vos propres journaux.
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| idObligatoire | texte | The webhook endpoint id. |
| Paramètre | Type | Valeurs admises | Par défaut | Exemple | Ce que cela fait |
|---|---|---|---|---|---|
| page | entiermin. 1 | 1 | 2 | Page to return. The first page is 1, not 0. | |
| per_page | entiermin. 1 · max. 200 · hors bornes, la valeur est ramenée au lieu d'échouer | 50 | 100 | How many items per page. Anything above 200 is clamped to 200 rather than rejected: asking for more is a reasonable thing to want. | |
| status | texte | pending · delivered · given_up | Only deliveries in this state. | ||
| event | texte | announcement.published · announcement.pending_review · announcement.acknowledged · person.created · person.deactivated | Only deliveries of this event type. | ||
| since | date ISO 8601 | Only events that happened at or after this instant. |
Exemples
Avec la requête entière et la réponse entière. Changez la clé et les noms ; le reste fonctionne tel quel.
Quand la GMAO clôt l'ordre d'arrêt
C'est le cas qu'on demande toujours. Votre système sait déjà que la ligne 3 s'arrête jeudi ; avec cet appel, il le publie lui-même, adressé aux services concernés et en demandant une confirmation de lecture, sans que personne ne saisisse rien deux fois.
Requête
curl -X POST https://app.blastack.com/api/v1/announcements \
-H "Authorization: Bearer blsk_a1b2c3d4e5f6_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"author": "EMP-0042",
"title": "Arrêt de la ligne 3 jeudi",
"body": "Jeudi 4 à 06:00, arrêt de la ligne 3 pour maintenance programmée. L'équipe du matin embauche à l'heure habituelle et passe sur la ligne 2.",
"audience": {
"type": "departments",
"ids": [
"Maintenance",
"Qualité"
]
},
"requires_acknowledgement": true,
"notify": true,
"language": "fr"
}'Réponse · 201
{
"id": "6b1f0f1e-0c2a-4c5e-9a3d-2f5b8c7d1e40",
"title": "Arrêt de la ligne 3 jeudi",
"body": "Jeudi 4 à 06:00, arrêt de la ligne 3 pour maintenance programmée. L'équipe du matin embauche à l'heure habituelle et passe sur la ligne 2.",
"status": "published",
"kind": "news",
"language": "fr",
"audience": {
"type": "departments",
"ids": [
"9c1d7e5f-2a3b-4c5d-8e9f-0a1b2c3d4e5f",
"44ab7e5f-2a3b-4c5d-8e9f-0a1b2c3d4e5f"
],
"names": [
"Maintenance",
"Qualité"
]
},
"community": null,
"section": null,
"author": {
"id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
"name": "Ana García",
"email": "ana.garcia@empresa.com",
"external_id": "EMP-0042"
},
"notify": true,
"comments_enabled": true,
"pinned": false,
"acknowledgements": {
"required": true,
"confirmed": 0
},
"reads": 0,
"published_at": "2026-09-01T06:00:00.000Z",
"created_at": "2026-09-01T06:00:00.000Z",
"updated_at": "2026-09-01T06:00:00.000Z",
"url": "https://app.blastack.com/inicio#post-6b1f0f1e-0c2a-4c5e-9a3d-2f5b8c7d1e40"
}La cible se donne par nom et non par identifiant, parce que c'est ce que votre système a sous la main. Si le nom n'existe pas, la réponse dit lequel et rien n'est publié : une demi-publication serait pire.
Quand le SIRH marque le départ
Si votre système parle SCIM, cela se fait déjà tout seul et cet appel est inutile. S'il ne le parle pas — ce qui est la norme dans une usine —, une ligne suffit pour désactiver la personne et fermer ses sessions sur-le-champ. Le chemin accepte votre propre identifiant : aucune table d'équivalences à maintenir.
Requête
curl -X DELETE https://app.blastack.com/api/v1/people/EMP-0042 \
-H "Authorization: Bearer blsk_a1b2c3d4e5f6_YOUR_SECRET"Réponse · 200
{
"id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
"external_id": "EMP-0042",
"email": "ana.garcia@empresa.com",
"name": "Ana García",
"job_title": "Chef d'équipe",
"department": "Maintenance",
"center": "Atelier 2",
"role": "editor",
"status": "disabled",
"language": null,
"created_at": "2026-02-11T08:14:00.000Z",
"updated_at": "2026-09-01T07:40:22.000Z"
}Cela désactive ; cela ne supprime pas. Ce qu'elle a publié reste, parce qu'un panneau plein de trous n'aide personne. Appeler deux fois n'est pas une erreur.
Chaque matin, ou la veille d'un audit
Un scénario Make ou un flux n8n qui demande les personnes en attente et les écrit dans une feuille : nom, service et confirmation ou non. C'est le rapport qu'un audit réclame, et celui qui évite de courir après quelqu'un dans un couloir.
Requête
curl -G https://app.blastack.com/api/v1/announcements/6b1f0f1e-0c2a-4c5e-9a3d-2f5b8c7d1e40/acknowledgements \
--data-urlencode "state=pending" \
--data-urlencode "department=Maintenance" \
--data-urlencode "per_page=200" \
-H "Authorization: Bearer blsk_a1b2c3d4e5f6_YOUR_SECRET"Réponse · 200
{
"announcement": {
"id": "6b1f0f1e-0c2a-4c5e-9a3d-2f5b8c7d1e40",
"title": "Arrêt de la ligne 3 jeudi"
},
"summary": {
"recipients": 34,
"acknowledged": 27,
"pending": 7
},
"data": [
{
"person": {
"id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
"name": "Ana García",
"email": "ana.garcia@empresa.com",
"external_id": "EMP-0042",
"department": "Maintenance",
"center": "Atelier 2"
},
"acknowledged": false,
"acknowledged_at": null
}
],
"page": 1,
"per_page": 200,
"total": 7
}Le résumé se compte sur la population entière et non sur la page ni sur le filtre, pour que le « 12 sur 30 » veuille encore dire quelque chose. L'heure de la confirmation est celle de la première fois et n'est plus jamais touchée.
Événements sortants
C'est ce qui rend tout cela vraiment connectable. Sans événements sortants, le déclencheur de votre scénario doit être « toutes les cinq minutes, demande », et c'est lent, facturé au passage et presque toujours pour rien.
| Événement | Quand il part |
|---|---|
| announcement.published | Quelque chose est paru sur le panneau, quel que soit le chemin emprunté : le compositeur, l'éditeur complet, cette API, la file de relecture ou une publication programmée arrivée à son heure. Le type voyage à l'intérieur, au cas où seules les publications simples vous intéressent et pas les sondages ou les événements. |
| announcement.pending_review | Une publication attend une approbation. Cela ne part que dans les entreprises dont la file de relecture est activée. |
| announcement.acknowledged | Quelqu'un a confirmé une lecture obligatoire. Un événement par personne, avec qui et quand. |
| person.created | Quelqu'un a été créé, peu importe par où : provisioning, code d'accès, authentification unique, écran d'administration ou cette API. |
| person.deactivated | Quelqu'un a été désactivé. Comme personne n'est jamais supprimé ici, c'est le signal de sortie. |
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"type": "announcement.published",
"occurred_at": "2026-09-01T06:00:00.000Z",
"organization_id": "0a9b8c7d-6e5f-4a3b-8c9d-0e1f2a3b4c5d",
"data": {
"announcement": {
"id": "6b1f0f1e-0c2a-4c5e-9a3d-2f5b8c7d1e40",
"title": "Parada de la línea 3 el jueves",
"body": "El jueves 4 a las 06:00 para la línea 3 por mantenimiento programado.",
"kind": "news",
"language": "es",
"requires_acknowledgement": true,
"audience": {
"type": "departments",
"names": [
"Mantenimiento",
"Calidad"
]
},
"community": "Planta de Getafe",
"author": {
"id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
"name": "Ana García",
"email": "ana.garcia@empresa.com",
"external_id": "EMP-0042"
},
"url": "https://app.blastack.com/inicio#post-6b1f0f1e-0c2a-4c5e-9a3d-2f5b8c7d1e40",
"status": "published"
}
}
}Ce qu'il y a dedans change avec l'événement ; l'enveloppe, non. L'identifiant ne change pas entre les tentatives : écarter un doublon tient en une ligne de votre côté.
| En-tête | À quoi cela sert |
|---|---|
| blastack-event | Ce qui s'est passé. C'est la valeur sur laquelle on branche. |
| blastack-event-id | L'identifiant de l'événement. Il ne change pas entre les tentatives : c'est celui qui sert à ne jamais exécuter deux fois la même chose. |
| blastack-delivery-attempt | De quelle tentative il s'agit, en commençant par la première. |
| blastack-signature | La signature. C'est la seule chose qui sépare un envoi de nous d'un envoi inventé par qui découvre votre adresse. |
La signature est un HMAC-SHA256 sur l'horodatage, un point et le corps brut, non analysé. C'est le format qu'utilisent les passerelles de paiement, donc celui que vous avez probablement déjà écrit une fois.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody, headers, secret) {
const sent = headers["blastack-signature"] ?? "";
const t = /t=(\d+)/.exec(sent)?.[1];
const v1 = /v1=([0-9a-f]+)/.exec(sent)?.[1];
if (!t || !v1) return false;
const mine = createHmac("sha256", secret)
.update(`${t}.${rawBody}`, "utf8")
.digest("hex");
if (v1.length !== mine.length) return false;
if (!timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(mine, "hex"))) {
return false;
}
return Math.abs(Date.now() / 1000 - Number(t)) < 300;
}Comparez en temps constant et rejetez tout horodatage vieux de plus de quelques minutes. Sans cette seconde vérification, une copie d'un envoi ancien peut vous être renvoyée pendant des années avec une signature toujours valable.
Erreurs
Toute erreur renvoie le même objet, avec un code pensé pour écrire une condition dessus. Les codes ne sont jamais renommés : ils sont ajoutés. Le message d'à côté est pour qui lit le journal, et celui-là peut changer.
{
"error": {
"status": 403,
"code": "insufficient_scope",
"message": "This API key does not have the \"metrics:read\" scope.",
"required_scope": "metrics:read",
"granted_scopes": [
"people:read"
]
},
"documentation": "https://blastack.com/en/developers"
}Un paramètre inconnu est refusé, pas ignoré. Un filtre écarté en silence vous renvoie plus de données que demandé et rien ne vous prévient.
RateLimit-Limit · RateLimit-Remaining · RateLimit-Reset · Retry-After
| Code | Quand il sort |
|---|---|
| invalid_token | 401 · La clé manque, est mal écrite ou a été révoquée. Nous ne disons pas laquelle des trois. |
| insufficient_scope | 403 · La clé est valide mais ne porte pas la portée que cet appel demande. La réponse dit laquelle il fallait et lesquelles elle a. |
| module_required | 403 · L'entreprise n'a pas souscrit le module d'identité d'entreprise, celui dont relève l'API. |
| read_only | 403 · La période d'essai est terminée et l'entreprise est en lecture seule. Cela ne touche que ce qui écrit. |
| rate_limited | 429 · Plus de requêtes que permis en une minute. La réponse dit combien de secondes attendre. |
| invalid_request | 400 · Un champ manque, est en trop ou n'est pas compris. Le message nomme le paramètre exact et liste les valeurs admises. |
| not_found | 404 · Rien à vous avec cet identifiant. C'est aussi ce que l'on reçoit pour quelque chose appartenant à une autre entreprise : distinguer les deux serait un moyen de découvrir ce qui existe ailleurs. |
| conflict | 409 · Cela entre en conflit avec ce qui existe déjà : deux personnes avec la même adresse, deux adresses d'événement identiques. La réponse apporte l'identifiant de ce qui bloquait, pour pouvoir continuer. |
| server_error | 500 · Quelque chose a cassé chez nous. Rien de l'erreur ne sort dans la réponse ; l'ensemble reste dans notre journal. |
Limites
Ce que l'API ne fait pas
Qui va intégrer a besoin des limites avant de commencer, pas quand un demi-scénario est déjà monté. Cette liste est ce qu'un développeur va chercher sans le trouver, et elle est mise à jour dès que quelque chose cesse d'être vrai.
Pour les machines
La moitié d'une évaluation d'achat consiste aujourd'hui à demander à un assistant si cela se connecte à quelque chose. La réponse est donc écrite pour être lisible sans compte et sans rien deviner.
Ce qu'on nous demande le plus est ce qui s'écrit ensuite. Et si quelque chose de cette page ne colle pas avec ce que répond le serveur, c'est une faute de notre part et nous voulons le savoir le jour même.