# Batch upload

> Creates multiple transactions in a single request (up to 1000 per call).

Página: https://doc.rapidchargeback.com/en/canais/transactions/envio-em-lote/

Creates multiple transactions in a single request (up to 1000 per call).

Use batch upload when you need to sync large volumes (e.g. initial load, reprocessing a whole day). Processing is per transaction: the success of one does not depend on the success of the others.

## Endpoint

```
POST https://api.rapidchargeback.com/api/v1/transactions/batch
```

## Authentication

```
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/json
```

---

## Request body

| Field | Type | Description |
|---|---|---|
| `transactions` | array | List of transactions (min. 1, max. 1000) |

Each array item follows the same schema as [Create transaction](https://doc.rapidchargeback.com/en/canais/transactions/criar-transacao/): the same required, optional and nested fields and validations.

---

## Validations

- The `transactions` array must have between 1 and 1000 items. A problem **in the envelope** (array missing, empty or above 1000) rejects the whole request
- The request body can be up to **5 MB**, which covers 1000 transactions with every field filled in. Above that the response is `413 PAYLOAD_TOO_LARGE` and nothing is created: split it into smaller batches
- Inside the array, **each transaction is validated individually**: invalid field, missing required field, text above the limit, duplicate, nonexistent merchant. All of these become an error for that row
- An error in one row does **not** block the others: the valid ones are created and the response says which ones failed
- A duplicate inside the batch itself (same `external_source` and `external_id` twice) creates the first and fails the second

---

## Request example

```bash
curl -X POST https://api.rapidchargeback.com/api/v1/transactions/batch \
  -H "Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=" \
  -H "Content-Type: application/json" \
  -d '{
    "transactions": [
      {
        "merchant_id": "00000000-0000-0000-0000-000000000001",
        "external_source": "custom",
        "external_id": "TXN-2026-001",
        "transaction_date": "2026-04-01T10:00:00Z",
        "amount": 150.00,
        "currency": "USD",
        "card_last4": "4242",
        "items": [{ "product_description": "Item A", "unit_price": 150.00 }]
      },
      {
        "merchant_id": "00000000-0000-0000-0000-000000000001",
        "external_source": "custom",
        "external_id": "TXN-2026-002",
        "transaction_date": "2026-04-01T11:00:00Z",
        "amount": 200.00,
        "currency": "BRL",
        "card_last4": "1234",
        "items": [{ "product_description": "Item B", "unit_price": 200.00 }]
      }
    ]
  }'
```

---

## Response examples

The batch responds **`200`**, not `201`: in a call that creates some rows and fails others, the status alone does not tell the result. The body does. Always check `failed` and `errors`, never just the HTTP code.

### Mixed results (200)

```json
{
  "data": {
    "created": 1,
    "failed": 1,
    "results": [
      {
        "external_id": "TXN-2026-001",
        "tx_id": "00000000-0000-0000-0000-000000000042",
        "warnings": ["card_bin missing: reduces match accuracy"]
      }
    ],
    "errors": [
      {
        "index": 1,
        "external_id": "TXN-2026-002",
        "status": 409,
        "error": "Transaction already exists"
      }
    ]
  }
}
```

Each item in `results` contains:
- `external_id`: identifies the transaction in your system.
- `tx_id`: UUID generated by Rapid (keep it for future operations).
- `warnings`: notices about missing fields (they do not block creation).

Each item in `errors` contains:
- `index`: position of the row in the array you sent, starting at zero. This is how you find the row when the invalid field is the `external_id` itself.
- `external_id`: identifies which transaction failed, or an empty string if the value sent was not valid.
- `status`: the equivalent HTTP code of the error (`422` validation, `404` nonexistent merchant, `409` duplicate).
- `error`: descriptive message.

`created + failed` is always the total number of rows sent. `results` and `errors` come out in input order.

### All created successfully (200)

```json
{
  "data": {
    "created": 2,
    "failed": 0,
    "results": [
      { "external_id": "TXN-2026-001", "tx_id": "uuid-1", "warnings": [] },
      { "external_id": "TXN-2026-002", "tx_id": "uuid-2", "warnings": [] }
    ],
    "errors": []
  }
}
```

### Row with an invalid field (200)

A row that fails validation does not bring down the others: it shows up in `errors` with `status: 422`.

```json
{
  "data": {
    "created": 1,
    "failed": 1,
    "results": [
      { "external_id": "TXN-2026-001", "tx_id": "uuid-1", "warnings": [] }
    ],
    "errors": [
      {
        "index": 1,
        "external_id": "TXN-2026-002",
        "status": 422,
        "error": "Currency must be 3 uppercase letters (ISO 4217)"
      }
    ]
  }
}
```

### Batch validation error (outside the array)

If the `transactions` array is empty, missing or exceeds 1000 items, the whole request is rejected:

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Array must contain at most 1000 element(s)"
  }
}
```

---

## Batch behaviors worth knowing

- An **unknown** `merchant_ref` **creates the seller** (with `merchant_name`, if sent) and does not return 404.
- A duplicate **inside the same batch** (same `external_source`/`external_id` twice) fails on the second row with `TRANSACTION_DUPLICATE`; the first one is created.
- The order of `results` is the input order.
