---
title: Batch-create passports
description: "Up to 100 passports per call. Per-item status in the response. Same overage flow as single-create (402 + confirmOverage:true). Idempotency-Key supported."
canonical: "https://www.tracepass.eu/docs/batch-create-passports"
locale: en
source: "https://www.tracepass.eu/docs/batch-create-passports"
---

# Batch-create passports

> Up to 100 passports per call. Per-item status in the response. Same overage flow as single-create (402 + confirmOverage:true). Idempotency-Key supported.

```http
POST /api/v1/passports/batch
```

Create up to 100 passports in one call. Each item carries the same body shape as the single-create endpoint (`{ productId, gs1: { gtin, serialNumber }, parties?, confirmOverage? }`). Partial-success per item — each gets its own status in the response array.

The whole batch consumes N writes upfront against your daily-write budget; if that would overflow, the entire batch returns 429 (no partial billing). The same applies to the DPP overage flow at the batch level — when the DPP quota would be exceeded, the batch returns 402 with `overage_required` and `confirmOverage: true` accepts the overage charge for the whole batch.

Idempotency-Key applies to the whole batch — replaying the same key returns the original full result array. Cap is 100 items per call (matches Stripe's batch ceiling so partial-success responses stay manageable).

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Authorization` | header | string | yes | `Bearer <token>` — either a `tp_` API key (Developer → API Keys; simplest, for server-to-server) or an OAuth 2.0 access token (Developer → OAuth Apps; for user-authorized apps, scoped + revocable). The Authentication page has the full OAuth flow and scope list. |
| `Idempotency-Key` | header | string | no | UUID v4 — applies to the whole batch. |
| `passports` | body | Array<CreatePassportInput> (1-100) | yes | 1–100 passport objects, each in the single-create body shape. |

## Examples

```bash
curl -sS -X POST https://app.tracepass.eu/api/v1/passports/batch \
  -H "Authorization: Bearer tp_REDACTED_xxxxxxxxxxxx" \
  -H "Idempotency-Key: 7b4f1e2c-9a3d-4e5b-8c1a-2d3e4f5a6b7c" \
  -H "Content-Type: application/json" \
  -d '{
    "passports": [
      { "productId": "6650a1b2c3d4e5f6a7b8c9d0", "gs1": { "gtin": "04012345000016", "serialNumber": "BP-48V-100-000001" } },
      { "productId": "6650a1b2c3d4e5f6a7b8c9d0", "gs1": { "gtin": "04012345000016", "serialNumber": "BP-48V-100-000002" } },
      { "productId": "6650a1b2c3d4e5f6a7b8c9d0", "gs1": { "gtin": "04012345000016", "serialNumber": "BP-48V-100-000003" } }
    ]
  }'
```

```typescript
import { randomUUID } from "node:crypto";

const passports = serials.map((serial) => ({
  productId: "6650a1b2c3d4e5f6a7b8c9d0",
  gs1: { gtin: "04012345000016", serialNumber: serial },
}));

const res = await fetch("https://app.tracepass.eu/api/v1/passports/batch", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRACEPASS_API_KEY}`,
    "Idempotency-Key": randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ passports }),
});
const { results, summary } = await res.json();
```

```python
import os, uuid, requests

passports = [
    {"productId": product_id, "gs1": {"gtin": gtin, "serialNumber": s}}
    for s in serials
]

res = requests.post(
    "https://app.tracepass.eu/api/v1/passports/batch",
    headers={
        "Authorization": f"Bearer {os.environ['TRACEPASS_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
        "Content-Type": "application/json",
    },
    json={"passports": passports},
)
res.raise_for_status()
body = res.json()
print(body["summary"])  # {created, errors, total}
```

## Responses

### 200 — Partial success

```json
{
  "results": [
    { "index": 0, "status": "created", "data": { "_id": "...", "gs1": { "...": "..." }, "status": "draft" } },
    { "index": 1, "status": "error", "error": "Serial number already exists for this GTIN" },
    { "index": 2, "status": "created", "data": { "...": "..." } }
  ],
  "summary": { "created": 2, "errors": 1, "total": 3 }
}
```

### 400 — Validation

```json
{ "error": "Validation error", "hint": "Send up to 100 passports per call." }
```

### 402 — Overage required

```json
{
  "error": "overage_required",
  "planLimit": 1000,
  "currentUsage": 950,
  "requested": 100,
  "extraPriceCents": 75,
  "message": "Batch would exceed DPP quota by 50. Retry with { confirmOverage: true } to accept the overage charge."
}
```

### 429 — Rate limit

```json
{ "error": "API rate limit: 200 writes/day via /api/v1. Currently 180 today; requested 25. Retry tomorrow (UTC) or upgrade your plan." }
```

## Related

- [Create a single passport](https://www.tracepass.eu/docs/create-passport.md)
