Convertir un prospect
Ce guide montre comment convertir un prospect en contact et en compte (et, si vous le souhaitez, en affaire) en un seul appel, pourquoi l'appel minimal fonctionne généralement du premier coup, comment surcharger des champs sur chaque cible avec la même validation qu'appliquerait une création directe, comment contrôler où finissent les fiches associées du prospect, et pourquoi la conversion n'a lieu qu'une seule fois. Il vous faut seulement un jeton d'API et votre URL de base, comme indiqué dans le guide de démarrage ; pour les noms de champs, les types et l'enveloppe d'écriture en général, consultez Champs, formats et mise en forme des réponses et Créer, modifier et supprimer des fiches — ce guide ne couvre que ce qui est spécifique à la conversion.
1. Ce que fait la conversion
POST /api/v1/leads/{id}/convert transforme un prospect en contact et en compte — les deux sont toujours créés, même si vous envoyez des objets vides pour eux — et, seulement si vous en demandez une, en affaire (potential). Le prospect lui-même est alors marqué comme converti. Il n'existe aucun moyen via l'API de revenir en arrière : un prospect converti reste converti, et un second POST sur le même endpoint est refusé (section 8).
Chaque cible est validée exactement comme si vous la créiez directement — mêmes champs obligatoires, mêmes règles de format — sauf qu'un champ peut aussi être satisfait par une valeur reprise du prospect, par le propriétaire auto-assigné, ou par la valeur par défaut configurée d'un champ picklist/date. C'est le mécanisme derrière l'appel minimal de la section suivante.
2. L'appel minimal
curl -sS -X POST "https://app.initiative-crm.com/api/v1/leads/65/convert" \
-H "Authorization: Bearer itv_YOUR_TOKEN_HERE" -H "Content-Type: application/json" \
-d '{"data":{"attributes":{"contact":{},"account":{}}}}'contact et account sont des clés requises — mais leurs objets peuvent être vides. Cela réussit quand même car chaque champ obligatoire des deux cibles finit par être satisfait sans surcharge :
- Les champs obligatoires de Contacts sont
lastnameetassigned_user_id. Lelastnamede ce prospect (« Fixture 1 ») est directement repris dulastnamepropre au prospect. - Les champs obligatoires d'Accounts sont
accountnameetassigned_user_id. Lecompanydu prospect (« Fixture Co 1 ») est repris pour devenir l'accountnamedu compte. assigned_user_idsur les deux cibles s'auto-assigne au propriétaire du jeton, comme pour toute création qui l'omet.
Envoyer contact ou account sous une forme autre qu'un objet — omettre complètement la clé, ou envoyer null — est rejeté purement et simplement (la section 8 montre l'erreur exacte). Un objet vide {} est la bonne façon de dire « utilisez simplement ce que le prospect a déjà ».
Si le champ source du prospect lui-même est également vide — par exemple si son company est vide et que vous ne surchargez pas accountname — il n'y a rien à reprendre et aucune valeur par défaut ne s'applique (c'est un simple champ chaîne, pas un picklist ni une date), donc la création échoue à la validation sur account.accountname avec REQUIRED, de la même façon qu'un POST /accounts {} nu échouerait.
3. Ce que contient la réponse
{
"data": {
"lead_id": "65",
"contact": {
"id": "1604",
"type": "contacts",
"attributes": {
"lastname": "Fixture 1",
"email": "",
"isconvertedfromlead": true,
"account_id": { "id": "1603", "label": "Fixture Co 1" },
"assigned_user_id": { "id": "7206", "label": "Taylor Morgan" }
}
},
"account": {
"id": "1603",
"type": "accounts",
"attributes": {
"accountname": "Fixture Co 1",
"isconvertedfromlead": true,
"assigned_user_id": { "id": "7206", "label": "Taylor Morgan" }
}
}
},
"meta": { "request_id": "cd88f40c-152f-4ccf-990f-25b1f1cf0c0d" }
}201, pas 200 — une conversion crée toujours au moins une nouvelle fiche. La réponse a sa propre forme (LeadConversionResponse), pas l'enveloppe de collection habituelle {id,type,attributes} : lead_id est l'id du prospect que vous venez de convertir, et contact/account (et potential, si demandé — section 5) sont chacun une enveloppe de fiche complète pour la fiche qui a été créée, exactement comme le renverrait GET /api/v1/contacts/{id}. Les deux fiches créées portent isconvertedfromlead: true, et l'account_id du contact pointe déjà vers le nouveau compte — le lien entre eux est établi pour vous.
Si en revanche un compte existant porte déjà exactement le même accountname que celui que la requête produirait, ce compte est réutilisé plutôt qu'un second n'en soit créé — bon à savoir si vous convertissez plusieurs prospects pour la même société et attendez un compte partagé unique plutôt que des doublons.
4. Surcharger les champs des cibles
Tout ce que vous mettez à l'intérieur de contact, account ou potential remplace la valeur reprise du prospect pour ce champ — les mêmes règles de format s'appliquent que pour une création directe (champs référence sous forme d'id simple, picklists sous leur valeur stockée exacte, dates au format YYYY-MM-DD ; voir Champs, formats et mise en forme des réponses) :
curl -sS -X POST "https://app.initiative-crm.com/api/v1/leads/66/convert" \
-H "Authorization: Bearer itv_YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
"data": { "attributes": {
"contact": { "email": "[email protected]" },
"account": { "accountname": "Fixture Co 2 SAS" },
"potential": { "potentialname": "Fixture Co 2 — first deal", "amount": 5000 },
"transfer_to": ["account", "potential"]
} } }'{
"data": {
"lead_id": "66",
"contact": {
"id": "1606", "type": "contacts",
"attributes": { "lastname": "Fixture 2", "email": "[email protected]", "account_id": { "id": "1605", "label": "Fixture Co 2 SAS" } }
},
"account": {
"id": "1605", "type": "accounts",
"attributes": { "accountname": "Fixture Co 2 SAS" }
},
"potential": {
"id": "1607", "type": "potentials",
"attributes": {
"potentialname": "Fixture Co 2 — first deal",
"amount": 5000,
"closingdate": null,
"sales_stage": "Préparation Devis",
"contact_id": { "id": "1606", "label": " Fixture 2" },
"related_to": { "id": "1605", "label": "Fixture Co 2 SAS" }
}
}
},
"meta": { "request_id": "798e271c-90b2-48cd-a437-eec451273cab" }
}201, et cela a réussi du premier coup — cet appel s'est exécuté sans rien ajouter au-delà de ce qui est montré ci-dessus. Chaque champ obligatoire de chaque cible a fini par être satisfait, par l'un de quatre mécanismes distincts :
- une surcharge explicite —
account.accountname,contact.email(non obligatoire, montré pour prouver que les surcharges s'appliquent),potential.potentialname; - une valeur reprise du prospect —
contact.lastname(à partir dulastnamepropre du prospect) ; - le propriétaire auto-assigné —
assigned_user_idsur les trois cibles, par défaut au propriétaire du jeton ; - une valeur par défaut de picklist —
potential.sales_stageest revenu à"Préparation Devis"alors qu'il n'a jamais été envoyé, carsales_stageest un picklist et les champs picklist/date reçoivent leur valeur par défaut configurée lorsque rien d'autre ne fournit de valeur.
potential.closingdate est un champ date et n'est pas obligatoire, donc revenir à null est normal — vérifiez votre propre schéma avant de présumer qu'un champ a besoin d'une valeur.
Il existe un cinquième mécanisme, propre à la conversion, invisible dans la charge utile : potential.related_to et potential.contact_id ne vous sont jamais demandés du tout, même si related_to est obligatoire sur une création directe de Potentials. La conversion les définit toujours elle-même (le nouveau compte et le nouveau contact que vous venez de créer), ils sont donc exemptés de validation plutôt que définis par défaut ou repris — les envoyer vous-même n'a aucun effet.
Lisez la liste réelle des champs obligatoires d'une cible depuis le schéma de son module avant de vous fier à quoi que ce soit de tout cela — ne devinez pas :
curl -sS "https://app.initiative-crm.com/api/v1/modules/potentials" \
-H "Authorization: Bearer itv_YOUR_TOKEN_HERE" \
| jq '.data.attributes.fields[] | select(.mandatory==true) | {name: .name, label: .label, type: .type}'Pour la forme générale des erreurs de validation et leurs codes (REQUIRED, INVALID_OPTION, …), consultez Créer, modifier et supprimer des fiches — un échec de conversion utilise l'enveloppe 422 VALIDATION_ERROR identique, simplement avec le field de chaque violation préfixé par la cible (account.accountname, contact.lastname, potential.sales_stage, …).
5. Créer aussi une affaire
potential est la seule cible optionnelle. Omettez-la et vous obtenez un contact et un compte ; incluez-la et vous obtenez aussi une affaire, déjà liée aux deux.
Vous avez rarement besoin de le remplir :
related_toetassigned_user_idsont définis par la conversion elle-mêmesales_stageretombe sur sa valeur par défautpotentialnameest repris ducompanydu prospect
Donc "potential": {} fonctionne généralement du premier coup. Cela échoue seulement quand le company du prospect est vide — envoyez alors potentialname vous-même, ou vous obtiendrez 422 REQUIRED.
6. Où vont les fiches associées
transfer_to est un sous-ensemble de ["contact", "account", "potential"] (pertinent uniquement pour les cibles que vous avez effectivement créées) qui contrôle quelle nouvelle fiche hérite des propres fiches associées du prospect — ses notes, ses activités, tout ce qui lui était lié en tant que prospect. Omis complètement, il vaut par défaut toutes les cibles que vous avez créées. L'exemple de la section 4 définissait "transfer_to": ["account", "potential"], en laissant délibérément contact de côté — le nouveau contact était créé dans tous les cas, simplement il ne reçoit pas les fiches associées du prospect ; celles-ci vont à la place vers le compte et l'affaire.
7. Définir le propriétaire
assigned_user_id au niveau supérieur d'attributes définit le propriétaire de toutes les cibles créées à la fois, et prend par défaut l'utilisateur propre du jeton lorsqu'il est complètement omis (c'est ce qui s'est passé dans les deux exemples ci-dessus — chaque fiche créée a fini par appartenir à Taylor Morgan, l'utilisateur propre du jeton, sans qu'on le demande). Placez plutôt assigned_user_id à l'intérieur de contact, account ou potential (à côté de toute autre surcharge pour cette cible) pour définir un propriétaire différent pour cette seule fiche — une valeur par cible l'emporte toujours sur celle de niveau supérieur pour cette cible.
8. La conversion n'a lieu qu'une seule fois
Convertir un prospect déjà converti est refusé, pas silencieusement ignoré :
curl -sS -X POST "https://app.initiative-crm.com/api/v1/leads/65/convert" \
-H "Authorization: Bearer itv_YOUR_TOKEN_HERE" -H "Content-Type: application/json" \
-d '{"data":{"attributes":{"contact":{},"account":{}}}}'{"error":{"code":"CONFLICT","message":"Lead 65 is already converted.","request_id":"597519a8-6755-40c5-80f0-795def0cdaa5"}}409 CONFLICT — rien n'est créé ni modifié par cet appel. Il n'y a pas de retour en arrière une fois qu'une conversion a réussi : le prospect reste converti, et le contact/compte/affaire qu'elle a produits sont désormais des fiches ordinaires, supprimables et modifiables comme n'importe quelle autre, mais qui ne peuvent pas être refusionnées dans un prospect. Si vous n'êtes pas certain qu'un prospect n'a pas déjà été converti, vérifiez d'abord (GET /api/v1/leads/{id} renvoie toujours le prospect dans tous les cas — la conversion ne supprime pas la fiche, elle ne fait que la marquer) plutôt que de compter sur le fait qu'une nouvelle tentative soit sans danger.
Les deux contrôles de cible requise échouent de la même façon quel que soit le prospect visé, et un prospect qui n'existe pas du tout renvoie un simple 404, pas une erreur de validation :
{"error":{"code":"VALIDATION_ERROR","message":"Validation failed.","request_id":"8fd15e43-3716-4a89-b26e-23c3ad478c54","details":[{"field":"account","code":"REQUIRED","message":"A 'account' object is required."}]}}{"error":{"code":"VALIDATION_ERROR","message":"Validation failed.","request_id":"2c413bee-2ca7-4761-b49d-5525b625b1d7","details":[{"field":"contact","code":"REQUIRED","message":"A 'contact' object is required."}]}}{"error":{"code":"NOT_FOUND","message":"Lead 999999999 not found.","request_id":"b2fcd0e9-cee0-46d3-8f85-7a5268dceaf7"}}422 nommant la clé manquante pour les deux premiers (account/contact, comme à la section 2), 404 pour le prospect inexistant. Aucun de ces trois appels ne crée quoi que ce soit ni ne marque le prospect comme converti — une validation échouée ou un prospect introuvable laisse le prospect exactement tel qu'il était, sûr à retenter avec un corps corrigé.
Erreurs courantes
- Omettre
contactouaccount. Les deux sont requis même quand il n'y a rien à surcharger — envoyez{}, pas une clé manquante. Une clé manquante donne422 VALIDATION_ERROR,REQUIREDsurcontactouaccount(section 8). - Un nom de compte vide à la fois sur la surcharge et sur le prospect. Si le
companydu prospect est vide et que vous ne fournissez pas vous-mêmeaccount.accountname, il n'y a rien à reprendre et aucune valeur par défaut ne s'applique —422suraccount.accountnameREQUIRED, comme pour unPOST /accounts {}nu. - Champs obligatoires manquants sur l'affaire.
potentialest validé comme n'importe quelle autre création dès que vous l'incluez — vérifiezGET /api/v1/modules/potentialspour savoir ce qui est réellement obligatoire plutôt que de le supposer (section 4/5). - Retenter après un
409. Reconvertir un prospect déjà converti ne réussit jamais et ne crée jamais rien de nouveau — vérifiez si le prospect est déjà converti avant de retenter, ne vous contentez pas de renvoyer le même appel. - Supposer que la conversion est réversible. Elle ne l'est pas. Une fois qu'un prospect a été converti avec succès, aucun appel d'API ne permet de retransformer le contact/compte/affaire résultant en prospect.
Updated about 1 month ago
