> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://catena.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://catena.ferndocs.com/_mcp/server.

# Async Write Operations

Asynchronous mode is the **default processing mode** for all write operations. When you submit a request, Catena immediately returns a `202 Accepted` response with a resource operation ID, then processes the request in the background with automatic retries and rate limiting.

> **Check**
>
> **Best for production workloads** where you want to create or update multiple resources without waiting for each TSP response. Catena handles retries, rate limiting, and error recovery automatically.

---

## How It Works

```mermaid
sequenceDiagram
    participant You as Your App
    participant Catena as Catena API
    participant TSP as TSP API
    participant WH as Your Webhook

    You->>Catena: POST /v2/telematics/messages
    Catena-->>You: 202 Accepted (resource operation)
    Note over Catena: status: pending
    Catena->>WH: resource_operation.created
    Catena->>TSP: Forward request (with retries)
    alt Success
        TSP-->>Catena: 200 OK
        Catena->>WH: resource_operation.succeeded
        Note over WH: includes resource_id & source_id
    else Failure
        TSP-->>Catena: Error
        Catena->>WH: resource_operation.failed
        Note over WH: includes error logs
    end
```

#### You submit a write request

Send a `POST` or `PATCH` request to the Telematics API with `is_sync=false` (or omit the parameter, since async is the default).

#### Catena returns immediately

You receive a `202 Accepted` response containing a resource operation object with `status: "pending"`. The `id` field is the operation tracking ID.

#### Catena processes in the background

The request is queued and processed with automatic retries and rate limiting to respect TSP API limits.

#### You receive the result via webhook

Catena sends a `resource_operation.succeeded` or `resource_operation.failed` webhook event with the final status and details.

---

## Example: Sending a Message

### Request

**`cURL`**

```bash cURL
curl -X POST 'https://api.catenatelematics.com/v2/telematics/messages' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "connection_id": "019ddd87-eedd-710f-967c-1c6cc72ac985",
    "sender_id": "f9c7ee1c-2e16-5858-9b7e-ff7c89a4dd04",
    "recipient_id": "b224f322-b3d2-57e0-b245-cda313f68a1d",
    "message_text": "Delivery confirmed at warehouse B",
    "priority": "low"
  }'
```

> **Info**
>
> The `sender_id` and `recipient_id` are **Catena user IDs**. Catena automatically resolves them to the TSP-specific identifiers (e.g., `source_sender_id`, `source_recipient_id`) before forwarding the request.

### Response (202 Accepted)

```json
{
  "id": "019df228-725e-7568-aaa8-d0029dffb003",
  "created_at": "2026-05-04T08:43:50.238535Z",
  "updated_at": "2026-05-04T08:43:50.238540Z",
  "deleted_at": null,
  "partner_id": "9df92c50-d8a7-460e-aab2-a93f1de9280a",
  "connection_id": "019ddd87-eedd-710f-967c-1c6cc72ac985",
  "resource": "message",
  "resource_id": null,
  "source_id": null,
  "operation_type": "create",
  "payload": {
    "connection_id": "019ddd87-eedd-710f-967c-1c6cc72ac985",
    "sender_id": "f9c7ee1c-2e16-5858-9b7e-ff7c89a4dd04",
    "recipient_id": "b224f322-b3d2-57e0-b245-cda313f68a1d",
    "message_text": "Delivery confirmed at warehouse B",
    "priority": "low",
    "reply_to_message_id": null,
    "source_sender_id": "51477344",
    "source_recipient_id": "51477717",
    "source_reply_to_message_id": null
  },
  "status": "pending",
  "logs": []
}
```

Key fields in the response:

| Field            | Description                                                                   |
| ---------------- | ----------------------------------------------------------------------------- |
| `id`             | The resource operation ID. Use this to track the operation status.            |
| `status`         | Always `"pending"` for async operations at creation time.                     |
| `resource`       | The type of resource being created (e.g., `message`, `vehicle`).              |
| `operation_type` | Either `"create"` or `"update"`.                                              |
| `resource_id`    | The Catena ID of the created resource. `null` until the operation succeeds.   |
| `source_id`      | The TSP-side ID of the created resource. `null` until the operation succeeds. |
| `payload`        | The full payload sent to the TSP, including auto-resolved source IDs.         |
| `logs`           | Empty initially. Populated with attempt logs if the operation fails.          |

> **Tip**
>
> Notice how the `payload` contains both your Catena IDs (`sender_id`, `recipient_id`) and the automatically resolved TSP IDs (`source_sender_id`, `source_recipient_id`). You don't need to look these up yourself.

---

## Receiving Results via Webhooks

To know whether an async operation succeeded or failed, subscribe to resource operation webhook events.

### Subscribe to Events

Create a webhook subscription for resource operation events:

**`cURL`**

```bash cURL
curl -X POST 'https://api.catenatelematics.com/v2/notifications/webhooks' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://your-domain.com/webhooks/catena",
    "event_name": "resource_operation.*",
    "secret": "your-webhook-secret-min-12-chars"
  }'
```

> **Info**
>
> Using `resource_operation.*` subscribes you to all three events: `created`, `succeeded`, and `failed`. You can also subscribe to individual events if you only need specific notifications.

### Success Webhook Payload

When the operation succeeds, the `resource_operation.succeeded` event includes the `resource_id` (Catena ID) and `source_id` (TSP ID) of the created resource:

```json
{
  "version": "1.0",
  "event_name": "resource_operation.succeeded",
  "webhook_id": "...",
  "timestamp": "2026-05-04T08:43:55.000Z",
  "data": [
    {
      "id": "019df228-725e-7568-aaa8-d0029dffb003",
      "status": "success",
      "resource": "message",
      "resource_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "source_id": "98765432",
      "operation_type": "create",
      "connection_id": "019ddd87-eedd-710f-967c-1c6cc72ac985",
      "payload": { "..." },
      "logs": []
    }
  ]
}
```

### Failure Webhook Payload

When the operation fails, the event includes error logs with details about what went wrong:

```json
{
  "version": "1.0",
  "event_name": "resource_operation.failed",
  "webhook_id": "...",
  "timestamp": "2026-05-04T08:43:55.000Z",
  "data": [
    {
      "id": "019df228-725e-7568-aaa8-d0029dffb003",
      "status": "failed",
      "resource": "message",
      "resource_id": null,
      "source_id": null,
      "operation_type": "create",
      "connection_id": "019ddd87-eedd-710f-967c-1c6cc72ac985",
      "payload": { "..." },
      "logs": [
        {
          "id": "019df22f-093f-7949-908d-d5564941fdbe",
          "created_at": "2026-05-04T08:51:02.079501Z",
          "resource_operation_id": "019df228-725e-7568-aaa8-d0029dffb003",
          "status": "failed",
          "error_type": "auth",
          "error_details": "Client error '401 Unauthorized' for url '...'"
        }
      ]
    }
  ]
}
```

Error types you may encounter:

| Error Type   | Description                                                    |
| ------------ | -------------------------------------------------------------- |
| `auth`       | Authentication failed with the TSP (e.g., expired credentials) |
| `validation` | The TSP rejected the payload (e.g., missing required fields)   |
| `network`    | Network error connecting to the TSP                            |
| `tsp`        | The TSP returned an unexpected error                           |

---

## Polling for Status

If you prefer not to use webhooks, you can poll the operation status using the Integrations API:

**`cURL`**

```bash cURL
curl -X GET 'https://api.catenatelematics.com/v2/integrations/connections/019ddd87-eedd-710f-967c-1c6cc72ac985/resource-operations/019df228-725e-7568-aaa8-d0029dffb003' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```

Or list all recent operations with filtering:

**`cURL`**

```bash cURL
curl -X GET 'https://api.catenatelematics.com/v2/integrations/connections/resource-operations?connection_id=019ddd87-eedd-710f-967c-1c6cc72ac985&resource=message' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```

> **Warning**
>
> Webhooks are the recommended approach for tracking async operations. Polling introduces latency and unnecessary API calls. Reserve polling for debugging or one-off status checks.

---

## When to Use Async Mode

#### Bulk operations

When creating or updating many resources at once (e.g., sending messages to an entire fleet), async mode lets you fire requests rapidly without waiting for each TSP response.

#### Non-blocking workflows

When your application doesn't need to wait for the TSP's response to continue its workflow. For example, dispatching a message where delivery confirmation can arrive later.

#### Production workloads

Async mode provides built-in retries and rate limiting, making it more resilient for production use. Catena manages the complexity of TSP-specific rate limits and transient failures.

> **Warning**
>
> **You must implement webhook handling** to catch failed operations. Without it, you won't know if a request failed on the TSP side. Build controls to listen for `resource_operation.failed` events and resolve issues (e.g., invalid credentials, missing required fields).

---

## Next Steps

#### [Sync Operations](/get-started/writing-data-sync)

Learn about synchronous mode for immediate TSP feedback.