---
title: "Batch-create passports (up to 100 per call)."
method: POST
path: "/api/v1/passports/batch"
tags: ["Passports"]
---

# Batch-create passports (up to 100 per call).

`POST /api/v1/passports/batch`

## Request

- Base URL: `https://app.tracepass.eu`
- URL: `https://app.tracepass.eu/api/v1/passports/batch`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://app.tracepass.eu/api/oauth/authorize`, token URL `https://app.tracepass.eu/api/oauth/token`, scopes: `passports:write`)

Create up to 100 passports in one call. Each item carries
the same body shape as the single-create endpoint;
partial-success per item — each gets its own status in the
response array.

The whole batch consumes N writes upfront against the
daily-write budget; if that would overflow, the entire
batch returns 429 (no partial billing). Same applies to
DPP overage 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.

Each item may carry its own `lineage` block (second-life battery
successors). A lineage rule violation fails that item only: its
result has `status: "error"` and `error` starting with the rule code,
e.g. `duplicate_predecessor: …`.

## Headers

- `Idempotency-Key` string

## Request body

- BatchCreatePassportsInput: Top-level `confirmOverage` is the BATCH-LEVEL flag — set it to accept the per-passport overage charge if the entire batch would exceed the workspace's `maxDpps` quota. Wins over any per-item `confirmOverage` (the single-create flag, which is also accepted on each item but only relevant if a single item would exhaust the budget on its own).
  - `passports` CreatePassportInput[], required
    - `productId` string, required: MongoDB ObjectId hex string (24 chars).
    - `identifier` union
      - object: GS1 GTIN + serial number (scheme "gs1"). Required for battery passports.
        - `scheme` 'gs1', required
        - `gtin` string, required: GS1 GTIN with a valid check digit. Accepts 8 digits (GTIN-8), 12 digits (GTIN-12/UPC-A), 13 digits (GTIN-13/EAN-13), or 14 digits (GTIN-14). All forms are left-padded to 14 digits before storage; stored and returned values are always 14 digits.
        - `serialNumber` string, required
        - `digitalLinkUri` string, uri
      - object: ISO/IEC 15459 identifier (scheme "iso15459"). Also valid for battery passports.
        - `scheme` 'iso15459', required
        - `issuingAgencyCode` string, required
        - `primaryId` string, required
        - `serial` string
        - `raw` string: The ISO/IEC 15459 unique identifier: issuing agency code + primary id + serial, concatenated. Always derived by the server from the parts; a value sent on create is ignored. Present on every read.
        - `uri` string, uri: The ISO/IEC 18975 Data-Identifier query-form resolver URL generated by the server, following EN 18219 Table B.12: `https://id.tracepass.eu/?.25P=<IAC><primaryId>&.S=<serial>` (`.S` component omitted when there is no serial; parameter values are percent-encoded). Always derived by the server from the identifier parts; present on every read.
      - object: IEC 61406 Identification Link — an https URI (scheme "iec61406"). Not valid for battery passports (Battery Regulation Art. 77(3) requires gs1 or iso15459).
        - `scheme` 'iec61406', required
        - `uri` string, uri, required
      - object: W3C DID Core identifier (scheme "did"). Not valid for battery passports (Battery Regulation Art. 77(3) requires gs1 or iso15459).
        - `scheme` 'did', required
        - `did` string, required
        - `method` string, required
      - object: Digital Object Identifier — ISO 26324 (scheme "doi"). Stored as bare `10.<registrant>/<suffix>`. Any `https://doi.org/` or `doi:` prefix is stripped on input; the DOI resolves as `https://doi.org/<doi>`. `granularity` is REQUIRED per EN 18219 §5.6.2(b): a DOI product identifier must declare whether it identifies the product model, a production batch, or an individual item. Not valid for battery passports (Battery Regulation Art. 77(3) requires gs1 or iso15459).
        - `scheme` 'doi', required
        - `doi` string, required
        - `granularity` 'model' | 'batch' | 'item', required: Whether the DOI identifies the product model, a production batch, or an individual item (EN 18219 §5.6.2(b)). Must be supplied on create; returned unchanged on read.
    - `gs1` object: Legacy GS1 identifier block. Prefer `identifier` with `scheme: "gs1"` on new integrations.
      - `gtin` string, required: GS1 GTIN with a valid check digit. Accepts 8 digits (GTIN-8), 12 digits (GTIN-12/UPC-A), 13 digits (GTIN-13/EAN-13), or 14 digits (GTIN-14). All forms are left-padded to 14 digits before storage; stored and returned values are always 14 digits.
      - `serialNumber` string, required
    - `parties` PartyMap: Map of role → Party. Each role appears at most once.
    - `lineage` LineageInput: Battery passports only. Links a second-life battery's new passport to the original battery passport(s), as Art. 77(7) of Regulation (EU) 2023/1542 requires. Immutable after create. `batteryStatus` is derived from the triggers (repurposed, remanufactured, …). Rules (422): `lineage_not_applicable` (non-battery), `duplicate_predecessor`, `status_trigger_mismatch` (the product's default `batteryStatus` contradicts the triggers), `predecessor_reason_required` (no predecessors and no reason), `predecessor_not_found`, `invalid_gtin_check_digit`. A second-life `batteryStatus` with no lineage block returns `successor_passport_required`.
      - `predecessors` LineagePredecessorInput[], required
        - `identifier` string: Resolvable identifier of the predecessor passport (http(s) URL, `urn:`, or bare token).
        - `internalPassportId` string: MongoDB ObjectId hex string (24 chars).
        - `trigger` 'preparation_for_reuse' | 'preparation_for_repurposing' | 'repurposing' | 'remanufacturing', required: The Art. 77(7) operation that produced the successor battery.
      - `noPredecessorReason` string: Only with an empty `predecessors` list: why no original passport exists, e.g. a battery placed on the market before 18 Feb 2027.
    - `confirmOverage` boolean: Accept the per-passport overage charge when the plan's `maxDpps` quota is already exhausted. Required only after a 402 response on a previous attempt.
  - `confirmOverage` boolean

## Response `200`

Partial-success batch result.

- BatchPassportsResponse
  - `results` BatchResultItem[], required
    - union
      - object
        - `index` integer, required
        - `status` 'created', required
        - `data` Passport, required
          - `_id` string: MongoDB ObjectId hex string (24 chars).
          - `companyId` string: MongoDB ObjectId hex string (24 chars).
          - `productId` string: MongoDB ObjectId hex string (24 chars).
          - `templateId` string: MongoDB ObjectId hex string (24 chars).
          - `identifier` union
            - object: GS1 GTIN + serial number (scheme "gs1"). Required for battery passports.
              - …
            - object: ISO/IEC 15459 identifier (scheme "iso15459"). Also valid for battery passports.
              - …
            - object: IEC 61406 Identification Link — an https URI (scheme "iec61406"). Not valid for battery passports (Battery Regulation Art. 77(3) requires gs1 or iso15459).
              - …
            - object: W3C DID Core identifier (scheme "did"). Not valid for battery passports (Battery Regulation Art. 77(3) requires gs1 or iso15459).
              - …
            - object: Digital Object Identifier — ISO 26324 (scheme "doi"). Stored as bare `10.<registrant>/<suffix>`. Any `https://doi.org/` or `doi:` prefix is stripped on input; the DOI resolves as `https://doi.org/<doi>`. `granularity` is REQUIRED per EN 18219 §5.6.2(b): a DOI product identifier must declare whether it identifies the product model, a production batch, or an individual item. Not valid for battery passports (Battery Regulation Art. 77(3) requires gs1 or iso15459).
              - …
          - `identifierKey` string: Canonical dedup key in `<scheme>:<parts>` form, e.g. `gs1:00012345678905:SN-001` or `did:did:example:123`. Globally unique (sparse index) — the same identifier cannot exist across different accounts.
          - `gs1` GS1Block
            - `gtin` string, required: GS1 GTIN with a valid check digit. Accepts 8 digits (GTIN-8), 12 digits (GTIN-12/UPC-A), 13 digits (GTIN-13/EAN-13), or 14 digits (GTIN-14). All forms are left-padded to 14 digits before storage; stored and returned values are always 14 digits.
            - `serialNumber` string, required
            - `digitalLinkUri` string, uri
          - `status` 'draft' | 'in_review' | 'approved' | 'published' | 'suspended' | 'expired' | 'archived'
          - `completionPercentage` integer
          - `fieldCounts` object
            - `total` integer
            - `empty` integer
            - `approved` integer
            - `pendingReview` integer
            - `flagged` integer
          - `fields` object
          - `parties` PartyMap: Map of role → Party. Each role appears at most once.
          - `lineage` PassportLineage: The stored, immutable lineage block of a successor battery passport.
            - `predecessors` object[]
              - …
            - `noPredecessorReason` string
          - `dynamicDataAsOf` string, date-time, nullable: `measuredAt` of the newest battery measurement applied to this passport; null before the first one. Returned with `format=full`.
          - `successors` PassportSuccessor[]: Forward links to successor passports created from this one (same account only). Never changes this passport's fields.
            - `passportId` string: MongoDB ObjectId hex string (24 chars).
            - `identifier` string: Canonical resolvable URI of the successor passport.
            - `addedAt` string, date-time
          - `publishedAt` string, date-time
          - `suspendedAt` string, date-time
          - `suspensionReason` string
          - `archivedAt` string, date-time
          - `createdAt` string, date-time
          - `updatedAt` string, date-time
        - `warnings` object[]: Non-blocking findings from the GLEIF check of an LEI the write set (see `upsertParty`). Present only when non-empty. The value was saved; the warning says what GLEIF reports about it.
          - `role` 'manufacturer' | 'importer' | 'authorisedRepresentative' | 'distributor' | 'recycler' | 'producerResponsibilityOrg'
          - `path` string[], required
          - `message` string, required
      - object
        - `index` integer, required
        - `status` 'error', required
        - `error` string, required
  - `summary` BatchSummary, required
    - `created` integer, required
    - `errors` integer, required
    - `total` integer, required

## Other responses

- `400`: Validation error or malformed request.
- `401`: Missing or invalid API key.
- `402`: DPP quota exhausted; retry with `confirmOverage: true` to accept the per-passport charge.
- `403`: Plan-gate or workspace permission denied.
- `422`: Idempotency-Key reused with a different request body. Use a new key for the new request, or reuse the original body.
- `429`: Daily v1 write or passport-read budget exhausted. Resets at 00:00 UTC.

---

[API](https://skmtc.dev/tracepass/apis/tracepass-api.md) · [All operations](https://skmtc.dev/tracepass/apis/tracepass-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tracepass/apis/tracepass-api/revisions/60ddeb25638b?raw)
