# 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/](https://prospex.ch/app/api-keys/). Add `prospect:run` if 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:

```bash
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:

```json
{
  "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:

```json
{
  "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](https://prospex.ch/docs/reason-codes/), which is the field to branch on.

## 4. Start the work

Research begins with a cycle, bounded by the project's budget:

```bash
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](https://prospex.ch/docs/webhooks/) 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](https://prospex.ch/docs/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.
