Les changements dans Codenica API

Pour travailler avec les changements via Codenica API, commencez par créer une clé dans les paramètres de Codenica. Si vous n'en avez pas encore créé, ouvrez dans un nouvel onglet Codenica API - introduction. Vous y trouverez les règles de création des clés, de conservation du secret et d'authentification communes.

Le nom technique du module est changes et le type d'un objet est change. Un changement sert à planifier et à contrôler une modification prévue d'un service, d'une infrastructure ou d'une configuration. En plus des données de base, il contient des champs de planification comme les dates, le risque, l'impact, le plan de déploiement, le plan de retour arrière et le motif du changement.

La suite présente le parcours complet : vérification du schéma et des dictionnaires, listes, filtres, création, mise à jour avec ETag, opérations batch, relations, utilisateurs, fichiers, actions de workflow, approbations et suppression.

Les exemples utilisent le préfixe PUBLIC-API-CHANGE-20260905130127. Dans votre intégration, remplacez-le par votre propre identifiant et adaptez les adresses e-mail, les identifiants et les valeurs aux données de votre base.


Changements - adresse de l'API et choix de l'installation

Toutes les routes consacrées aux changements commencent par :

{BASE_URL}/api/v1/changes

Dans Codenica Cloud, utilisez le domaine public attribué à votre installation :

export BASE_URL="https://votre-entreprise.codenica.com"

Dans l'installation On-Premise par défaut, Codenica Discovery enregistre le service localement à l'adresse suivante :

export BASE_URL="http://codenica.local:5150"

Si l'administrateur a publié l'installation On-Premise sous un domaine d'entreprise, derrière un reverse proxy, en HTTPS ou sur un autre port, utilisez l'adresse exacte communiquée pour cette installation :

export BASE_URL="https://api.votre-entreprise.example"

N'utilisez pas localhost si le programme d'intégration s'exécute sur un autre ordinateur que l'API. N'envoyez pas tenantId dans le body ou dans la chaîne de requête. La base correcte est choisie à partir de l'adresse hôte utilisée par l'intégration.


Changements - clé API et limites de licence

Créez une clé API dans Codenica, dans Paramètres - API - API Keys. Le secret n'est affiché qu'une seule fois, immédiatement après la création ou la rotation de la clé. Enregistrez alors le Client ID et le Client Secret dans le coffre de secrets utilisé par l'intégration.

Codenica API est disponible avec les licences Plus et Enterprise. Plus permet de créer jusqu'à 50 clés actives et Enterprise jusqu'à 100. Starter ne comprend pas Codenica API. Créez une clé distincte pour chaque application et chaque environnement afin de pouvoir limiter séparément ses périmètres, effectuer une rotation du secret ou supprimer son accès.

Sélectionnez uniquement les autorisations nécessaires au traitement des changements. Une intégration en lecture seule peut utiliser changes:read. La création d'approbations et le traitement des décisions d'approbation nécessitent également les périmètres du module approvals.


Changements - authentification et requêtes sécurisées

Authentifiez chaque requête de l'API publique avec les deux en-têtes de la clé :

export CLIENT_ID="cna_votre_client_id"
export CLIENT_SECRET="cns_votre_client_secret"

curl --request GET "$BASE_URL/api/v1/changes?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 du JWT de l'administrateur ni des cookies du panneau Codenica. Ne placez pas la clé dans un dépôt, dans du code envoyé au navigateur, dans une URL, dans l'historique des commandes ou dans les journaux. En dehors des tests locaux, utilisez HTTPS.

Conservez meta.requestId dans chaque réponse. Il aide à diagnostiquer une requête précise, mais ne remplace pas l'identifiant du changement et ne doit pas être utilisé comme secret.


Changements - vérification du contexte de connexion

Avant le premier enregistrement, lisez le contexte. Vous vérifierez ainsi que l'adresse mène à la bonne base et que la clé choisie possède les périmètres nécessaires :

curl --request GET "$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 :

  • data.apiVersion et data.contractVersion ;
  • data.tenant.id et data.tenant.resolvedDomain ;
  • data.caller.authentication égal à api_key ;
  • la présence de changes dans data.capabilities.resources ;
  • les périmètres attribués à la clé ;
  • les limites de pagination, de batch, de fichiers et de requêtes.

Si le contexte indique une autre base ou ne contient pas le périmètre requis, interrompez l'intégration et corrigez l'adresse ou la clé. Les périmètres ne peuvent pas être accordés dans une requête individuelle.


Changements - périmètres d'autorisation

La gestion complète des changements nécessite les périmètres correspondant aux opérations utilisées :

changes:read
changes:write
changes:delete
changes:schema
changes:stats
changes:relationships:read
changes:relationships:write
changes:users:read
changes:users:write
changes:files:read
changes:files:write
changes:technical:read
changes:technical:write
changes:pin:write
changes:spam:write
changes:reopen:write
changes:rating:write
changes:escalation:write
changes:approval:write

Pour une lecture simple, changes:read suffit. Le schéma et les statistiques nécessitent changes:schema et changes:stats. La lecture des relations, des utilisateurs et des fichiers nécessite respectivement :relationships:read, :users:read et :files:read. Les opérations d'écriture utilisent les périmètres :write correspondants.

Si l'intégration crée, lit, modifie ou supprime des approbations, ajoutez :

approvals:read
approvals:write
approvals:delete
approvals:relationships:read
approvals:relationships:write
approvals:technical:read
approvals:technical:write

Les relations avec d'autres modules nécessitent également l'accès en lecture au module cible, par exemple assets:read, documents:read, tickets:read, problems:read ou releases:read. Accordez les périmètres selon le principe du moindre privilège.


Changements - schéma et champs de planification

Le schéma indique quels champs peuvent être lus et écrits dans votre base. Récupérez-le avant de préparer le body :

curl --request GET "$BASE_URL/api/v1/changes/schema" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pour chaque champ, vérifiez notamment readable, writable, required, technical, unique, maxLength et les règles de génération automatique. Le schéma renvoie aussi les cibles de relations disponibles.

La création d'un changement nécessite actuellement au minimum subject et requesterEmail. Les autres champs dépendent de la configuration et du processus :

Groupe
Champs d'exemple
Utilisation
Base
subject, requesterEmail, description, comments
description et demandeur
Classification
type, status, priority, impact, urgency, severity
traitement et évaluation de l'impact
Planification
datePlannedStart, datePlannedEnd, risk, impactInfo, rolloutPlan, backoutPlan, reasonForChange
dates, risque et méthode de mise en œuvre
Intégration
source, externalNumber, referenceNumber, services, tags
liaison avec un autre système
Coûts
currency, estimatedCost, totalValue
valeurs financières

Récupérez les valeurs des dictionnaires comme le statut, la priorité, le type et le risque dans le schéma ou via l'endpoint values. Envoyez les dates au format ISO 8601 et les nombres comme nombres JSON. Ne supposez pas que les dictionnaires sont identiques dans deux bases.

{
  "datePlannedStart": "2030-01-15T09:00:00Z",
  "datePlannedEnd": "2030-01-15T17:00:00Z",
  "risk": "Medium",
  "impactInfo": "Évaluation de l'impact planifié",
  "rolloutPlan": "Déployez et vérifiez les contrôles de santé.",
  "backoutPlan": "Restaurez la version précédente si la vérification échoue.",
  "reasonForChange": "La version actuelle de la plateforme nécessite une mise à jour contrôlée."
}

Changements - endpoints principaux

Les routes les plus utilisées pour les changements sont :

  • GET /api/v1/changes - liste des changements ;
  • GET /api/v1/changes/{id} - un changement ;
  • POST /api/v1/changes - création ;
  • PATCH /api/v1/changes/{id} - modification partielle ;
  • DELETE /api/v1/changes/{id} - suppression ;
  • GET /api/v1/changes/schema - schéma des champs et des relations ;
  • GET /api/v1/changes/stats - statistiques ;
  • GET /api/v1/changes/values - valeurs de filtres ;
  • POST /api/v1/changes:batch - opérations de création, modification et suppression.

Les relations, les utilisateurs, les fichiers, les actions de workflow et les approbations ont leurs propres routes. L'intégration peut ainsi recevoir uniquement les autorisations dont elle a réellement besoin.


Changements - listes et pagination

Récupérez les listes page par page. Même pour une petite collection, indiquez explicitement le numéro et la taille de la page :

curl --request GET "$BASE_URL/api/v1/changes?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 ainsi que page, pageSize, totalItems, totalPages et hasNextPage. Continuez tant que hasNextPage vaut true :

curl --request GET "$BASE_URL/api/v1/changes?page=2&pageSize=25&sort=dateUpdated&direction=desc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pour la synchronisation, trier par dateUpdated et mémoriser les derniers enregistrements traités est pratique. Ne définissez pas pageSize au-dessus de la limite renvoyée dans le contexte.


Changements - recherche, filtres et tri

Vous pouvez combiner les paramètres de liste. Cet exemple recherche un enregistrement précis, le limite au type change et au risque Medium, puis trie le résultat par date de mise à jour :

curl --get "$BASE_URL/api/v1/changes" \
  --data-urlencode "itemType=change" \
  --data-urlencode "customId=PUBLIC-API-CHANGE-20260905130127-SOURCE" \
  --data-urlencode "risk=Medium" \
  --data-urlencode "sort=dateUpdated" \
  --data-urlencode "direction=desc" \
  --data-urlencode "page=1" \
  --data-urlencode "pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pour une synchronisation régulière, les paramètres suivants peuvent également être utiles : status, priority, subject, requesterEmail, source, externalNumber, referenceNumber, datePlannedStart, datePlannedEnd, createdAfter, createdBefore, updatedAfter et updatedBefore, lorsqu'ils sont disponibles dans le contrat actuel.

Encodez les valeurs textuelles et les dates pour l'URL. Utilisez search pour une recherche générale et le paramètre propre au champ pris en charge par le schéma pour un filtre précis. Ne supposez pas que chaque valeur de dictionnaire porte un nom anglais.


Changements - sélection des champs et inclusion des données

Le paramètre fields limite la réponse aux propriétés nécessaires à l'intégration. Le paramètre include ajoute les données liées :

curl --get "$BASE_URL/api/v1/changes/PUBLIC_CHANGE_UUID" \
  --data-urlencode "fields=subject,requesterEmail,status,priority,risk,datePlannedStart,datePlannedEnd" \
  --data-urlencode "include=files,relationships,users" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pour le modèle complet, vous pouvez utiliser fields=*. L'inclusion des fichiers, des relations et des utilisateurs nécessite les périmètres de lecture correspondants. fields ne contourne pas le contrôle d'accès et ne révèle pas les champs techniques pour lesquels la clé n'a pas d'autorisation.

Dans la réponse, vérifiez data.id, data.itemType, data.attributes et data.meta. Lisez les champs techniques comme pin ou isSpam, mais modifiez-les avec les actions dédiées décrites plus loin.


Changements - statistiques et valeurs des dictionnaires

Les statistiques peuvent par exemple compter les changements par niveau de risque. Il s'agit d'une opération de lecture qui ne modifie pas les enregistrements :

curl --get "$BASE_URL/api/v1/changes/stats" \
  --data-urlencode "field=risk" \
  --data-urlencode "limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Récupérez séparément les valeurs d'un champ pour construire des contrôles de filtre :

curl --get "$BASE_URL/api/v1/changes/values" \
  --data-urlencode "field=risk" \
  --data-urlencode "search=Medium" \
  --data-urlencode "limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Lisez d'abord le dictionnaire, puis envoyez la valeur renvoyée dans le body. C'est particulièrement important pour risk, status, priority et type, car leurs valeurs peuvent dépendre de la langue et des réglages d'une base donnée.


Changements - création d'un enregistrement

Créez un changement avec POST /api/v1/changes. Placez le type technique change et les champs inscriptibles dans attributes. L'exemple suivant contient les données de base, la classification, les informations d'intégration et tout le groupe de planification :

export IDEMPOTENCY_KEY="public-api-change-create-20260905130127"

curl --request POST "$BASE_URL/api/v1/changes" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --data-raw '{
    "itemType": "change",
    "attributes": {
      "customId": "PUBLIC-API-CHANGE-20260905130127-SOURCE",
      "subject": "PUBLIC-API-CHANGE-20260905130127 demande d'intégration",
      "requesterEmail": "[email protected]",
      "description": "Créé par le parcours Changes de l'API publique",
      "comments": "Changement d'intégration ITSM",
      "source": "Public API",
      "type": "Standard",
      "status": "Closed",
      "priority": "High",
      "impact": "Medium",
      "urgency": "High",
      "severity": "High",
      "services": "Codenica Public API",
      "tags": "public-api,change",
      "externalNumber": "EXT-PUBLIC-API-CHANGE-20260905130127",
      "referenceNumber": "REF-PUBLIC-API-CHANGE-20260905130127",
      "currency": "PLN",
      "estimatedCost": 12.5,
      "totalValue": 12.5,
      "datePlannedStart": "2030-01-15T09:00:00Z",
      "datePlannedEnd": "2030-01-15T17:00:00Z",
      "risk": "Medium",
      "impactInfo": "Évaluation de l'impact planifié pour la demande d'intégration",
      "rolloutPlan": "Déployez le changement approuvé et vérifiez les contrôles de santé.",
      "backoutPlan": "Restaurez la version précédente si la vérification échoue.",
      "reasonForChange": "La version actuelle de la plateforme nécessite une mise à jour contrôlée."
    }
  }'

Une requête réussie renvoie 201 Created. Enregistrez data.id, l'ETag de l'en-tête HTTP et data.meta.etag. La propriété facultative customValues sert aux champs personnalisés lorsque l'intégration connaît leur configuration.

Si la base exige d'autres valeurs de dictionnaire, ne recopiez pas les noms ci-dessus sans vérifier le schéma et l'endpoint values.


Changements - nouvelles tentatives sûres avec Idempotency-Key

Envoyez une Idempotency-Key unique avec chaque opération qui modifie les données. Si la réponse est perdue à cause d'une interruption réseau, répétez exactement la même requête avec la même clé :

curl --request POST "$BASE_URL/api/v1/changes" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-change-create-20260905130127" \
  --data-binary @change.json

L'idempotence fait qu'une nouvelle tentative identique renvoie le résultat de l'opération initiale au lieu de créer un second changement. La même clé ne doit pas être utilisée avec un autre body. Générez une nouvelle clé pour un nouveau changement, une modification, une relation, un fichier ou une action.

L'idempotence ne remplace pas l'ETag. Pour les opérations qui nécessitent un contrôle de version, envoyez aussi le If-Match actuel.


Changements - lecture d'un enregistrement et de son ETag

Après avoir créé ou trouvé un identifiant, lisez un changement :

export CHANGE_ID="PUBLIC_CHANGE_UUID"

curl --get "$BASE_URL/api/v1/changes/$CHANGE_ID" \
  --data-urlencode "fields=*" \
  --data-urlencode "include=files,relationships,users" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

L'ETag est renvoyé dans l'en-tête HTTP ETag et dans data.meta.etag. Considérez-le comme la version de ce changement précis et enregistrez-le avant toute nouvelle mutation.

L'ETag peut changer après la modification de champs, d'une relation, l'affectation d'un utilisateur, l'envoi ou la suppression d'un fichier, ou l'exécution d'une action de workflow. Après chaque mutation réussie, lisez le nouvel état ou récupérez le nouvel ETag dans la réponse.


Changements - mise à jour avec If-Match

Utilisez PATCH pour une modification partielle. Envoyez uniquement les champs à modifier, l'ETag actuel et une nouvelle clé d'idempotence :

curl --request PATCH "$BASE_URL/api/v1/changes/$CHANGE_ID" \
  --header "Accept: application/json" \
  --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-change-update-20260905130127" \
  --data-raw '{
    "attributes": {
      "description": "Changement mis à jour PUBLIC-API-CHANGE-20260905130127",
      "status": "Closed",
      "priority": "High",
      "risk": "Low",
      "impactInfo": "Évaluation de l'impact mise à jour",
      "rolloutPlan": "Exécutez le plan de déploiement révisé et vérifiez le service.",
      "backoutPlan": "Restaurez la version précédente si le changement révisé échoue.",
      "reasonForChange": "Justification de mise en œuvre mise à jour."
    }
  }'

Avec un ETag actuel, la réponse est 200 OK et contient une nouvelle version. Modifiez les champs techniques comme pin et isSpam avec leurs endpoints dédiés. Ne tentez pas de les modifier avec un PATCH ordinaire lorsque le schéma les marque en lecture seule.

Les dates de planification restent des champs ordinaires du changement et se mettent donc à jour dans attributes. Avant l'enregistrement, vérifiez que le schéma les marque comme writable.


Changements - ETag périmé ou manquant

Si un autre processus a modifié l'enregistrement après sa lecture, un ancien ETag ne peut pas remplacer la version la plus récente. Pour une valeur périmée, l'API renvoie 412 Precondition Failed et le code if_match_failed :

{
  "status": 412,
  "code": "if_match_failed"
}

L'absence de If-Match lors d'une mutation qui l'exige renvoie 428 Precondition Required avec le code if_match_required :

{
  "status": 428,
  "code": "if_match_required"
}

Après l'une ou l'autre réponse, relisez le changement, examinez son état actuel et décidez si votre mise à jour est toujours nécessaire. Envoyez-la ensuite avec le nouvel ETag et une nouvelle clé d'idempotence. Ne désactivez pas le contrôle de concurrence dans l'intégration.


Changements - opérations batch

Une opération batch regroupe plusieurs opérations indépendantes dans une seule requête. L'exemple suivant crée deux changements :

curl --request POST "$BASE_URL/api/v1/changes:batch" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-change-batch-create-20260905130127" \
  --data-raw '{
    "items": [
      {
        "operation": "create",
        "create": {
          "itemType": "change",
          "attributes": {
            "customId": "PUBLIC-API-CHANGE-20260905130127-BATCH-A",
            "subject": "Changement batch A",
            "requesterEmail": "[email protected]",
            "description": "Changement batch A",
            "source": "Public API",
            "type": "Standard",
            "status": "Open",
            "priority": "Medium",
            "risk": "Low",
            "datePlannedStart": "2030-02-10T09:00:00Z",
            "datePlannedEnd": "2030-02-10T12:00:00Z"
          }
        }
      },
      {
        "operation": "create",
        "create": {
          "itemType": "change",
          "attributes": {
            "customId": "PUBLIC-API-CHANGE-20260905130127-BATCH-B",
            "subject": "Changement batch B",
            "requesterEmail": "[email protected]",
            "description": "Changement batch B",
            "source": "Public API",
            "type": "Standard",
            "status": "Open",
            "priority": "Low",
            "risk": "High",
            "datePlannedStart": "2030-02-11T09:00:00Z",
            "datePlannedEnd": "2030-02-11T12:00:00Z"
          }
        }
      }
    ]
  }'

La réponse contient items, le statut de chaque opération et les compteurs succeeded et failed. Traitez chaque élément séparément. Un batch n'est pas une transaction tout-ou-rien : l'échec d'un élément ne rétablit pas nécessairement les autres.

La modification et la suppression nécessitent l'ETag de chaque enregistrement. Le body d'un batch comprenant une modification et une suppression peut être le suivant :

{
  "items": [
    {
      "operation": "update",
      "id": "CHANGE_A_UUID",
      "ifMatch": "\"CHANGE_A_ETAG\"",
      "update": {
        "attributes": {
          "description": "Mise à jour batch A"
        }
      }
    },
    {
      "operation": "delete",
      "id": "CHANGE_B_UUID",
      "ifMatch": "\"CHANGE_B_ETAG\""
    }
  ]
}

Une seule clé d'idempotence identifie toute la requête batch, et non les éléments individuellement. Après la réponse, enregistrez les identifiants et les ETag uniquement pour les enregistrements créés ou modifiés avec succès.


Changements - relations avec les objets

Les cibles possibles des relations sont renvoyées par changes/schema. Selon les accès et les données, un changement peut être lié à des actifs, des documents, d'autres changements, des tickets, des problèmes et des versions. Chaque cible doit être visible pour la clé et targetItemType doit correspondre au type réel de l'objet.

Ajouter une relation :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships" \
  --header "Accept: application/json" \
  --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-change-relationship-asset-20260905130127" \
  --data-raw '{
    "targetId": "ASSET_UUID",
    "targetDataSet": "assets",
    "targetItemType": "computer",
    "relationshipType": "related"
  }'

L'ajout d'une relation renvoie 201 Created. Plusieurs relations peuvent être ajoutées dans une seule requête :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships:batch" \
  --header "Accept: application/json" \
  --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-change-relationship-batch-20260905130127" \
  --data-raw '{
    "add": [
      {
        "targetId": "ASSET_UUID",
        "targetDataSet": "assets",
        "targetItemType": "computer",
        "relationshipType": "related"
      },
      {
        "targetId": "DOCUMENT_UUID",
        "targetDataSet": "documents",
        "targetItemType": "document",
        "relationshipType": "related"
      }
    ],
    "remove": []
  }'

Lire les relations :

curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

La réponse du batch contient les compteurs added, removed et skipped. Chaque modification de relation change l'ETag de la source ; relisez donc la valeur avant la mutation suivante.


Changements - suppression des relations

Supprimez une relation avec l'ETag actuel du changement source. Indiquez dans le chemin la collection cible et son identifiant :

curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships/changes/$TARGET_CHANGE_ID?relationshipType=related" \
  --header "Accept: application/json, application/problem+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-change-relationship-delete-20260905130127"

Pour un actif, utilisez relationships/assets/{TARGET_ID} ; pour un document, relationships/documents/{TARGET_ID}. Le paramètre relationshipType doit correspondre au type enregistré.

Vous pouvez aussi supprimer des relations dans le cadre d'une modification partielle :

curl --request PATCH "$BASE_URL/api/v1/changes/$CHANGE_ID" \
  --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-change-relationship-patch-20260905130127" \
  --data-raw '{
    "relationshipsToRemove": [
      {
        "targetId": "TARGET_UUID",
        "targetDataSet": "changes",
        "targetItemType": "change",
        "relationshipType": "related"
      }
    ]
  }'

Après la suppression, relisez la liste et vérifiez que la bonne cible a été retirée. La suppression d'une relation ne supprime pas l'enregistrement qui en était la cible.


Changements - relations avec les utilisateurs

Les relations avec les utilisateurs constituent un mécanisme séparé. Un changement prend en charge trois rôles : agent pour la personne qui réalise le travail, watcher pour un observateur et appUserRequester pour l'utilisateur à l'origine de la demande. Cet objet ne prend pas en charge clientRequester.

Affecter un agent :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships" \
  --header "Accept: application/json" \
  --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-change-agent-20260905130127" \
  --data-raw '{
    "targetId": "USER_UUID",
    "targetDataSet": "users",
    "relationshipType": "agent"
  }'

Ajouter un observateur avec un batch :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships:batch" \
  --header "Accept: application/json" \
  --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-change-watcher-20260905130127" \
  --data-raw '{
    "add": [
      {
        "targetId": "WATCHER_USER_UUID",
        "targetDataSet": "users",
        "relationshipType": "watcher"
      }
    ],
    "remove": []
  }'

Lire les relations avec les utilisateurs :

curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Supprimer une affectation en indiquant le type de relation :

curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships/users/$USER_ID?relationshipType=appUserRequester" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header 'If-Match: "CURRENT_ETAG"' \
  --header "Idempotency-Key: public-api-change-app-user-requester-delete-20260905130127"

Utilisez la même route pour supprimer un agent, un observateur ou le demandeur, en modifiant relationshipType. Un observateur peut aussi être supprimé par batch avec un tableau add vide et une entrée dans remove.


Changements - fichiers

Un fichier envoyé vers un changement possède son propre identifiant et ses métadonnées. L'upload nécessite l'ETag actuel, une nouvelle clé d'idempotence et une requête multipart/form-data :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/files?relationshipType=documentation" \
  --header "Accept: application/json, application/problem+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-change-file-one-20260905130127" \
  --form "[email protected];type=text/plain"

Un upload réussi renvoie 201 Created avec l'identifiant et les métadonnées du fichier. Lisez la liste des fichiers ainsi :

curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/files?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Téléchargez le contenu comme donnée binaire et enregistrez-le dans un fichier :

export FILE_ID="FILE_UUID"

curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/files/$FILE_ID/content" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output downloaded-change-file.bin

Vous pouvez attacher un fichier existant à un autre changement. L'ETag concerne alors le changement cible :

curl --request POST "$BASE_URL/api/v1/changes/OTHER_CHANGE_UUID/files/$FILE_ID?relationshipType=manual" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header 'If-Match: "OTHER_CHANGE_ETAG"' \
  --header "Idempotency-Key: public-api-change-file-attach-20260905130127"

Supprimez un fichier avec DELETE /api/v1/changes/{id}/files/{fileId}. L'opération renvoie 200 OK lorsqu'elle réussit. Après un upload, une association ou une suppression, actualisez l'ETag du changement et la liste des fichiers.

curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_ID/files/$FILE_ID" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header 'If-Match: "CURRENT_ETAG"' \
  --header "Idempotency-Key: public-api-change-file-delete-20260905130127"

Changements - épinglage, spam et réouverture

L'épinglage, le marquage comme spam et la réouverture sont des actions distinctes. Chacune exige le If-Match actuel et une nouvelle Idempotency-Key.

Épingler un changement :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/pin" \
  --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-change-pin-20260905130127" \
  --data-raw '{"pin":2}'

Pour retirer l'épingle, utilisez la même route avec null, si le schéma et les autorisations le permettent :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/pin" \
  --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-change-unpin-20260905130127" \
  --data-raw '{"pin":null}'

Marquer comme spam puis annuler ce marquage :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/spam" \
  --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-change-spam-20260905130127" \
  --data-raw '{"isSpam":true}'

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/spam" \
  --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-change-spam-undo-20260905130127" \
  --data-raw '{"isSpam":false}'

Rouvrir un changement fermé :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/reopen" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header 'If-Match: "CURRENT_ETAG"' \
  --header "Idempotency-Key: public-api-change-reopen-20260905130127"

Après chaque action, relisez le changement et enregistrez son nouvel ETag. Les périmètres nécessaires sont respectivement changes:pin:write, changes:spam:write et changes:reopen:write.


Changements - évaluation et escalade

Enregistrez une évaluation avec un endpoint distinct. Vous pouvez y joindre une demande d'escalade :

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/rating" \
  --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-change-rating-20260905130127" \
  --data-raw '{
    "rating": 4,
    "feedback": "Évaluation envoyée par l'intégration",
    "isEscalationRequested": true,
    "escalationRequestReason": "Demande d'escalade via l'API publique"
  }'

changes:rating:write est nécessaire pour enregistrer l'évaluation et changes:escalation:write pour joindre une demande d'escalade. Utilisez une valeur d'évaluation prise en charge par l'API. Après l'enregistrement, lisez notamment rating, feedback, les dates d'évaluation et escalationRequestReason.

Si aucune escalade n'est nécessaire, omettez isEscalationRequested et escalationRequestReason. N'envoyez pas de demande d'escalade sans motif.


Changements - approbation et décision

Créez une approbation comme objet approval distinct et reliez-la au changement. Vous avez besoin des périmètres du module d'approbation et de l'identifiant de la personne qui doit prendre la décision :

export APPROVER_ID="USER_UUID"

curl --request POST "$BASE_URL/api/v1/approvals" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-change-approval-create-20260905130127" \
  --data-raw '{
    "itemType": "approval",
    "approverId": "USER_UUID",
    "attributes": {
      "customId": "PUBLIC-API-CHANGE-20260905130127-APPROVAL",
      "category": "Public API",
      "description": "Approbation du changement"
    },
    "relationships": [
      {
        "targetId": "CHANGE_UUID",
        "targetDataSet": "changes",
        "targetItemType": "change"
      }
    ]
  }'

La personne indiquée dans approverId peut prendre la décision via la route du changement. APPROVAL_ID est l'identifiant de l'approbation, et non celui d'un utilisateur :

export APPROVAL_ID="APPROVAL_UUID"

curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/approvals/$APPROVAL_ID" \
  --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-change-approval-decision-20260905130127" \
  --data-raw '{
    "approve": true,
    "remark": "Approuvé via l'API publique Changes."
  }'

Pour refuser, envoyez approve à false avec votre propre remarque. Après la décision, lisez l'approbation et vérifiez son statut et sa date de décision. Actualisez ensuite le changement, car la décision peut modifier son ETag et l'état du processus.


Changements - suppression d'un enregistrement

Relisez le changement avant de le supprimer et utilisez son ETag actuel :

curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_ID" \
  --header "Accept: application/json, application/problem+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-change-delete-20260905130127"

Après 200 OK, envoyez un GET sur le même UUID. Attendez-vous à un 404 avec le code change_not_found ou le code correspondant à l'enregistrement. Pour contrôler la synchronisation, faites une liste filtrée par customId et vérifiez que totalItems vaut zéro.

La suppression ne doit pas servir à archiver l'historique. Avant une opération en production, vérifiez la politique de conservation, les relations et les obligations d'audit. Si l'enregistrement doit rester dans l'historique, modifiez son statut au lieu de le supprimer.


Changements - erreurs, limites et sécurité

Les erreurs utilisent le format Problem Details application/problem+json. Exemple :

{
  "type": "https://docs.codenica.com/errors/change_not_found",
  "title": "Changement introuvable.",
  "status": 404,
  "detail": "Le changement n'existe pas ou n'est pas accessible par cet appelant.",
  "instance": "/api/v1/changes/PUBLIC_CHANGE_UUID",
  "code": "change_not_found",
  "requestId": "request-id-from-response"
}

Dans la logique d'intégration, basez-vous surtout sur status et code. Le champ detail est destiné aux personnes et sa formulation peut changer.

HTTP
Signification
401
authentification absente ou incorrecte
403
périmètre requis ou autorisation utilisateur manquant
404
enregistrement, fichier ou cible de relation absent ou invisible
409
conflit de données ou d'idempotence
412
ETag périmé
422
body ou valeurs de champs invalides
428
If-Match ou Idempotency-Key manquant
429
limite de requêtes dépassée

Lisez X-RateLimit-Limit et X-RateLimit-Remaining. Après 429, appliquez un backoff et respectez Retry-After lorsqu'il est présent. Ne contournez pas les limites en créant plusieurs clés ou en augmentant le parallélisme. Enregistrez la méthode, l'endpoint, le statut et requestId, mais jamais le Client Secret ni les en-têtes d'authentification complets.


Changements - ordre recommandé pour l'intégration

  1. Définissez BASE_URL pour la bonne installation Cloud ou On-Premise.
  2. Créez une clé distincte dans Paramètres - API - API Keys et sélectionnez les périmètres minimum.
  3. Placez le Client ID et le Client Secret dans un coffre sécurisé.
  4. Envoyez GET /api/v1/context et vérifiez la base, les périmètres et les limites.
  5. Récupérez GET /api/v1/changes/schema et les valeurs utilisées par l'intégration.
  6. Lisez la liste des changements ou créez-en un avec POST et une Idempotency-Key unique.
  7. Enregistrez l'UUID du changement et son ETag.
  8. Actualisez l'ETag avant chaque mutation et utilisez une nouvelle clé d'idempotence.
  9. Ajoutez les relations, les utilisateurs et les fichiers après avoir vérifié le catalogue des cibles dans le schéma.
  10. Effectuez séparément les actions de workflow et les décisions d'approbation, puis relisez le nouvel état après chacune.
  11. En cas de 412, relisez l'enregistrement, résolvez le conflit et relancez l'opération en connaissance de cause.
  12. Pour un batch, contrôlez chaque élément, car une erreur partielle ne doit pas annuler les réussites.
  13. Gérez 429, conservez requestId sans secret et supprimez la clé lorsque l'intégration n'est plus utilisée.

Ce parcours permet de synchroniser des changements planifiés avec un autre système sans dépendre de la structure interne de la base. Si la configuration des champs, l'adresse de l'installation ou les périmètres de la clé changent, relisez le contexte et le schéma.