> ## Documentation Index
> Fetch the complete documentation index at: https://code.dcycle.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Classify Purchase Suppliers (v2)

> Give up to 1,000 existing purchase suppliers their activity code and recalculate their purchases, as an ingest job

[← Purchases API](https://code.dcycle.io/api-reference/purchases/overview.md)

Give suppliers you already have their activity code (CNAE or SIC), which picks the spend-based emission factor of
their purchases: the suppliers [Create Purchases (v2)](https://code.dcycle.io/api-reference/purchases/create-v2.md) created `in_progress` from a
`supplier_name` it did not know, the ones created in the app, or one
[Create Purchase Suppliers (v2)](https://code.dcycle.io/api-reference/purchases/suppliers-create-v2.md) rejected with `SUPPLIER_ALREADY_EXISTS`.
The request checks every record, gives each supplier its code at once and answers `202 Accepted` with an
[ingest job](https://code.dcycle.io/api-reference/ingest-jobs/get.md) that recalculates their purchases in the background (see
[how bulk ingestion works](https://code.dcycle.io/api-reference/ingest-jobs/overview.md)). Follow it with
[`GET /v2/ingest-jobs/{id}`](https://code.dcycle.io/api-reference/ingest-jobs/get) or, for a job submitted with an API key, the
[`ingest_job.finished`](https://code.dcycle.io/api-reference/webhooks/overview) webhook.

> [!WARNING]
>
> **Beta.** Part of the bulk ingest API, in beta. The contract may still change before general availability.

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X PATCH "https://api.dcycle.io/v2/purchases/suppliers" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -H "Idempotency-Key: 9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a" \
  -H "Content-Type: application/json" \
  -d '{
    "records": [
      {
        "supplier_id": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
        "code": "1712",
        "framework": "cnae_2009",
        "client_row_id": "SUP-0042"
      }
    ]
  }'
```

```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import os
import uuid

import requests

response = requests.patch(
    "https://api.dcycle.io/v2/purchases/suppliers",
    headers={
        "x-api-key": os.environ["DCYCLE_API_KEY"],
        "x-organization-id": os.environ["DCYCLE_ORG_ID"],
        "Idempotency-Key": str(uuid.uuid4()),  # keep it to retry this same batch
    },
    json={
        "records": [
            {
                "supplier_id": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
                "code": "1712",
                "framework": "cnae_2009",
                "client_row_id": "SUP-0042",
            }
        ]
    },
    timeout=60,
)
response.raise_for_status()
print(response.json()["id"])
```

```json 202 theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "2b1a0f9e-8d7c-4b6a-9f5e-4d3c2b1a0f9e",
  "status": "processing",
  "entity_type": "purchase_suppliers",
  "operation": "update",
  "source": "api_bulk",
  "counts": { "submitted": 1, "succeeded": 0, "failed": 0 },
  "chunks_total": 1,
  "chunks_done": 0,
  "created_at": "2026-10-29T09:20:31.877Z",
  "finished_at": null,
  "links": {
    "self": "/v2/ingest-jobs/2b1a0f9e-8d7c-4b6a-9f5e-4d3c2b1a0f9e",
    "items": "/v2/ingest-jobs/2b1a0f9e-8d7c-4b6a-9f5e-4d3c2b1a0f9e/items"
  }
}
```

```json 422 theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
  "title": "Unprocessable Entity",
  "status": 422,
  "code": "BULK_RECORDS_REJECTED",
  "detail": "1 of the submitted records are invalid; nothing was written.",
  "errors": [
    {
      "source_row_index": 0,
      "client_row_id": "SUP-0042",
      "error_code": "REFERENCE_NOT_FOUND",
      "error_params": { "field": "supplier_id", "value": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c" }
    }
  ],
  "rejected": 1,
  "request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
```

```json 200 (dry_run=true) theme={"theme":{"light":"github-light","dark":"github-dark"}}
{ "dry_run": true, "submitted": 1, "valid": 1 }
```

## How it works

1. **Every record is checked**: its supplier exists and is in your organization's
   [perimeter](https://code.dcycle.io/api-reference/ingest-jobs/overview.md#perimeter), it is not already in the request, and its `code` is an
   active code of its `framework`, as in [Create Purchase Suppliers (v2)](https://code.dcycle.io/api-reference/purchases/suppliers-create-v2.md#activity-codes).
   If any record is invalid the **whole** request is rejected with `422` and nothing is written
   ([all or nothing](https://code.dcycle.io/api-reference/ingest-jobs/overview.md#all-or-nothing)).
2. **Every supplier takes its code at once**, in one transaction: it is `active`, and a classification Dcycle had
   found for it (D\&B) is replaced by yours, as the Data Importer's supplier codes import does. Its name and country do
   not change.
3. **The job recalculates the purchases of each supplier**, in the supplier's own organization: they go back to
   `in_progress`, without emissions, and are calculated again with the factor of the new activity, whatever their
   status was (an `error` one included). A supplier sent with the code it already has is recalculated too, so send
   only the suppliers whose code you want to set or change.
4. **When every chunk is done** the job is `completed` (or `completed_with_errors`). For a job submitted with an API
   key, `ingest_job.finished` is sent with `"operation": "update"` to the webhook endpoints of the `x-organization-id`
   organization.

> [!NOTE]
>
> The job is done when the purchases are queued for their calculation, not when it ends: for a supplier with many
> purchases they can stay `in_progress` for some minutes after the job is `completed`. Read them with
> [List Purchases](https://code.dcycle.io/api-reference/purchases/list.md).

## Request

### Headers

**x-api-key** `string` *required*

Your API key (see [Authentication](https://code.dcycle.io/api-reference/introduction.md#authentication)).

**x-organization-id** `string` *required*

The organization the suppliers are classified for. Its suppliers, and those of the organizations under it that you
can write to (its [perimeter](https://code.dcycle.io/api-reference/ingest-jobs/overview.md#perimeter)), can be classified.

**Idempotency-Key** `string` *required*

1 to 255 characters, one per batch, looked up per organization across every v2 bulk route. Within 24 hours, the
same key with the same route and body returns the original job (with `Idempotent-Replayed: true`); the same key with
another body or on another route is `422 IDEMPOTENCY_KEY_REUSED`, and while the first request is still being
processed `409 IDEMPOTENCY_KEY_IN_PROGRESS`. After 24 hours the key is free, and a request with it is a new one. See
[The Idempotency-Key](https://code.dcycle.io/api-reference/ingest-jobs/overview.md#the-idempotency-key).

### Query Parameters

**dry\_run** `boolean` (default: false)

Check only: the same `422` for invalid records, nothing written, no job; `200` with
`{"dry_run": true, "submitted": n, "valid": n}` when every record is valid. The `Idempotency-Key` header is still
required, but a dry run does not check or store it.

### Body Parameters

**records** `array[object]` *required*

The suppliers to classify, 1 to 1,000. A field not listed here is rejected (`SCHEMA_INVALID`).

**record**

**supplier\_id** `uuid` *required*

The supplier's `id`, as [Create Purchase Suppliers (v2)](https://code.dcycle.io/api-reference/purchases/suppliers-create-v2.md) answers it
or [List Purchase Suppliers](https://code.dcycle.io/api-reference/purchases/suppliers-list.md) lists it.

**code** `string` *required*

The supplier's activity code in `framework`, up to 16 characters (see
[Activity codes](https://code.dcycle.io/api-reference/purchases/suppliers-create-v2.md#activity-codes)).

**framework** `string` *required*

The classification of `code`: `cnae_2009` (CNAE 2009) or `us_sic_v87` (US SIC 1987).

**client\_row\_id** `string`

Your own reference for the record, up to 255 characters, echoed in errors and in the job items.

## Response

`202 Accepted` with the job (`entity_type: purchase_suppliers`, `operation: update`) and a `Location` header to it.
[`GET /v2/ingest-jobs/{id}/items`](https://code.dcycle.io/api-reference/ingest-jobs/list-items) has one item per supplier, in the order sent,
with the supplier's id as `entity_id`; an item is `failed` with `CALCULATION_FAILED` when the supplier was deleted
before the job reached it, or its purchases could not be queued.

## Errors

[Problem details](https://code.dcycle.io/api-reference/errors.md). Per-record codes in `errors[].error_code` of a `422 BULK_RECORDS_REJECTED`:

| `error_code` | Cause |
| - | - |
| `SCHEMA_INVALID` | The record does not match the schema: no `supplier_id` or one that is not a UUID, no `code` or `framework`, a `framework` not listed, an unknown field (e.g. `business_name` or `organization_id`)... `error_params.errors` says where. |
| `REFERENCE_NOT_FOUND` | The supplier does not exist or is outside your organization's [perimeter](https://code.dcycle.io/api-reference/ingest-jobs/overview.md#perimeter), both answer the same (`error_params.field` is `supplier_id`), or `code` is not an active code of `framework` (`code`). |
| `DUPLICATE_SUPPLIER` | Another record of the request has the same `supplier_id`. |

Request-level errors: `401` for a missing or invalid API key, `403 LOGGED_USER_NOT_MEMBER` when the key's user is not a
member of the organization, `422 REQUEST_VALIDATION_FAILED` for a malformed body (no `records`, more than 1,000, no
`Idempotency-Key`), `422 IDEMPOTENCY_KEY_REUSED`, `409 IDEMPOTENCY_KEY_IN_PROGRESS`, and `429` beyond the
[rate limits](https://code.dcycle.io/api-reference/rate-limits.md).

## Limits

| Limit | Value |
| - | - |
| Records per request | 1 to 1,000 |
| Suppliers per recalculation chunk | 100 |

## Related Endpoints

> **[Create Purchase Suppliers (v2)](https://code.dcycle.io/api-reference/purchases/suppliers-create-v2.md)**
>
> Create new suppliers, with their code

> **[List Purchase Suppliers](https://code.dcycle.io/api-reference/purchases/suppliers-list.md)**
>
> Find the ids to classify

> **[Create Purchases (v2)](https://code.dcycle.io/api-reference/purchases/create-v2.md)**
>
> Purchases from these suppliers

> **[Get Ingest Job](https://code.dcycle.io/api-reference/ingest-jobs/get.md)**
>
> Follow the recalculation


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.