Approbations dans Codenica API
Pour commencer à travailler avec les approbations via Codenica API, créez une clé API dans les paramètres de Codenica. Si vous n'en avez pas encore, ouvrez Codenica API - introduction dans un nouvel onglet. Vous y trouverez le fonctionnement commun de la création des clés, du stockage des secrets et de l'authentification.
Le nom technique de l'objet est approval et le nom de sa collection dans l'API est approvals. Une approbation contient une demande, la personne chargée de la décision, des informations descriptives et des liens vers les objets du processus. Elle peut également comporter des fichiers et un niveau d'épinglage.
La différence importante avec une mise à jour ordinaire est que le résultat de la décision n'est pas écrit directement dans status. Une approbation est approuvée ou rejetée via un endpoint de décision dédié. L'API peut ainsi vérifier que le bon approbateur agit et que l'enregistrement n'a pas changé depuis sa lecture.
Les exemples utilisent l'identifiant PUBLIC-API-APPROVAL-20260906060644. Remplacez-le par un identifiant fourni par votre application d'intégration et adaptez les UUID et les valeurs de champs à votre base de données.
Approbations - adresse de l'API et choix de l'installation
Toutes les routes des approbations commencent par :
{BASE_URL}/api/v1/approvalsBASE_URL est l'adresse du serveur Codenica sans le suffixe /api/v1. Dans Cloud, utilisez le domaine réellement attribué à l'entreprise :
export BASE_URL="https://{actual-company-domain}"Dans l'installation On-Premise par défaut, l'adresse enregistrée localement par Codenica Discovery est :
export BASE_URL="http://codenica.local:5150"Si un administrateur a rendu l'installation accessible via un domaine d'entreprise, un proxy inverse, HTTPS ou un autre port, utilisez l'adresse exacte fournie pour cette installation :
export BASE_URL="https://{actual-installation-address}"N'utilisez pas localhost lorsque l'application d'intégration s'exécute sur un autre ordinateur que l'API. La base de données cible est déterminée par l'hôte de la requête. N'envoyez pas tenantId dans le corps, la chaîne de requête ou un en-tête supplémentaire.
Approbations - périmètres de la clé API
La clé utilisée pour les approbations doit contenir uniquement les périmètres nécessaires à l'intégration concernée. L'ensemble complet des périmètres du module est :
approvals:read
approvals:write
approvals:delete
approvals:schema
approvals:stats
approvals:relationships:read
approvals:relationships:write
approvals:users:read
approvals:files:read
approvals:files:write
approvals:technical:read
approvals:technical:write
approvals:pin:write
approvals:decision:write
users:readPour les listes et la lecture des enregistrements, choisissez approvals:read. La création et la modification exigent approvals:write, tandis que la suppression exige approvals:delete. Ajoutez les périmètres des relations, des fichiers, des statistiques, des données techniques, de l'épinglage et des décisions uniquement si l'intégration utilise ces opérations.
Si l'intégration recherche des cibles de relations, elle a également besoin des périmètres de lecture appropriés pour les collections concernées, par exemple notes:read, worktasks:read, requesteditems:read, tickets:read, changes:read, problems:read ou releases:read. Le périmètre de la clé ne remplace pas les droits de l'utilisateur.
Approbations - authentification
Authentifiez chaque requête Codenica API avec deux en-têtes :
export CLIENT_ID="cna_your_client_id"
export CLIENT_SECRET="cns_your_client_secret"
curl --request GET --url "$BASE_URL/api/v1/approvals?page=1&pageSize=25" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Une intégration externe n'a pas besoin d'un JWT d'administrateur ni des cookies du panneau Codenica. Stockez le secret dans un coffre de secrets côté serveur. Ne le placez pas dans du code livré au navigateur, un dépôt, une URL, l'historique du shell ou des journaux. Utilisez HTTPS en dehors des essais locaux.
Enregistrez meta.requestId dans les réponses. Il permet de retrouver une requête précise dans les journaux, mais ce n'est ni l'UUID de l'approbation ni un secret.
Approbations - vérifier le contexte de connexion
Avant la première écriture, récupérez le contexte. Vous vérifierez ainsi que l'adresse atteint la bonne base de données et que la clé possède les périmètres et les limites nécessaires :
curl --request GET --url "$BASE_URL/api/v1/context" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Vérifiez que data.apiVersion, data.contractVersion et data.tenant sont présents, que data.caller.authentication vaut api_key, que approvals figure dans data.capabilities.resources, et contrôlez les périmètres de la clé ainsi que les limites.
Si le contexte correspond à une autre entreprise ou ne contient pas un périmètre requis, corrigez l'adresse ou créez une clé avec les autorisations nécessaires. N'essayez pas d'atteindre une autre base en envoyant un tenantId étranger.
Approbations - schéma et cibles de relations
Le schéma est la référence actuelle pour les champs, leurs types, leur possibilité d'écriture et les cibles de relations autorisées :
curl --request GET --url "$BASE_URL/api/v1/approvals/schema" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"La réponse contient data.itemType, data.fields et data.relationshipTargets. Pour ce module, itemType vaut approval. Pour chaque champ, contrôlez readable, writable, required, technical, unique, maxLength et hasAutoGeneration.
Extrait de schéma :
{
"data": {
"itemType": "approval",
"fields": [
{ "name": "description", "type": "string", "writable": true },
{ "name": "level", "type": "string", "writable": true },
{ "name": "status", "type": "string", "writable": false },
{ "name": "pin", "type": "integer", "writable": false }
],
"relationshipTargets": [
{ "targetDataSet": "notes", "targetItemType": "note" },
{ "targetDataSet": "tickets", "targetItemType": "ticket" }
]
}
}Ne construisez pas votre mapping uniquement à partir de cet extrait. Récupérez le schéma de la base de données concernée avant de démarrer l'intégration et utilisez uniquement les champs et les cibles retournés.
Approbations - champs métier et champs système
Les principaux champs d'une approbation sont les suivants :
customIdlocation, departmenttag, linkinfo, descriptionlevel, categorystatus, dateApproved, dateRejectedremark, pinid, itemType, creator, updater, dateCreated, dateUpdated, importId, importSource et dateImported sont attribués par le système ou destinés aux lectures techniques. Ne les envoyez pas dans attributes.
creator
updater
dateCreated
dateUpdated
importId
importSource
dateImportedApprobations - endpoints disponibles
Les principales routes du module approvals sont :
GET /api/v1/approvals
POST /api/v1/approvals
GET /api/v1/approvals/{APPROVAL_ID}
PATCH /api/v1/approvals/{APPROVAL_ID}
DELETE /api/v1/approvals/{APPROVAL_ID}
GET /api/v1/approvals/schema
GET /api/v1/approvals/stats
GET /api/v1/approvals/values
POST /api/v1/approvals:batch
GET /api/v1/approvals/{APPROVAL_ID}/relationships
POST /api/v1/approvals/{APPROVAL_ID}/relationships
POST /api/v1/approvals/{APPROVAL_ID}/relationships:batch
DELETE /api/v1/approvals/{APPROVAL_ID}/relationships/{DATASET}/{TARGET_ID}
GET /api/v1/approvals/{APPROVAL_ID}/user-relationships
GET /api/v1/approvals/{APPROVAL_ID}/files
POST /api/v1/approvals/{APPROVAL_ID}/files
POST /api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}
DELETE /api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}
GET /api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}/content
POST /api/v1/approvals/{APPROVAL_ID}/pin
POST /api/v1/approvals/{APPROVAL_ID}/decisionLes opérations de lecture exigent les périmètres read, tandis que chaque modification demande les périmètres supplémentaires décrits plus haut. Toute requête qui modifie les données exige également Idempotency-Key et les opérations sur un enregistrement existant exigent en plus le If-Match actuel.
Approbations - liste et pagination
Récupérez les listes d'approbations page par page :
curl --request GET --url "$BASE_URL/api/v1/approvals?itemType=approval&page=1&pageSize=25" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"La réponse contient data.items et les informations de pagination :
{
"data": {
"items": [
{
"id": "approval-uuid",
"itemType": "approval",
"attributes": {
"customId": "ERP-APPROVAL-2026-0042",
"category": "Procurement",
"status": "Open",
"level": "Supervisor"
},
"meta": {
"etag": "\"etag-value\""
}
}
],
"page": 1,
"pageSize": 25,
"totalItems": 1,
"totalPages": 1,
"hasNextPage": false
},
"meta": {
"requestId": "request-id"
}
}Passez à la page suivante selon hasNextPage. Lisez la taille maximale dans data.capabilities.limits.maxPageSize au lieu de la fixer en dur.
Approbations - recherche et filtres
Utilisez search pour une recherche textuelle. Pour une synchronisation, un customId stable ou un UUID est préférable :
curl --silent --show-error -G \
--data-urlencode "search=purchase" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals"Les filtres simples peuvent utiliser les noms des champs :
curl --silent --show-error -G \
--data-urlencode "status=Open" \
--data-urlencode "category=Procurement" \
--data-urlencode "customId=ERP-APPROVAL-2026-0042" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals"Les filtres structurés utilisent la forme field:operator:value :
category:eq:Procurement
level:ne:Assistant
description:contains:monitor
customId:startswith:ERP-
link:notempty:Les opérateurs pris en charge incluent eq, ne, gt, gte, lt, lte, contains, startswith, endswith et notempty. Encodez les valeurs dans l'URL, en particulier lorsqu'elles contiennent des espaces, des deux-points ou des caractères spéciaux.
Approbations - sélection des champs et données incluses
Utilisez fields lorsque vous n'avez besoin que d'une partie de la réponse. Incluez les fichiers, les relations et les utilisateurs avec include :
curl --silent --show-error -G \
--data-urlencode "fields=id,itemType,customId,location,department,level,category,status" \
--data-urlencode "include=files,relationships,users" \
--data-urlencode "ids={APPROVAL_ID}" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals"Les valeurs include disponibles sont files, relationships et users. Chacune peut exiger un périmètre distinct. fields=* ne donne pas accès aux champs techniques et ne modifie pas les règles d'accès.
Vous pouvez également filtrer avec createdAfter, createdBefore, updatedAfter, updatedBefore, sort et direction. Vérifiez les noms de champs dans le schéma actuel.
Approbations - statistiques et valeurs de champs
L'endpoint stats présente la distribution des données, tandis que values renvoie des valeurs utiles pour construire des filtres :
curl --silent --show-error -G \
--data-urlencode "field=category" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/stats"
curl --silent --show-error -G \
--data-urlencode "field=level" \
--data-urlencode "search=super" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/values"Ces deux requêtes sont en lecture seule et ne modifient pas les approbations. Le champ doit être autorisé par le schéma et les valeurs dépendent des enregistrements visibles par l'utilisateur.
Approbations - création minimale
Un enregistrement minimal utile contient le type, un identifiant fourni par l'application d'intégration, une catégorie, une description et l'utilisateur qui doit prendre la décision :
{
"itemType": "approval",
"attributes": {
"customId": "ERP-APPROVAL-0001",
"category": "Procurement",
"description": "Approval for a monitor purchase"
},
"approverId": "{APPROVER_USER_ID}"
}Envoyez-le au format JSON :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: erp-approval-create-0001" \
--data-binary @approval.json \
"$BASE_URL/api/v1/approvals"approverId identifie l'utilisateur Codenica actif qui prendra la décision. Ce n'est ni l'identifiant d'un client ni une adresse e-mail arbitraire.
Approbations - exemple de création complète
Cet exemple contient des informations de processus, des étiquettes, un niveau d'approbation et une règle de valeur technique :
{
"itemType": "approval",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-20260906060644-SOURCE",
"location": "Warsaw",
"department": "IT",
"tag": "public-api,approvals,PUBLIC-API-APPROVAL-20260906060644",
"link": "https://codenica.com",
"info": "Approval request created by the Public API complete flow.",
"level": "Supervisor",
"category": "Procurement",
"description": "Approval created through the Codenica Public API."
},
"approverId": "{APPROVER_USER_ID}",
"customValues": [
{
"name": "description",
"valuePattern": "[approval-example] PUBLIC-API-APPROVAL-20260906060644"
}
]
}approverId exige approvals:technical:write. customValues est facultatif et exige également le périmètre technique. Utilisez-le uniquement pour les champs autorisés par le schéma.
Dans une intégration réelle, choisissez l'approbateur selon le processus de l'entreprise. L'utilisateur qui crée l'enregistrement devient le demandeur.
Approbations - réponse de création et clé d'idempotence
Une création réussie renvoie 201 Created, l'identifiant de l'enregistrement et son ETag initial. Conservez ces deux valeurs dans l'intégration :
{
"data": {
"id": "{APPROVAL_ID}",
"itemType": "approval",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-20260906060644-SOURCE",
"level": "Supervisor",
"category": "Procurement",
"status": "Open"
},
"meta": {
"customId": "PUBLIC-API-APPROVAL-20260906060644-SOURCE",
"etag": "\"{ETAG_AFTER_CREATE}\""
}
},
"meta": {
"requestId": "{REQUEST_ID}",
"etag": "\"{ETAG_AFTER_CREATE}\""
}
}Toute requête qui modifie les données doit avoir sa propre Idempotency-Key. Si le client ne sait pas si la première requête a atteint le serveur, renvoyez le même corps avec la même clé :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: public-api-approval-source-create-20260906060644" \
--data-binary @approval.json \
"$BASE_URL/api/v1/approvals"La répétition de la même requête ne crée pas une deuxième approbation. Un corps différent avec la même clé est rejeté, car une clé ne peut représenter qu'une seule opération.
Approbations - lire un enregistrement et son ETag
Après la création et avant chaque modification suivante, lisez l'enregistrement par UUID :
curl --fail-with-body --silent --show-error \
--request GET \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}?fields=*"La réponse contient data.attributes et data.meta.etag. Le serveur renvoie aussi la même valeur dans un en-tête HTTP :
HTTP/1.1 200 OK
ETag: "{ETAG_AFTER_GET}"Après chaque modification réussie, l'ETag peut changer, notamment après une relation, un épinglage, une décision ou une opération sur un fichier. Conservez toujours la valeur renvoyée par la dernière opération réussie.
Approbations - modifier les champs avec If-Match
Une mise à jour ordinaire modifie uniquement les champs métier. Ne l'utilisez pas pour écrire le statut, les dates de décision ou l'épinglage :
curl --fail-with-body --silent --show-error \
--request PATCH \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AFTER_GET}"' \
--header "Idempotency-Key: public-api-approval-update-20260906060644" \
--data '{
"attributes": {
"info": "Updated approval information from the integration.",
"level": "Manager",
"category": "Approved procurement",
"description": "Approval edited through the Codenica Public API."
}
}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}"En cas de succès, la réponse est 200 OK avec un nouvel ETag. Ne mettez à jour que les champs réellement modifiés. Les conflits sont ainsi plus simples à résoudre et le risque d'écraser des données diminue.
Approbations - If-Match obligatoire et protection contre les conflits
L'ETag actuel est obligatoire pour modifier un enregistrement existant. Un PATCH sans cet en-tête renvoie :
{
"type": "https://docs.codenica.com/errors/if_match_required",
"title": "Precondition required.",
"status": 428,
"code": "if_match_required",
"detail": "Send the ETag returned by GET in the If-Match header."
}Si l'ETag fourni n'est plus actuel, l'API renvoie 412 Precondition Failed avec le code if_match_failed :
{
"type": "https://docs.codenica.com/errors/if_match_failed",
"title": "Precondition failed.",
"status": 412,
"code": "if_match_failed",
"detail": "The supplied ETag is not the current approval version."
}Une requête rejetée avec 412 n'enregistre aucune modification. Relisez l'approbation, comparez les données et préparez ensuite une mise à jour volontaire. N'écrasez pas automatiquement les changements effectués par une autre personne ou une autre intégration.
Approbations - épinglage
Le champ pin est en lecture seule et se modifie via un endpoint dédié. Les valeurs autorisées sont des entiers de 0 à 3 :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-pin-20260906060644" \
--data '{"pin":3}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/pin"Pour supprimer l'épinglage, envoyez null via le même endpoint :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AFTER_PIN}"' \
--header "Idempotency-Key: public-api-approval-unpin-20260906060644" \
--data '{"pin":null}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/pin"Les deux opérations exigent l'ETag actuel et approvals:pin:write. N'envoyez pas pin dans un PATCH ordinaire.
Approbations - exécuter une décision Approved ou Rejected
Les décisions utilisent un endpoint dédié :
/api/v1/approvals/{APPROVAL_ID}/decisionUne décision positive définit status=Approved, dateApproved et dateEnd :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-decision-approved-20260906060644" \
--data '{"approved":true,"remark":"Approved through the Public API integration."}' \
"$BASE_URL/api/v1/approvals/{APPROVED_APPROVAL_ID}/decision"Une décision négative définit status=Rejected, dateRejected et dateEnd :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-decision-rejected-20260906060644" \
--data '{"approved":false,"remark":"Rejected through the Public API integration."}' \
"$BASE_URL/api/v1/approvals/{REJECTED_APPROVAL_ID}/decision"Ne modifiez pas le statut avec PATCH pour contourner cette procédure. Une décision exige approvals:decision:write, le droit métier approprié (Approval_Accept ou Approval_Reject), un ETag actuel et un appel effectué exactement par l'utilisateur désigné comme approbateur.
Approbations - demandeur et approbateur
Lisez les relations utilisateur via un endpoint distinct :
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/user-relationships?page=1&pageSize=20"La réponse contient une relation requester et, lorsqu'un approbateur a été fourni, une relation approver :
{
"data": {
"items": [
{
"userId": "{REQUESTER_USER_ID}",
"relationshipType": "requester"
},
{
"userId": "{APPROVER_USER_ID}",
"relationshipType": "approver"
}
]
}
}Le demandeur est affecté automatiquement à l'utilisateur qui crée l'approbation. Les deux relations sont en lecture seule. N'essayez pas de modifier l'approbateur avec POST sur user-relationships ; son affectation relève de la création contrôlée ou du processus système.
Approbations - relations d'objets autorisées
Le catalogue des cibles de relations d'une approbation est volontairement limité :
Ce catalogue ne comprend pas les relations avec assets, clients, vendors, documents, confirmations ni l'approbation elle-même.
{
"targetId": "{TARGET_ID}",
"targetDataSet": "notes",
"targetItemType": "note"
}Sélectionnez d'abord une cible dans la liste de la collection concernée. Ne supposez pas que chaque base contient un enregistrement dans chacune des sept collections.
Approbations - une différence importante dans le format des relations
Les relations d'objets des approbations ne stockent pas relationshipType. Le corps contient uniquement l'identifiant de la cible, le nom de la collection et le type technique de l'objet :
{
"targetId": "7bdda87a-6c37-49ae-9e40-272a7a9b8616",
"targetDataSet": "notes",
"targetItemType": "note"
}N'envoyez pas ce champ :
{
"targetId": "{TARGET_ID}",
"targetDataSet": "notes",
"targetItemType": "note",
"relationshipType": "related"
}relationshipType est utilisé par d'autres modèles de relations et par les fichiers, mais il est refusé pour les relations d'approbations avec les objets de processus.
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/notes?page=1&pageSize=10"La sélection d'une cible exige le périmètre read de la collection, par exemple notes:read.
Approbations - ajouter, lire et supprimer une relation
La création directe d'une relation exige l'ETag actuel de l'approbation et approvals:relationships:write :
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-relation-add-0001" \
--data '{"targetId":"{NOTE_ID}","targetDataSet":"notes","targetItemType":"note"}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships"Lisez les relations après l'ajout :
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships?targetDataSet=notes&page=1&pageSize=100"Supprimez une relation avec le nouvel ETag renvoyé après l'ajout :
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AFTER_RELATION_ADD}"' \
--header "Idempotency-Key: public-api-approval-relation-delete-0001" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships/notes/{NOTE_ID}"Après chaque écriture, récupérez à nouveau la collection de relations et confirmez que la cible a été ajoutée ou supprimée.
Approbations - lots de relations et relations dans PATCH
Modifiez plusieurs relations avec une seule requête :
{
"add": [
{
"targetId": "{NOTE_ID}",
"targetDataSet": "notes",
"targetItemType": "note"
}
],
"remove": []
}curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-relationship-batch-0001" \
--data-binary @relationship-batch.json \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships:batch"La réponse contient les compteurs added, removed et skipped. Un PATCH peut aussi contenir relationshipsToAdd et relationshipsToRemove :
{
"attributes": {
"info": "Updated together with a relationship."
},
"relationshipsToAdd": [
{
"targetId": "{TICKET_ID}",
"targetDataSet": "tickets",
"targetItemType": "ticket"
}
],
"relationshipsToRemove": []
}Dans les deux variantes, l'ETag actuel, l'idempotence et le périmètre des relations sont obligatoires.
Approbations - liste des fichiers et envoi
Les fichiers sont des ressources distinctes liées à une approbation. Lisez d'abord la liste actuelle :
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files?page=1&pageSize=100"Envoyez un fichier en multipart/form-data. Le rôle du fichier est transmis dans la chaîne de requête :
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-file-upload-0001" \
--form "[email protected];type=application/pdf" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files?relationshipType=decision-form"Le nom du fichier doit être un nom simple sans chemin. Vérifiez sa taille avant l'envoi et définissez volontairement son type MIME. L'envoi exige approvals:files:write.
{
"data": {
"id": "{FILE_ID}",
"fileName": "approval-decision-form.pdf",
"contentType": "application/pdf",
"size": 48231,
"relationshipType": "decision-form",
"isMain": false,
"downloadUrl": "/api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}/content"
}
}L'API des approbations ne propose pas d'opération pour définir un fichier principal. Les fichiers renvoyés ont isMain=false. Ne construisez pas une intégration qui attendrait un endpoint /main pour cet objet.
Approbations - télécharger, rattacher et supprimer des fichiers
Téléchargez le contenu avec l'endpoint content et enregistrez-le comme fichier binaire :
curl --fail-with-body --silent --show-error \
--output downloaded-approval-form.pdf \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}/content"Si un fichier existe déjà dans le système et que vous possédez son File ID, rattachez-le à une approbation sans envoyer une nouvelle copie :
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{TARGET_APPROVAL_ETAG}"' \
--header "Idempotency-Key: public-api-approval-file-attach-0001" \
"$BASE_URL/api/v1/approvals/{TARGET_APPROVAL_ID}/files/{FILE_ID}?relationshipType=reference"Supprimez un fichier d'une approbation :
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-file-delete-0001" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}"Le rattachement crée un lien vers un fichier existant et n'en envoie pas une nouvelle copie. L'envoi, le rattachement et la suppression modifient l'ETag de l'approbation. Le téléchargement est en lecture seule.
Approbations - opérations par lots
L'endpoint /api/v1/approvals:batch crée, modifie et supprime plusieurs enregistrements. Il ne remplace pas les opérations de décision, d'épinglage, de relations ou de fichiers :
{
"items": [
{
"operation": "create",
"create": {
"itemType": "approval",
"approverId": "{APPROVER_USER_ID}",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-BATCH-A",
"location": "Warsaw",
"department": "IT",
"level": "Supervisor",
"category": "Procurement",
"description": "Batch-created Approval A"
}
}
},
{
"operation": "create",
"create": {
"itemType": "approval",
"approverId": "{APPROVER_USER_ID}",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-BATCH-B",
"location": "Warsaw",
"department": "IT",
"level": "Manager",
"category": "Procurement",
"description": "Batch-created Approval B"
}
}
}
]
}curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: public-api-approval-batch-create-0001" \
--data-binary @approvals-batch-create.json \
"$BASE_URL/api/v1/approvals:batch"Un même lot peut combiner create, update et delete. Chaque mise à jour et chaque suppression doit fournir son propre id et son ifMatch actuel.
{
"data": {
"items": [
{
"index": 0,
"operation": "create",
"status": 201,
"id": "{BATCH_ID_A}",
"data": {
"id": "{BATCH_ID_A}",
"meta": { "etag": "{ETAG_A}" }
}
}
],
"succeeded": 2,
"failed": 0
}
}Le traitement par lots n'est pas une transaction tout ou rien. Un résultat partiel peut renvoyer 207 Multi-Status. Analysez chaque élément de la réponse et ne répétez pas les opérations déjà réussies.
Approbations - supprimer un enregistrement
Avant la suppression, relisez l'enregistrement, vérifiez l'UUID et l'ETag actuel, puis confirmez que le processus métier autorise cette suppression :
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{CURRENT_ETAG}"' \
--header "Idempotency-Key: public-api-approval-delete-0001" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}"Une réponse réussie renvoie 200 OK et data=true. Après la suppression, la lecture du même UUID doit renvoyer 404 Not Found avec approval_not_found. Vous pouvez également vérifier le résultat avec une liste filtrée par customId et attendre totalItems=0.
Ne supprimez pas une approbation sans vérifier son ETag. Vous éviterez ainsi de supprimer une version plus récente alors que vous travaillez avec une copie ancienne.
Approbations - erreurs, limites et séquence sûre
Les erreurs utilisent le format Problem Details. Enregistrez status, code et requestId, mais ne journalisez jamais le Client Secret ni les en-têtes complets :
authentication_failedapproval_approver_requiredapproval_not_foundapproval_unique_constraint ou approval_concurrency_conflictif_match_failed, if_match_requiredvalidation_failed, approval_decision_rejected, approval_pin_rejectedrate_limit_exceededRetry-After.Lisez X-RateLimit-Limit et X-RateLimit-Remaining. Mettez le schéma et les valeurs en cache, limitez la concurrence et utilisez un délai progressif après un 429.
Une séquence sûre est la suivante : context, schema, choisir un approbateur, lister ou lire un enregistrement, créer avec Idempotency-Key, conserver son UUID et son ETag, ajouter des relations ou des fichiers, modifier avec If-Match, prendre la décision via /decision, relire pour vérifier et supprimer uniquement si nécessaire. La même séquence peut être utilisée dans n8n en transmettant les UUID, les ETag et les clés d'idempotence entre les étapes.
