Un panneau Booster est une petite application web créée dans AYETO Booster Studio. Un panneau peut avoir sa propre base de données, et les endpoints de cette page permettent à votre serveur de lire et de modifier cette base de données avec une clé API : importer des données dans un panneau, les synchroniser avec un autre système ou traiter ce que les utilisateurs du panneau ont saisi.
Tous les endpoints se trouvent sous /api/v3/booster/database/private/. Les panneaux eux-mêmes
accèdent à leur base de données par un autre chemin d'accès, qui n'est pas décrit ici.
Concepts
Les panneaux et leur base de données
Chaque panneau a au plus une base de données. Elle existe lorsque le paramètre Accès à la base de données
du panneau (détails du panneau dans l'application) vaut Base de données publique ou Base de données privée ;
avec Pas de base de données, tous les endpoints de cette page répondent 403. Les modes public et
privé peuvent tous deux être utilisés via cette API. La base de données est créée à la première utilisation et
est supprimée avec le panneau.
Chaque requête désigne le panneau dans l'en-tête panel-id. L'ID du panneau est affiché, avec
un bouton de copie, en haut des détails du panneau dans l'application.
Collections et enregistrements
Une base de données contient des collections, et une collection contient des enregistrements. Les collections
n'ont pas besoin d'être créées : une collection existe dès qu'elle contient un enregistrement. Les noms de collection
ne peuvent contenir que des lettres, des chiffres et des underscores (orders, contact_requests).
Un enregistrement a exactement deux champs :
| Champ | Type | Description |
|---|---|---|
key |
UUID | Identifiant de l'enregistrement, unique dans les bases de données de tous les panneaux (pas seulement dans sa collection). |
value |
tout type | Les données que vous avez stockées. Toute valeur JSON est acceptée ; utilisez un objet si vous voulez filtrer ou trier sur ses champs. |
Les enregistrements ne portent aucune autre métadonnée : les réponses n'incluent ni le nom de la collection,
ni les horodatages, ni l'auteur. Si vous en avez besoin, stockez-les dans value.
Les endpoints qui travaillent sur un seul enregistrement (get, update, delete et leurs variantes
par lot) l'adressent uniquement par sa key ; la collection est déduite de l'enregistrement stocké.
Les endpoints qui travaillent sur une collection entière (create, find, count, verrous) prennent
le nom de la collection dans le corps.
{
"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "open",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
}
Qui peut accéder aux données d'un panneau
Les requêtes agissent au nom de l'utilisateur propriétaire de la clé API. Cet utilisateur doit :
- être propriétaire du panneau (en être le créateur, ou membre du groupe qui le possède, par exemple les administrateurs d'une organisation qui a reçu le panneau d'un partenaire), ou
- avoir reçu le panneau en partage, directement ou via un groupe auquel il appartient.
Les propriétaires et les utilisateurs avec qui le panneau est partagé (partage en lecture ou en écriture) peuvent lire et écrire la base de données, dans les deux modes : écrire dans la base de données compte comme une utilisation du panneau, pas comme sa modification (modifier le panneau lui-même nécessite toujours un partage en écriture). L'appartenance à l'organisation du panneau ne donne pas accès à elle seule, pas plus que les comptes administrateur AYETO. La clé API doit également porter la portée correspondante :
| Portée | Endpoints |
|---|---|
ayeto.booster.database |
get, find, count |
ayeto.booster.database.write |
create, create-many, update, update-many, delete, delete-many, lock/acquire, lock/release |
La portée d'écriture n'inclut pas la portée de lecture ; une clé qui lit et écrit a besoin des deux.
Les écritures effectuées via cette API sont des écritures dans la base de données du panneau comme les autres : elles démarrent les workflows ayant un déclencheur d'enregistrement booster sur le panneau et exécutent les modules de webhook et de notification par e-mail du panneau.
Règles de collection
Un panneau peut définir des règles de collection qui déterminent ce que les visiteurs anonymes du panneau peuvent faire. Les règles ne s'appliquent qu'en mode base de données publique ; un panneau en mode privé les ignore, et tous les endpoints de cette page fonctionnent sur toutes ses collections.
Pour un panneau en mode public, une seule partie des règles compte pour les requêtes de cette page :
- Une opération réglée sur none pour une collection (ou pour la règle
*qui la couvre) est désactivée pour tout le monde, y compris pour cette API. La requête échoue avec403. - Tous les autres niveaux (public, secret, private) autorisent les requêtes API.
- Une collection sans règle correspondante est entièrement accessible à l'API.
Les contraintes d'écriture d'une règle (schéma de validation, taille maximale de la valeur, nombre maximal d'enregistrements) ne sont pas appliquées aux écritures effectuées via cette API. Validez les données de votre côté avant de les écrire.
Limites
| Limite | Valeur |
|---|---|
Enregistrements renvoyés par un find |
jusqu'à 1000 avec pagination (limit_to vaut au plus 1000, limit_from est inférieur à 1000) ; tous les enregistrements correspondants si aucune limite n'est envoyée |
| Conditions de filtre dans une requête | 1000, y compris les conditions à l'intérieur de AND / OR |
Imbrication de AND / OR |
100 niveaux |
Valeurs dans une condition in |
100 |
| Valeur de filtre de type chaîne | 1000 caractères |
| Durée de vie d'un verrou | plus de 0,1 s, 3600 s par défaut |
Les endpoints par lot n'ont pas de nombre maximal fixe d'éléments, mais chaque élément est écrit séparément (voir Créer plusieurs enregistrements) ; limitez les lots à quelques centaines d'éléments pour qu'une requête se termine largement dans le délai d'expiration HTTP.
Interroger les enregistrements
find et count acceptent un objet params facultatif. Ses champs suivent les
conventions de requête générales, avec les différences indiquées ici.
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
filters |
tableau | non | Conditions, qui doivent toutes être satisfaites. Voir Filtres et ci-dessous. |
sort_key |
chaîne | non | Champ de tri : key ou value.<field>. |
sort_order |
entier | non | 0 croissant (par défaut lorsque sort_key est défini), 1 décroissant. |
limit_from |
entier | non | Index du premier enregistrement à renvoyer, à partir de 0, inférieur à 1000. |
limit_to |
entier | non | Index qui suit le dernier enregistrement à renvoyer (pas un nombre d'éléments), au plus 1000. Lorsque seul limit_from est envoyé, il vaut limit_from + 100 (au plus 1000). |
Champs filtrables et triables
Seuls deux types de noms de champs sont acceptés :
key, la clé de l'enregistrement (à comparer avec une chaîne UUID).value.<path>, un champ à l'intérieur de la valeur de l'enregistrement, avec des points pour les objets imbriqués :value.status,value.customer.email.
Tout autre nom échoue avec 422. Les enregistrements dont la valeur ne contient pas le champ (ou n'est pas un
objet) ne correspondent simplement pas.
Une condition s'écrit [field, operator, value] avec les opérateurs ==, !=, <, >,
<=, >=, regex (toujours insensible à la casse) et in (la valeur est une liste, dont n'importe quel
élément peut correspondre). Les conditions peuvent être combinées avec {"AND": [...]} et
{"OR": [...]} ; chacun nécessite au moins deux conditions et peut être imbriqué.
{
"collection": "tickets",
"params": {
"filters": [
["value.status", "in", ["open", "waiting"]],
{"OR": [
["value.priority", ">=", 3],
["value.customer.email", "regex", "@example\\.com$"]
]}
],
"sort_key": "value.created_at",
"sort_order": 1,
"limit_from": 0,
"limit_to": 50
}
}
Points à garder à l'esprit lorsque vous filtrez sur des valeurs :
- Les types doivent correspondre.
["value.priority", ">=", 3]ne correspond pas à un"priority": "3"stocké. Stockez les nombres comme des nombres et les dates comme des chaînes ISO 8601 ou comme des nombres, afin que<et>les comparent correctement. - Les chaînes ressemblant à des UUID restent des chaînes dans les conditions
value.*, si bien qu'un UUID stocké sous forme de texte est trouvé en tant que texte. - Les caractères
<,>,"et'dans une valeur de filtre de type chaîne sont échappés avant la comparaison, si bien qu'une condition sur un texte qui les contient ne correspond pas. Une valeur de filtre de type chaîne ne doit pas non plus commencer par$.
Tri et pagination
Sans sort_key, les enregistrements arrivent du plus récent au plus ancien. Avec sort_key, ils sont triés selon
ce champ.
limit_from et limit_to sont des positions dans le résultat : la deuxième page de 50
est donc "limit_from": 50, "limit_to": 100. Comme limit_to ne peut pas dépasser 1000,
la pagination par limites n'atteint que les 1000 premiers enregistrements correspondants. Pour aller plus loin,
paginez par valeur : triez sur un champ et filtrez sur la dernière valeur reçue, par
exemple ["value.created_at", "<", "2026-09-30T12:00:00Z"] avec
"sort_key": "value.created_at", "sort_order": 1.
Si vous n'envoyez ni limit_from ni limit_to, find renvoie tous les enregistrements
correspondants. Ne le faites que pour des collections que vous savez petites.
count applique les filtres et ignore le tri et la pagination : il renvoie le nombre total
d'enregistrements correspondants.
En-têtes de requête et erreurs communs
Tous les endpoints de cette page nécessitent ces en-têtes :
| En-tête | Description |
|---|---|
uni-api-key |
Votre clé API. Voir Authentification. |
panel-id |
ID du panneau dont vous accédez à la base de données. |
Content-Type |
application/json |
Les erreurs sont du JSON de la forme {"detail": "..."} (voir Erreurs).
Celles-ci peuvent provenir de tous les endpoints :
| Statut | detail |
Cause |
|---|---|---|
401 |
API key not provided / API key is invalid |
La clé est vide, inconnue, désactivée ou n'a pas la portée de l'endpoint. |
403 |
permission denied |
Vous n'êtes pas propriétaire du panneau et il n'est pas partagé avec vous. |
403 |
database access is not allowed for this panel |
L'accès à la base de données du panneau est réglé sur Pas de base de données. |
403 |
operation '<operation>' is disabled for collection '<collection>' |
Une règle de collection d'un panneau en mode public règle cette opération sur none. L'opération est create, read, update, delete, count ou lock. |
404 |
panel not found |
Aucun panneau avec cet ID, ou le panneau est désactivé. |
422 |
erreur de validation | L'en-tête panel-id est absent ou n'est pas un UUID, ou le corps ne correspond pas au modèle de requête. |
422 |
Collection name can only contain alphanumeric characters and underscores |
Nom de collection invalide (Collection cannot be empty pour un nom vide). |
429 |
message de limite de débit | Trop de requêtes ; attendez la durée indiquée dans l'en-tête Retry-After. Voir Limites de débit. |
500 |
erreur serveur | Échec inattendu ; réessayez plus tard. |
Rechercher des enregistrements
Renvoie les enregistrements d'une collection qui correspondent à la requête.
| Endpoint | POST /api/v3/booster/database/private/find |
| Portée | ayeto.booster.database |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
collection |
chaîne | oui | Nom de la collection. |
params |
objet | non | Filtres, tri et pagination ; voir Interroger les enregistrements. Sans lui, tous les enregistrements de la collection sont renvoyés, du plus récent au plus ancien. |
Réponse
Un tableau d'enregistrements (key, value). Une collection inconnue ou vide
renvoie [].
Erreurs
| Statut | detail |
Cause |
|---|---|---|
422 |
Field '<field>' is not allowed for filtering or sorting |
Un filtre ou sort_key désigne autre chose que key ou value.<path>. |
422 |
Each filter condition must be a list of [field, operator, value] |
Condition mal formée. |
422 |
Operator '<operator>' is not allowed |
Opérateur inconnu. |
422 |
'<AND/OR>' operator requires a list of at least 2 conditions |
La valeur de AND / OR n'est pas une liste d'au moins deux conditions. |
422 |
Logical filter must have exactly one key ('AND' or 'OR') |
Condition logique mal formée, par exemple {} ou un objet avec plusieurs clés. |
422 |
limit_from must be lower than 1000 |
limit_from vaut 1000 ou plus (la pagination n'atteint que les 1000 premiers enregistrements). |
422 |
Maximum number of filter conditions is 1000 (including conditions inside AND/OR) |
Trop de conditions. |
422 |
sort_order must be 0 (ASC) or 1 (DESC) |
sort_order invalide. |
422 |
limit_to cannot exceed 1000 |
limit_to supérieur à 1000. |
422 |
limit_from cannot be greater than limit_to |
Plage inversée. |
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/find" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{
"collection": "tickets",
"params": {
"filters": [["value.status", "==", "open"]],
"sort_key": "value.priority",
"sort_order": 1,
"limit_from": 0,
"limit_to": 20
}
}'
[
{
"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "open",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
},
{
"key": "c9f0f895-fb98-4b91-8f2a-6d3e5c1b0a47",
"value": {
"customer": {"name": "Petr Svoboda", "email": "petr@example.org"},
"status": "open",
"priority": 1,
"created_at": "2026-10-01T11:40:00Z"
}
}
]
Compter les enregistrements
Renvoie le nombre d'enregistrements d'une collection qui correspondent aux filtres.
| Endpoint | POST /api/v3/booster/database/private/count |
| Portée | ayeto.booster.database |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
collection |
chaîne | oui | Nom de la collection. |
params |
objet | non | Même objet que pour Rechercher des enregistrements. Seuls les filters influent sur le résultat ; le tri et la pagination sont validés mais ignorés. |
Réponse
Un entier.
Erreurs
Les erreurs de requête de Rechercher des enregistrements.
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/count" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{"collection": "tickets", "params": {"filters": [["value.status", "==", "open"]]}}'
42
Obtenir un enregistrement
Renvoie un enregistrement d'après sa clé.
| Endpoint | POST /api/v3/booster/database/private/get |
| Portée | ayeto.booster.database |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
key |
UUID | oui | Clé de l'enregistrement. |
Réponse
Erreurs
| Statut | detail |
Cause |
|---|---|---|
404 |
Database record not found |
La base de données de ce panneau ne contient aucun enregistrement avec cette clé. |
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/get" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70"}'
{
"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "open",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
}
Créer un enregistrement
Ajoute un enregistrement à une collection.
| Endpoint | POST /api/v3/booster/database/private/create |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
collection |
chaîne | oui | Nom de la collection (lettres, chiffres, underscores). La collection est créée avec son premier enregistrement. |
value |
tout type | non | Les données à stocker. Absent équivaut à null. |
key |
UUID | non | Clé du nouvel enregistrement. Générée si elle est absente ; elle ne doit être utilisée par aucun enregistrement existant d'aucun panneau (sinon 422). |
Réponse
L'enregistrement créé, y compris sa key.
Erreurs
| Statut | detail |
Cause |
|---|---|---|
422 |
a record with key '<key>' already exists |
La clé envoyée est utilisée par un enregistrement existant (de ce panneau ou d'un autre). |
500 |
error creating database record |
L'enregistrement n'a pas pu être stocké (rarement, deux requêtes ont créé la même clé au même moment). |
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/create" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{
"collection": "tickets",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "open",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
}'
{
"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "open",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
}
Créer plusieurs enregistrements
Ajoute plusieurs enregistrements, éventuellement dans des collections différentes.
| Endpoint | POST /api/v3/booster/database/private/create-many |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
Le corps est un tableau JSON d'objets de même forme que pour
Créer un enregistrement (collection, value, key facultative).
Les éléments sont écrits un par un, dans l'ordre. Le lot n'est pas atomique : si un élément
échoue, la requête renvoie l'erreur, les enregistrements qui le précèdent restent créés et les
éléments qui le suivent ne sont pas écrits. Un élément dont la key existe déjà arrête le lot
avec 422. Avant de relancer un lot en échec, vérifiez ce qui a été
écrit, ou envoyez vos propres clés afin de savoir quels éléments existent.
Réponse
Un tableau des enregistrements créés, dans l'ordre de la requête.
Erreurs
Les erreurs de Créer un enregistrement, pour le premier élément en échec.
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/create-many" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '[
{"collection": "products", "key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 12}},
{"collection": "products", "key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 40}}
]'
[
{"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 12}},
{"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 40}}
]
Mettre à jour un enregistrement
Remplace la valeur d'un enregistrement.
| Endpoint | POST /api/v3/booster/database/private/update |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
key |
UUID | oui | Clé de l'enregistrement. |
value |
tout type | non | La nouvelle valeur. Elle remplace entièrement la valeur stockée ; les champs que vous omettez sont supprimés. Absent équivaut à null. |
Pour modifier un seul champ, lisez l'enregistrement, modifiez le champ et renvoyez la valeur entière. Si d'autres clients peuvent écrire le même enregistrement au même moment, faites-le sous un verrou.
Réponse
L'enregistrement mis à jour.
Erreurs
| Statut | detail |
Cause |
|---|---|---|
404 |
Database record not found |
La base de données de ce panneau ne contient aucun enregistrement avec cette clé. |
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/update" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{
"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "closed",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
}'
{
"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70",
"value": {
"customer": {"name": "Jana Nováková", "email": "jana@example.com"},
"status": "closed",
"priority": 3,
"created_at": "2026-10-01T09:15:00Z"
}
}
Mettre à jour plusieurs enregistrements
Remplace les valeurs de plusieurs enregistrements.
| Endpoint | POST /api/v3/booster/database/private/update-many |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
Le corps est un tableau JSON d'objets de même forme que pour
Mettre à jour un enregistrement (key, value). Les éléments sont écrits un par un, dans
l'ordre, et le lot n'est pas atomique : un élément en échec arrête la requête, les éléments qui le
précèdent restent mis à jour.
Réponse
Un tableau des enregistrements mis à jour, dans l'ordre de la requête.
Erreurs
Les erreurs de Mettre à jour un enregistrement, pour le premier élément en échec.
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/update-many" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '[
{"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 10}},
{"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 37}}
]'
[
{"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "value": {"sku": "MUG-01", "name": "Mug", "quantity": 10}},
{"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54", "value": {"sku": "TEE-M", "name": "T-shirt M", "quantity": 37}}
]
Supprimer un enregistrement
Supprime un enregistrement.
| Endpoint | POST /api/v3/booster/database/private/delete |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
key |
UUID | oui | Clé de l'enregistrement. |
Réponse
null.
Erreurs
| Statut | detail |
Cause |
|---|---|---|
404 |
Database record not found |
La base de données de ce panneau ne contient aucun enregistrement avec cette clé (y compris lorsqu'il a déjà été supprimé). |
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/delete" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{"key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70"}'
Supprimer plusieurs enregistrements
Supprime plusieurs enregistrements.
| Endpoint | POST /api/v3/booster/database/private/delete-many |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
Le corps est un tableau JSON d'objets avec un champ key, comme pour
Supprimer un enregistrement. Les enregistrements sont supprimés un par un, dans l'ordre ; un élément
en échec (par exemple une clé qui n'existe pas) arrête la requête, et les enregistrements qui le précèdent
restent supprimés.
Réponse
null.
Erreurs
Les erreurs de Supprimer un enregistrement, pour le premier élément en échec.
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/delete-many" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '[
{"key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30"},
{"key": "5a9d3f2e-8c1b-4a6e-b7d0-3e2f1c9a8b54"}
]'
Verrous
Les verrous permettent à plusieurs clients (vos serveurs, le panneau lui-même) d'accéder à tour de rôle aux mêmes données. Un verrou a une durée de vie et est de l'un des deux types suivants :
- Verrou d'enregistrement :
collectionetkey. Utilisez la collection réelle de l'enregistrement ; un verrou pris sous un autre nom de collection ne protège pas l'enregistrement. - Verrou de collection :
collectionsanskey.
Les verrous sont consultatifs : le serveur ne les vérifie pas. get, find, count,
create, update, delete et leurs variantes par lot passent, qu'un enregistrement ou une
collection soit verrouillé ou non. Un verrou fait seulement attendre les autres appels lock/acquire pour le même
verrou ; il ne protège donc les données que si chaque client qui les écrit prend d'abord le verrou ;
cette coordination incombe au panneau et à votre code.
- Les verrous d'enregistrement et de collection sont indépendants. Détenir un verrou de collection n'empêche personne de prendre un verrou d'enregistrement dans cette collection, et inversement.
- N'importe qui peut libérer un verrou.
releaselibère le verrou quel que soit celui qui l'a pris, et un secondacquired'un verrou que vous détenez déjà attend comme pour celui de n'importe qui d'autre. Ne libérez un verrou que depuis le code qui l'a acquis. - Les verrous expirent. Chaque verrou est libéré automatiquement après son
ttl, même s'il n'a jamais été libéré. Choisissez un TTL plus long que la durée de votre traitement, mais assez court pour qu'un client planté ne bloque pas les autres trop longtemps.
Le verrouillage correspond à l'opération lock des règles de collection ; les deux
endpoints nécessitent la portée d'écriture et le même accès au panneau que l'écriture.
Acquérir un verrou
Prend un verrou d'enregistrement ou de collection, en attendant qu'il soit libre.
| Endpoint | POST /api/v3/booster/database/private/lock/acquire |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
collection |
chaîne | oui | Nom de la collection. |
key |
UUID | non | Clé de l'enregistrement. Omettez-la pour prendre le verrou de collection. |
acquire_timeout |
nombre | non | Nombre de secondes d'attente du verrou. 0 échoue immédiatement si le verrou est pris. S'il est absent, la requête attend aussi longtemps que nécessaire, jusqu'au TTL restant du détenteur actuel ; envoyez toujours une valeur plus courte que votre délai d'expiration HTTP. |
ttl |
nombre | non | Nombre de secondes après lesquelles le verrou est libéré automatiquement. Doit être supérieur à 0.1. 3600 par défaut. |
Réponse
null, une fois le verrou à vous.
Erreurs
| Statut | detail |
Cause |
|---|---|---|
423 |
Failed to acquire lock for collection '<collection>' and key '<key>' |
Le verrou est resté pris pendant acquire_timeout secondes (<key> vaut None pour un verrou de collection). Réessayez plus tard. |
422 |
erreur de validation | ttl vaut 0.1 ou moins. |
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/lock/acquire" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{"collection": "products", "key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", "acquire_timeout": 10, "ttl": 30}'
Libérer un verrou
Libère un verrou d'enregistrement ou de collection, quel que soit son détenteur.
| Endpoint | POST /api/v3/booster/database/private/lock/release |
| Portée | ayeto.booster.database.write |
| Limite de débit | par défaut |
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
collection |
chaîne | oui | Nom de la collection, tel qu'envoyé à lock/acquire. |
key |
UUID | non | Clé de l'enregistrement, telle qu'envoyée à lock/acquire. Omettez-la pour le verrou de collection. |
Réponse
null. Libérer un verrou qui n'est pas pris (ou qui a expiré) réussit également.
Exemples
curl -X POST "https://ayeto.ai/api/v3/booster/database/private/lock/release" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
-H "Content-Type: application/json" \
-d '{"collection": "products", "key": "0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30"}'
Lecture-modification-écriture sous verrou
update remplace la valeur entière : deux clients qui lisent chacun un enregistrement, le modifient
et le réécrivent peuvent donc écraser mutuellement leurs modifications. Prenez le verrou d'enregistrement autour de toute
la séquence et libérez-le dans un bloc finally ; chaque client qui écrit l'enregistrement doit faire
de même :
import os
import time
import requests
BASE_URL = "https://ayeto.ai/api/v3/booster/database/private"
HEADERS = {
"uni-api-key": os.environ["AYETO_API_KEY"],
"panel-id": "3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90",
}
def call(path: str, body):
response = requests.post(f"{BASE_URL}/{path}", json=body, headers=HEADERS, timeout=30)
response.raise_for_status()
return response.json()
def change_stock(key: str, delta: int, attempts: int = 3) -> dict:
"""Add `delta` to the quantity of a product record without losing concurrent changes."""
lock = {"collection": "products", "key": key}
for attempt in range(attempts):
try:
# wait at most 10 s; the lock frees itself after 30 s if this process dies
call("lock/acquire", {**lock, "acquire_timeout": 10, "ttl": 30})
break
except requests.HTTPError as e:
if e.response.status_code != 423 or attempt == attempts - 1:
raise
time.sleep(2)
try:
record = call("get", {"key": key})
value = record["value"]
value["quantity"] = value.get("quantity", 0) + delta
return call("update", {"key": key, "value": value})
finally:
call("lock/release", lock)
print(change_stock("0b6e8c1a-5d2f-4e3b-9a7c-1f4d6e8a2b30", -2))