# Asynchronous Article Updates

The asynchronous article update API allows you to queue screenshot replacements for one or more help center articles in a single request. Jobs are processed in the background via an SQS-backed queue, and you can poll for completion at any time.

This is the recommended way to sync screenshots with your help center. It replaces the legacy synchronous `PUT /helpcenter/article/:id` approach, which could not safely handle multiple image updates to the same article in quick succession.

## Why asynchronous?

When a user clicks "Accept and Sync" on several rows in rapid succession, each update touches the same article on the help center. Synchronous processing caused race conditions - the second update might overwrite the first, or the help center API might reject concurrent writes. The async queue serializes updates per article, automatically delaying overlapping jobs and retrying them after a short cooldown.

For GitHub/Mintlify integrations, asynchronous processing is **required**: every commit on a Mintlify-tracked branch triggers a full redeploy, so updates are coalesced into a single pull request instead of individual commits.

## Supported platforms

| Platform | Integration `platform` | Provider value |
| --- | --- | --- |
| Intercom | `helpcenter` | `intercom` |
| Zendesk | `helpcenter` | `zendesk` |
| Helpjuice | `helpcenter` | `helpjuice` |
| Help Scout | `helpcenter` | `helpscout` |
| Mintlify (via GitHub) | `github` | `mintlify` |

## Create article update jobs

`POST /helpcenter/article/async`

Submits a batch of screenshot replacement jobs. Each job targets a specific article and screenshot. The API validates the request, persists each job to DynamoDB, dispatches messages to the processing queue, and returns immediately with a `202 Accepted`.

### Request

##### Headers

| Header | Required | Description |
| --- | --- | --- |
| `x-api-key` | Yes | Your LaunchBrightly API key |
| `Content-Type` | Yes | `application/json` |

##### Body

```json
{
  "integrationId": "d9e45598-d24d-40d8-baf6-33b6185c61b3",
  "data": [
    {
      "articleId": "8444283",
      "screenshots": [
        {
          "name": "settings-page.png",
          "metadata": {
            "ImageUniqueID": "601eb123-a472-4ffd-ae8c-0f939ae9df3ex"
          },
          "hash": "4d441888f21eceed2443eef4ba9b4e4d6c198f86904c258d476fed10a6b2e555",
          "url": "https://your-bucket.s3.us-east-1.amazonaws.com/your-team/2026-01-15/screenshot-001.png"
        }
      ]
    }
  ]
}
```

### Success Response

##### Code: `202 Accepted`

```json
{
  "articleRequestId": "c3a1f9e2-7b4d-4e8a-9f5c-2d6b8a3e1f7d",
  "jobs": [
    {
      "id": "a1b2c3d4-5e6f-7890-abcd-ef1234567890",
      "status": "pending",
      "createdAt": "2026-02-11T11:01:50.068Z"
    }
  ]
}
```

### Batch request (multiple articles and screenshots)

You can update multiple screenshots across multiple articles in a single request:

##### cURL

```bash
curl --location --request POST 'https://api.launchbrightly.com/helpcenter/article/async' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "integrationId": "d9e45598-d24d-40d8-baf6-33b6185c61b3",
  "data": [
    {
      "articleId": "8444283",
      "screenshots": [
        {
          "metadata": { "ImageUniqueID": "601eb123-a472-4ffd-ae8c-0f939ae9df3ex" },
          "hash": "4d441888f21eceed2443eef4ba9b4e4d6c198f86904c258d476fed10a6b2e555",
          "url": "https://your-bucket.s3.us-east-1.amazonaws.com/your-team/2026-01-15/screenshot-001.png"
        }
      ]
    },
    {
      "articleId": "8444284",
      "screenshots": [
        {
          "metadata": { "ImageUniqueID": "401qb163-d472-5eed-ae2c-0f931ae2d5fe2" },
          "hash": "b6975b10b36df3cc8e41b16a9be8c4f691aa1a2059d3dbcfde31d16fe6d5f65d",
          "url": "https://your-bucket.s3.us-east-1.amazonaws.com/your-team/2026-01-15/screenshot-002.png"
        }
      ]
    }
  ]
}'
```

### Error Responses

##### Validation errors - Code: `422`

When a required field is missing or a constraint is violated, the API returns a `422` with an `errors` array. For example, if `integrationId` is missing:

```json
{
  "errors": [
    "integrationId is required."
  ]
}
```

### Job lifecycle
A job moves through the following statuses:

```plaintext
pending → processing → completed
                     → failed
        → delayed → processing → completed
                               → failed
                   → delayed → delayed → failed (MaxDelayRetryReached)
```

| Status | Description |
| --- | --- |
| `pending` | Job created and queued for processing. |
| `processing` | A worker has picked up the job. |
| `delayed` | Another update for the same article is in flight. The job will auto-retry after ~30 seconds. |
| `completed` | The screenshot was matched and replaced in the live article. |
| `failed` | The job could not complete. Check the `error` field for details.
