Champs, formats et mise en forme des réponses

Ce guide montre comment découvrir la liste des champs d'un module directement depuis l'API, écrire la valeur correcte pour chaque type de champ sans avoir à deviner, et contrôler le contenu d'une réponse — y compris lire un champ de texte long en HTML brut plutôt qu'en texte brut. Il vous faut seulement un jeton d'API et l'URL de base de votre environnement, comme indiqué dans le guide de démarrage ; les autres guides renvoient ici pour toute question de champs et de formats plutôt que de répéter ce contenu.

1. Lister les modules

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules" | jq '.data[0:5]'
[
  {
    "id": "leads",
    "type": "module",
    "attributes": {
      "name": "Leads",
      "label": "Pistes",
      "singular": "SINGLE_LEADS",
      "is_entity": true,
      "createable": true,
      "updateable": true,
      "deleteable": true,
      "retrieveable": true,
      "links": { "records": "/api/v1/leads", "schema": "/api/v1/modules/leads" }
    }
  },
  {
    "id": "contacts",
    "type": "module",
    "attributes": {
      "name": "Contacts",
      "label": "Contacts",
      "singular": "SINGLE_CONTACTS",
      "is_entity": true,
      "createable": true,
      "updateable": true,
      "deleteable": true,
      "retrieveable": true,
      "links": { "records": "/api/v1/contacts", "schema": "/api/v1/modules/contacts" }
    }
  },
  {
    "id": "accounts",
    "type": "module",
    "attributes": { "name": "Accounts", "label": "Comptes", "singular": "SINGLE_ACCOUNTS", "is_entity": true, "createable": true, "updateable": true, "deleteable": true, "retrieveable": true, "links": { "records": "/api/v1/accounts", "schema": "/api/v1/modules/accounts" } }
  },
  {
    "id": "potentials",
    "type": "module",
    "attributes": { "name": "Potentials", "label": "Affaires", "singular": "SINGLE_POTENTIALS", "is_entity": true, "createable": true, "updateable": true, "deleteable": true, "retrieveable": true, "links": { "records": "/api/v1/potentials", "schema": "/api/v1/modules/potentials" } }
  },
  {
    "id": "quotes",
    "type": "module",
    "attributes": { "name": "Quotes", "label": "Devis", "singular": "SINGLE_QUOTES", "is_entity": true, "createable": true, "updateable": true, "deleteable": true, "retrieveable": true, "links": { "records": "/api/v1/quotes", "schema": "/api/v1/modules/quotes" } }
  }
]

Il y a 16 modules au total : accounts, comments, contacts, documents, events, helpdesk, invoices, leads, potentials, pricebooks, products, purchase-orders, quotes, sales-orders, services, tasks.

Le id de chaque entrée est le slug — la valeur que vous utilisez dans chaque URL de fiche (/api/v1/{slug}) et, comme le montre links.schema ci-dessus, dans l'URL de schéma également.

attributes.name est le nom interne du module (Quotes, Products…), indiqué surtout à titre de référence. Un module cache un piège : le nom interne du slug tasks est Calendar, pas Tasks.

2. Lire le schéma des champs d'un module

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules/potentials" | jq '.data.attributes.fields | length'
22
curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules/potentials" \
  | jq '.data.attributes.fields[0:5] | map({name: .name, label: .label, type: .type, mandatory: .mandatory})'
[
  {
    "name": "potentialname",
    "label": "Nom affaire",
    "type": "string",
    "mandatory": true
  },
  {
    "name": "contact_id",
    "label": "Contact",
    "type": "reference",
    "mandatory": false
  },
  {
    "name": "related_to",
    "label": "Compte",
    "type": "reference",
    "mandatory": true
  },
  {
    "name": "cf_1375",
    "label": "Besoin",
    "type": "string",
    "mandatory": false
  },
  {
    "name": "closingdate",
    "label": "Echéance",
    "type": "date",
    "mandatory": false
  }
]

name est la valeur que vous envoyez et recevez dans chaque requête ; label est ce que l'interface du CRM affiche à un utilisateur qui la consulte.

Le chemin du schéma prend le slug, pas le nom interne du module. GET /api/v1/modules/potentials (le slug en minuscules de l'étape 1) renvoie le schéma ; GET /api/v1/modules/Potentials (l'attribut name avec majuscule) n'existe pas :

curl -sS -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules/Potentials"
# 404
curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules/Potentials"
{"error":{"code":"NOT_FOUND","message":"Unknown module: Potentials","request_id":"7415c115-4654-4a2f-b638-a2ac8adb5269"}}

Chaque champ du tableau fields porte name (ce que vous envoyez/recevez), label (ce qu'affiche l'interface), type, mandatory, editable et max_length. Selon le type du champ, il porte aussi l'un des éléments suivants :

  • options — les valeurs valides d'une picklist.
  • refers_to — le module cible d'un champ référence (target_modules à la place lorsque la référence est polymorphe, par ex. le lien produit/service d'une ligne de commande).
  • schema_url — pour les champs pays/devise (voir l'étape 6).

3. Trouver les champs obligatoires

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules/potentials" \
  | jq '.data.attributes.fields[] | select(.mandatory == true) | {name: .name, label: .label, type: .type}'
{ "name": "potentialname", "label": "Nom affaire", "type": "string" }
{ "name": "related_to", "label": "Compte", "type": "reference" }
{ "name": "sales_stage", "label": "Phase de vente", "type": "picklist" }
{ "name": "assigned_user_id", "label": "Assigné à", "type": "owner" }

Ces quatre champs sont des champs ordinaires de la fiche elle-même :

  • potentialname — le nom de l'affaire.
  • related_to — le compte auquel l'affaire appartient. L'interface l'affiche sous le libellé « Compte » (Account) bien que le nom du champ dise « related to » ; le schéma complet indique refers_to: ["accounts"].
  • sales_stage — voir l'étape 5 pour son piège lié aux picklists.
  • assigned_user_id — attribué par défaut côté serveur au propriétaire du jeton si vous l'omettez (voir le guide de démarrage).

4. Champs personnalisés

Les champs personnalisés apparaissent dans la même liste, nommés cf_XXXX :

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/modules/potentials" \
  | jq '.data.attributes.fields[] | select(.name | startswith("cf_")) | {name: .name, label: .label, type: .type}'
{ "name": "cf_1375", "label": "Besoin", "type": "string" }
{ "name": "cf_1283", "label": "Raison de la perte", "type": "picklist" }

Le suffixe numérique n'a pas de signification en soi — utilisez label pour repérer le champ dans l'interface d'administration, et name (par ex. cf_1375) pour le lire et l'écrire. Ne codez jamais en dur un numéro cf_XXXX — récupérez-le plutôt via cet appel de schéma.

5. Formats de valeurs à connaître

La plupart des types sont des valeurs JSON ordinaires qui ne demandent aucune explication — string, integer, float, percentage, boolean, email, phone et url se lisent et s'écrivent exactement comme on s'y attend. Le tableau ci-dessous couvre les types dont la forme mérite d'être connue avant d'en écrire un.

TypeForme en lectureForme en écriture
reference / owner{ "id": "61", "label": "ACME France" }chaîne d'identifiant simple : "61"
picklistla valeur stockée, par ex. "Closed Lost"la même valeur stockée — pas le libellé traduit ("Perdue")
date"2026-09-15" (YYYY-MM-DD)même format
datetime (horodatages)"2026-08-03T12:22:49Z" (ISO 8601, UTC)même format
booleanJSON true / falseidem
tout identifiant (id, assigned_user_id.id, …)chaîne d'entier, par ex. "62"chaîne d'entier

Voici une écriture de champ référence, sur le account_id d'un contact :

curl -sS -X PATCH "https://app.initiative-crm.com/api/v1/contacts/62" \
  -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" -H "Content-Type: application/json" \
  -d '{"data":{"attributes":{"account_id":"61"}}}' | jq '.data.attributes.account_id'
{ "id": "61", "label": "ACME France" }

{"account_id": {"id": "61"}} (la même forme que celle renvoyée par l'API en lecture) est également acceptée — l'API extrait .id d'un objet si vous en envoyez un.

Les picklists s'écrivent avec la valeur stockée du schéma, pas le libellé affiché dans l'interface. Pour sales_stage, les valeurs stockées sont Qualification, Négociation, Closed Lost et Closed Won :

curl -sS -X PATCH "https://app.initiative-crm.com/api/v1/potentials/1587" \
  -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" -H "Content-Type: application/json" \
  -d '{"data":{"attributes":{"sales_stage":"Closed Lost"}}}' | jq '.data.attributes.sales_stage'
"Closed Lost"

6. Pays et devises

Les champs pays et devise (uitype 112 et 117) se résolvent via deux endpoints de référence statiques, au lieu de renvoyer des options en ligne :

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/countries" | jq '.data[0], .meta.total'
{ "id": "3", "type": "country", "attributes": { "name": "Afghanistan", "code": "AF" } }
252
curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/currencies" | jq '.data'
[
  { "id": "1", "type": "currency", "attributes": { "label": "Euro", "symbol": "€", "code": "EUR", "conversion_rate": 1 } }
]

Les deux listes sont statiques (cet exemple n'a qu'une seule devise configurée ; la vôtre peut en avoir plusieurs). Récupérez chacune une seule fois au démarrage et mettez-la en cache ; il n'y a aucune raison d'appeler l'un ou l'autre endpoint par fiche.

7. Demander moins de champs

?fields=a,b,c restreint les attributes renvoyés — mais uniquement sur les endpoints de liste et de recherche (GET /{module} et POST /{module}/search). Cela n'a aucun effet sur un GET /{module}/{id} d'une seule fiche : celui-ci renvoie toujours tous les champs, quel que soit fields=.

curl -sS -G -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" "https://app.initiative-crm.com/api/v1/contacts" \
  --data-urlencode "filter[id]=62" --data-urlencode "fields=firstname,lastname" \
  | jq '.data[0].attributes | keys'
["createdtime", "firstname", "lastname", "modifiedtime"]

createdtime et modifiedtime reviennent toujours sur les endpoints de liste/recherche, même si vous ne les avez pas demandés. id et type reviennent aussi toujours, mais au niveau racine de chaque élément, pas dans attributes.

Un nom de champ inconnu renvoie une erreur 400 — sur les endpoints de liste/recherche :

curl -sS -G -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
  "https://app.initiative-crm.com/api/v1/contacts" --data-urlencode "fields=not_a_real_field"
400
{ "code": "INVALID_FILTER", "message": "Unknown field 'not_a_real_field' in fields parameter.", "request_id": "bad8c32e-a71c-4ec1-9dce-55f46734758d" }

Le même fields=not_a_real_field sur GET /contacts/{id} (récupération d'une seule fiche) est ignoré silencieusement — pas d'erreur, pas de filtrage, la fiche complète est renvoyée. Ne comptez pas sur fields= pour la validation ou le contrôle de taille sur une récupération d'une seule fiche.

8. Champs vides

Les champs sans valeur sont renvoyés en JSON sous la forme null par défaut — ils ne sont pas omis. Passez ?include_nulls=false pour les exclure entièrement de la réponse.

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" "https://app.initiative-crm.com/api/v1/contacts/62" \
  | jq '.data.attributes | keys | length'
curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" "https://app.initiative-crm.com/api/v1/contacts/62?include_nulls=false" \
  | jq '.data.attributes | keys | length'
29
23

Ce contact compte 29 champs au total, dont 6 sont nuls ; include_nulls=false supprime exactement ces 6 champs, sans en laisser aucun :

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" "https://app.initiative-crm.com/api/v1/contacts/62?include_nulls=false" \
  | jq '.data.attributes | to_entries | map(select(.value == null)) | length'
0

Quelques points à connaître sur ce paramètre :

  • Il fonctionne de la même façon sur les endpoints de liste, de recherche, de fiche unique et de fiches liées.
  • Il n'agit que sur les attributs de premier niveau — un null imbriqué dans line_items ou le bloc de totaux group reste présent dans la réponse, quel que soit ce que vous passez.
  • C'est une exclusion facultative, pas un interrupteur : toute valeur autre que false ou 0 (y compris une faute de frappe) est traitée comme « tout garder », et vous récupérez la réponse complète.

9. Texte enrichi : notes, commentaires et comptes-rendus

C'est l'option de mise en forme de réponse la plus largement proposée dans l'API : 64 opérations l'exposent. Elle s'applique à tout champ dont le type est text — comptes-rendus, commentaires, descriptions, etc. Ces champs stockent du texte enrichi, mais par défaut l'API renvoie du texte brut : balises supprimées, entités HTML décodées, limites de blocs transformées en sauts de ligne.

Écrivez du HTML dans le compte-rendu (comment) d'un événement :

curl -sS -X PATCH "https://app.initiative-crm.com/api/v1/events/5680" \
  -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" -H "Content-Type: application/json" \
  -d '{"data":{"attributes":{"comment":"<p>Agreed scope and timeline.</p><p>Next step: <b>send the quote</b> &amp; confirm budget.</p>"}}}' \
  | jq '.data.attributes.comment'
"Agreed scope and timeline.\nNext step: send the quote & confirm budget."

Relisez-le de la façon par défaut — même forme en texte brut, pas ce à quoi on pourrait s'attendre pour quelque chose que vous venez d'écrire en HTML :

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" "https://app.initiative-crm.com/api/v1/events/5680" \
  | jq '.data.attributes.comment'
"Agreed scope and timeline.\nNext step: send the quote & confirm budget."

Relisez-le avec ?rich_text=html — le balisage stocké, intact :

curl -sS -H "Authorization: Bearer itv_YOUR_TOKEN_HERE" "https://app.initiative-crm.com/api/v1/events/5680?rich_text=html" \
  | jq '.data.attributes.comment'
"<p>Agreed scope and timeline.</p><p>Next step: <b>send the quote</b> & confirm budget.</p>"

Les deux modes décodent &amp; en & ; seule la suppression des balises diffère entre eux. Les écritures prennent toujours du HTML brut — il n'existe pas de mode d'écriture en texte brut — et rich_text=html est en lecture seule : cela change la façon dont une valeur revient, pas la façon dont vous l'envoyez.

Erreurs courantes

  • Utiliser un libellé de picklist traduit au lieu de la valeur stockée. Écrire "sales_stage": "Perdue" (le libellé français de Closed Lost) échoue : 422 VALIDATION_ERROR, {"field":"sales_stage","code":"INVALID_OPTION","message":"Value 'Perdue' is not a valid option for 'sales_stage'. See GET /api/v1/modules/{module} for valid options."}. Envoyez toujours la value provenant du options[] du schéma, jamais le label.
  • Supposer qu'un champ text revient exactement tel qu'il a été stocké. La lecture par défaut supprime le HTML pour ne garder que du texte brut (étape 9). Passez ?rich_text=html lorsque vous avez besoin de récupérer le balisage.
  • Mettre le nom du module dans le chemin du schéma au lieu du slug. GET /api/v1/modules/Potentials renvoie une erreur 404 (Unknown module: Potentials). Utilisez le slug en minuscules issu de GET /api/v1/modules (potentials), le même que celui déjà pointé par links.schema.
  • Écrire un champ référence avec son libellé au lieu de son identifiant. Envoyer "account_id": "ACME France" ne provoque pas d'erreur — c'est ignoré silencieusement et la valeur précédente est conservée. Les champs référence s'écrivent avec l'identifiant numérique ("61"), jamais avec leur libellé affiché.
  • S'attendre à ce que fields= ait un effet sur un GET d'une seule fiche. Il est accepté mais ignoré à cet endroit — fields= ne filtre que sur les endpoints de liste et de recherche. include_nulls=false, lui, fonctionne bien sur un GET d'une seule fiche (étape 8).

Did this page help you?