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 indiquerefers_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.
| Type | Forme en lecture | Forme en écriture |
|---|---|---|
reference / owner | { "id": "61", "label": "ACME France" } | chaîne d'identifiant simple : "61" |
picklist | la 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 |
boolean | JSON true / false | idem |
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" } }
252curl -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
nullimbriqué dansline_itemsou le bloc de totauxgroupreste 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
falseou0(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> & 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 & 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 deClosed 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 lavalueprovenant duoptions[]du schéma, jamais lelabel. - Supposer qu'un champ
textrevient 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=htmllorsque 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/Potentialsrenvoie une erreur 404 (Unknown module: Potentials). Utilisez le slug en minuscules issu deGET /api/v1/modules(potentials), le même que celui déjà pointé parlinks.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 unGETd'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 unGETd'une seule fiche (étape 8).
Updated about 1 month ago
