# The async write loop

## The async write loop

```
POST /articles
Authorization: Bearer mrc_live_...
Idempotency-Key: nightly-sync-2026-05-19
Content-Type: application/json
{ "articles": [ ... up to 100,000 rows ... ] }

→  202 Accepted
   { "job_id": "4242", "status_url": "/api/public/v1/jobs/4242" }
```
Then poll:

```
GET /api/public/v1/jobs/4242

→  200 OK
   {
     "job_id": "4242",
     "entity": "ARTICLES",
     "status": "RUNNING",
     "created_at": "2026-05-19T10:00:00Z",
     "updated_at": "2026-05-19T10:00:05Z",
     "total_rows": 12000,
     "created_count": 0,
     "updated_count": 0,
     "skipped_count": 0,
     "deleted_count": 0,
     "error_count": 0,
     "errors": [],
     "error_message": null,
     "result": null
   }
```
…and again a few seconds later:

```
{
   "job_id": "4242",
   "entity": "ARTICLES",
   "status": "COMPLETED",
   "created_at": "2026-05-19T10:00:00Z",
   "updated_at": "2026-05-19T10:00:42Z",
   "total_rows": 12000,
   "created_count": 9000,
   "updated_count": 2950,
   "skipped_count": 0,
   "deleted_count": 0,
   "error_count": 50,
   "errors": [
     { "row_number": 137, "identifier": "LEU-0900-18-830", "error_message": "missing list_price" }
   ],
   "error_message": null,
   "result": null
}
```
If the whole batch is rejected, nothing is written and the job ends
`FAILED` — `error_message` carries the reason. A batch rejected for a
reason outside its rows, such as an unknown tag name, has no per-row
`errors[]`:

```
{
   "job_id": "4243",
   "entity": "ARTICLES",
   "status": "FAILED",
   "created_at": "2026-05-19T10:05:00Z",
   "updated_at": "2026-05-19T10:05:04Z",
   "total_rows": 0,
   "created_count": 0,
   "updated_count": 0,
   "skipped_count": 0,
   "deleted_count": 0,
   "error_count": 0,
   "errors": [],
   "error_message": "Unknown tag name(s): AE, BR. Create them in the Mercura admin UI before assigning them to articles, or send the batch with create_missing_tags: true.",
   "result": null
}
```
When rows themselves are invalid, `errors[]` lists them as well — see
**Rejected rows**.
`result` is `null` for `ARTICLES` / `CUSTOMERS` / `SUPPLIERS` jobs; for
`REQUESTS` jobs (created via `POST /tenders` / `POST /orders`) it carries
`{ request_id, request_status, position_count }`.

Version: 1.79.2

## Description:

  - `The async write loop` ()
    ```
POST /articles
Authorization: Bearer mrc_live_...
Idempotency-Key: nightly-sync-2026-05-19
Content-Type: application/json
{ "articles": [ ... up to 100,000 rows ... ] }

→  202 Accepted
   { "job_id": "4242", "status_url": "/api/public/v1/jobs/4242" }
``` Then poll: ```
GET /api/public/v1/jobs/4242

→  200 OK
   {
     "job_id": "4242",
     "entity": "ARTICLES",
     "status": "RUNNING",
     "created_at": "2026-05-19T10:00:00Z",
     "updated_at": "2026-05-19T10:00:05Z",
     "total_rows": 12000,
     "created_count": 0,
     "updated_count": 0,
     "skipped_count": 0,
     "deleted_count": 0,
     "error_count": 0,
     "errors": [],
     "error_message": null,
     "result": null
   }
``` …and again a few seconds later: ```
{
   "job_id": "4242",
   "entity": "ARTICLES",
   "status": "COMPLETED",
   "created_at": "2026-05-19T10:00:00Z",
   "updated_at": "2026-05-19T10:00:42Z",
   "total_rows": 12000,
   "created_count": 9000,
   "updated_count": 2950,
   "skipped_count": 0,
   "deleted_count": 0,
   "error_count": 50,
   "errors": [
     { "row_number": 137, "identifier": "LEU-0900-18-830", "error_message": "missing list_price" }
   ],
   "error_message": null,
   "result": null
}
``` If the whole batch is rejected, nothing is written and the job ends
`FAILED` — `error_message` carries the reason. A batch rejected for a
reason outside its rows, such as an unknown tag name, has no per-row
`errors[]`: ```
{
   "job_id": "4243",
   "entity": "ARTICLES",
   "status": "FAILED",
   "created_at": "2026-05-19T10:05:00Z",
   "updated_at": "2026-05-19T10:05:04Z",
   "total_rows": 0,
   "created_count": 0,
   "updated_count": 0,
   "skipped_count": 0,
   "deleted_count": 0,
   "error_count": 0,
   "errors": [],
   "error_message": "Unknown tag name(s): AE, BR. Create them in the Mercura admin UI before assigning them to articles, or send the batch with create_missing_tags: true.",
   "result": null
}
``` When rows themselves are invalid, `errors[]` lists them as well — see
**Rejected rows**. `result` is `null` for `ARTICLES` / `CUSTOMERS` / `SUPPLIERS` jobs; for
`REQUESTS` jobs (created via `POST /tenders` / `POST /orders`) it carries
`{ request_id, request_status, position_count }`.

