Send a CRM segment into a project
Post a list of companies at a Prospect project, keep your own row ids on them, and read back which ones Prospex could place.
You have a list in your CRM: a segment, a saved view, a campaign's target accounts. This walks it into a Prospect project, keeps your own row ids attached so the results can go back where they came from, and shows what happens to the rows Prospex cannot place with confidence.
Before you start
- A project, created in the app.
- An API key with
prospect:write, from prospex.ch/app/api-keys/. Addprospect:runif this job will also start the research.
1. Name each company in the strongest way you can
Identity is a ladder, and the highest rung you supply is the one used. Send the best identifier you have, and send the others alongside it as a fallback:
| Field | Rung |
|---|---|
| company_id | A Prospex company id. Exact, and the answer to an earlier ambiguity. |
| uid | The Swiss UID, CHE-123.456.789. Exact, and the best thing a CRM usually holds. |
| crm_reference | A record id from your own mirrored CRM, used only where the mirror already resolved that row to one company. |
| domain | With name. Around one Swiss company in five shares its website with another, so the name is what breaks the tie. |
| name | With canton. The weakest rung, and the one that goes ambiguous most often. |
A lower rung is consulted only when the higher ones were not supplied.
2. Post the batch
Up to 100 companies per request, with an Idempotency-Key so a retry after a timeout cannot add the segment twice:
curl -sS -X POST \
-H "Authorization: Bearer $PROSPEX_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: hubspot-segment-4471-2026-08-21' \
-d @segment.json \
'https://prospex.ch/api/v1/prospect/projects/project_128/prospects'
The body, with your own row ids travelling as external references:
{
"companies": [
{
"uid": "CHE-123.456.789",
"name": "Exemple Fiduciaire SA",
"external_references": [
{"system": "hubspot", "type": "company", "id": "8817342001"}
]
},
{
"domain": "exemple-industrie.ch",
"name": "Exemple Industrie Sàrl",
"external_references": [
{"system": "hubspot", "type": "company", "id": "8817342002"}
]
}
]
}
External references come back unchanged on every read, on the feed and in webhook payloads, so a workflow can write results back to the right CRM record without a mapping table.
3. Read what resolved
One entry per row you sent, in the order you sent them, each carrying its own outcome:
{
"object": "list",
"count": 2,
"resolved": 1,
"data": [
{
"index": 0,
"resolution": {
"status": "resolved",
"method": "uid",
"company": {"id": "company_481203", "name": "Exemple Fiduciaire SA"},
"candidates": [],
"reason_code": "identity_confirmed"
},
"prospect": {"id": "prospect_9912"}
},
{
"index": 1,
"resolution": {
"status": "ambiguous",
"method": "domain",
"company": null,
"candidates": [
{"id": "company_512001", "name": "Exemple Industrie Sàrl"},
{"id": "company_512044", "name": "Exemple Industrie Holding SA"}
],
"reason_code": "identity_ambiguous"
},
"prospect": null
}
]
}
| status | What happened | Do |
|---|---|---|
| resolved | One company, and the prospect exists. | Store the prospect id against your row. |
| ambiguous | Several companies fit. Nothing was created. | Pick from candidates and re-send that row with company_id. Holding structures are the commonest cause. |
| unmatched | The identifier was usable and matched nothing on file. | Try a stronger rung. A company outside the Swiss register will not resolve at all. |
| unusable | No rung was supplied, so there was nothing to look up. | Read detail, which names the combinations that would have worked. |
The response is 201 when at least one prospect was created and 200 when none was, so a batch of nothing but ambiguity is a success with work for you in it. Every reason_code here is one of the reason codes, which is the field to branch on.
4. Start the work
Research begins with a cycle, bounded by the project's budget:
curl -sS -X POST \
-H "Authorization: Bearer $PROSPEX_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: cycle-hubspot-segment-4471' \
-d '{"prospect_ids": ["prospect_9912"]}' \
'https://prospex.ch/api/v1/prospect/projects/project_128/cycles'
A project runs one cycle at a time. Asking for a cycle while one is queued or running answers 200 with that cycle when your request names no new prospects — retrying is safe. It answers 409 cycle_active with the blocking cycle attached when it names others.
5. Get the results back
- Be told. A webhook fires when research lands, when an opener needs approval and when the cycle finishes. The payload is the whole prospect, external references included.
- Or poll. The project feed with
?updated_since=hands you everything that moved since your last pass. - Then write back. Your CRM id is on the row, so a workflow can update the record it came from with no mapping table.
An opener needs a human approval naming the exact revision and its content fingerprint before it counts as released. Prospex does not send email.
A simpler route, if your CRM is connected
A project draws its candidates from a market or a watch, and a watch can be built from your connected HubSpot companies. So the no-code version of this page is: connect the CRM, build a watch from the segment, point the project at that watch. The review step handles the ambiguity the API hands back to you as JSON.
Use the API when the list lives outside the CRM mirror, when a program makes the selection, or when results need to land on a record id in a system Prospex does not know.