---
title: "SOM API: booking with customs declarations"
canonical: "https://ingrid-support.refined.site/space/KB/451641345/SOM%20API%3A%20booking%20with%20customs%20declarations"
format: markdown
---
## What is it?

**SOM API: Booking with Customs Declarations** defines how to include customs declaration data in cross-border shipments booked via the Ingrid SOM API. It covers three supported integration paths depending on how your fulfillment systems are structured, plus a complete field reference for `GeneralCustomsDeclaration` and `GeneralCustomsDeclarationItem`.

Any shipment that crosses a customs border requires a `customs_declaration` object in the booking call. Ingrid does not derive customs data automatically — it must come from your systems.

---

## Which path to use

| Your setup | Recommended path |
| --- | --- |
| You use Ingrid Delivery Checkout and have a `tos_id` | Path 1: TOS ID + inline customs declaration |
| You provide all shipment data directly (no Delivery Checkout) | Path 2: Full API booking + inline customs declaration |
| Customs data comes from a separate system or pipeline step | Path 3: Create shipment → upsert customs → book |

---

## Path 1: TOS ID booking + inline customs declaration

Use when you book shipments using a `tos_id` from a completed Ingrid Delivery Checkout session. Ingrid resolves addresses, shipping method, and line items from the checkout session — but customs data must still be included in every booking call.

```
POST /v1/som/shipments.createAndBook

{
  "tos_id": "{{tos_id}}",
  "customs_declaration": {
    "general_customs_declaration": {
      "contents_type": "SALE_OF_GOODS",
      "contents_explanation": "Clothing",
      "invoice_number": "INV-2024-001",
      "invoice_date": "2024-01-15",
      "incoterms": "DDP",
      "currency": "SEK",
      "seller_identification_numbers": {
        "vat_number": "SE123456789001",
        "eori_number": "SE123456789"
      },
      "items": [
        {
          "description": "Cotton T-shirt",
          "hs_tariff_number": "6109100010",
          "country_of_origin": "CN",
          "quantity": 2,
          "unit_value": 29900,
          "unit_net_weight": 200,
          "unit_gross_weight": 250
        }
      ]
    }
  }
}

```

---

## Path 2: Full API booking + inline customs declaration

Use when you provide the full shipment payload directly — no Delivery Checkout involved. The `customs_declaration` block is identical to Path 1.

```
POST /v1/som/shipments.createAndBook

{
  "shipment": {
    "address_from": { ... },
    "address_to": { ... },
    "parcels": [ ... ]
  },
  "customs_declaration": {
    "general_customs_declaration": {
      "contents_type": "SALE_OF_GOODS",
      "contents_explanation": "Clothing",
      "incoterms": "DDP",
      "currency": "SEK",
      "seller_identification_numbers": {
        "vat_number": "SE123456789001",
        "eori_number": "SE123456789"
      },
      "items": [
        {
          "description": "Cotton T-shirt",
          "hs_tariff_number": "6109100010",
          "country_of_origin": "CN",
          "quantity": 2,
          "unit_value": 29900,
          "unit_net_weight": 200,
          "unit_gross_weight": 250
        }
      ]
    }
  }
}

```

---

## Path 3: Create shipment → upsert customs declaration → book

Use when customs data is produced by a separate system or pipeline step after shipment creation.

**Step 1: Create the shipment**

```
POST /v1/som/shipments.create

{
  "shipment": {
    "address_from": { ... },
    "address_to": { ... },
    "parcels": [ ... ]
  }
}

```

Response includes the `shipment_id` needed for the next steps.

**Step 2: Upsert the customs declaration**

```
POST /v1/som/shipments.upsertCustomsDeclaration

{
  "shipment_id": "{{shipment_id}}",
  "general_customs_declaration": {
    "contents_type": "SALE_OF_GOODS",
    "contents_explanation": "Clothing",
    "incoterms": "DDP",
    "currency": "SEK",
    "seller_identification_numbers": {
      "vat_number": "SE123456789001",
      "eori_number": "SE123456789"
    },
    "items": [
      {
        "description": "Cotton T-shirt",
        "hs_tariff_number": "6109100010",
        "country_of_origin": "CN",
        "quantity": 2,
        "unit_value": 29900,
        "unit_net_weight": 200,
        "unit_gross_weight": 250
      }
    ]
  }
}

```

Calling `upsertCustomsDeclaration` again on the same shipment will replace the existing customs declaration.

**Step 3: Book the shipment**

```
POST /v1/som/shipments.bookParcels

{
  "shipment_id": "{{shipment_id}}"
}

```

Ensure Step 2 completes successfully before calling `bookParcels`.

---

## Reducing payload with booking rules

Many customs declaration fields are the same for every order on a given route — seller tax IDs, incoterms, currency, importer address. With **booking rules**, Ingrid can populate these static fields automatically at booking time based on conditions like origin country.

**What booking rules can auto-populate:**

- `seller_identification_numbers` — VAT, EORI per origin country
- `incoterms` and `place_of_incoterms`
- `currency`
- `sold_to` — importer or customs broker address. **Note**: The `region` field (state/province) is required for: United States, Canada, Australia, China, Brazil, Mexico, Malaysia, New Zealand.
- Carrier-specific metadata

**What you must always send per order:**

- `items[]` — HS tariff number, country of origin, value, net and gross weight per line item
- `contents_type` and `contents_explanation` (unless configured as a static rule)
- `invoice_number` and `invoice_date` (if required by your carrier)

Booking rules are configured by the Ingrid team. Contact your integration manager or [support@ingrid.com](mailto:support@ingrid.com) with your route setup and which fields are static per origin country or warehouse.

---

## Field reference

### GeneralCustomsDeclaration

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `currency` | string | Yes | ISO 4217 currency code (e.g. SEK, EUR, USD) |
| `contents_type` | enum | Yes | SALE_OF_GOODS, GIFT, RETURN, COMMERCIAL_SAMPLE, DOCUMENTS, OTHER, DANGEROUS_GOODS, HUMANITARIAN_DONATIONS |
| `contents_explanation` | string | Yes | Short description of contents (e.g. "Clothing") |
| `incoterms` | enum | Carrier-dependent | DDP, DAP, DDU, EXW, FCA, etc. |
| `invoice_number` | string | Carrier-dependent | Unique invoice identifier |
| `invoice_date` | string | Carrier-dependent | RFC-3339 date when invoice was issued |
| `total_gross_weight` | integer | Carrier-dependent | Total parcel weight in grams including packaging |
| `seller_address` | Address | Carrier-dependent | Exporter address |
| `seller_identification_numbers` | TaxIdentificationNumbers | Carrier-dependent | Seller EORI, VAT, VOEC, IOSS, etc. |
| `sold_to` | Address | Carrier-dependent | Buyer/importer address.  
**Note**: The `region` field (state/province) is required for: United States, Canada, Australia, China, Brazil, Mexico, Malaysia, New Zealand. |
| `buyer_identification_numbers` | TaxIdentificationNumbers | Carrier-dependent | Buyer EORI, VOEC, PCCC, etc. |
| `duties_payer` | Payer | No | Who pays import duties. Defaults to sender |
| `declaration_statement` | string | Carrier-dependent | Legal statement for customs processing |
| `items` | GeneralCustomsDeclarationItem[] | Yes | Line items in the declaration |

### GeneralCustomsDeclarationItem

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Item name |
| `sku` | string | Yes | Product SKU |
| `description` | string | Recommended | Composition or material |
| `hs_tariff_number` | string | Yes | Harmonized System tariff code (6–10 digits) |
| `country_of_origin` | string | Yes | ISO Alpha-2 country code where item was manufactured |
| `quantity` | integer | Yes | Number of units |
| `unit_value` | integer (uint32) | Yes | Value per single unit in smallest currency unit (cents/öre). E.g., €128.25 = `12825`. Do not send decimal values — they will be rejected |
| `unit_net_weight` | integer | Yes | Net weight per unit in grams |
| `unit_gross_weight` | integer | Recommended | Gross weight per unit in grams |
| `brand` | string | No | Item brand |
| `category` | string | No | Commodity category |

---

## FAQ

- **Do I need to send **`customs_declaration`** if I book with a TOS ID?**  
Yes. A TOS ID reduces the shipment data you need to send, but cross-border shipments still require `customs_declaration` in every booking call.
- **What is the difference between Path 1 and Path 2?**  
The `customs_declaration` block is identical in both. The only difference is whether shipment data is resolved from a TOS order (Path 1) or provided directly in the request (Path 2).
- **Does **`upsertCustomsDeclaration`** overwrite existing customs data?**  
Yes — it is an upsert. Calling it again on the same shipment replaces the existing customs declaration.
- **Can I update the customs declaration after booking?**  
No. Once `bookParcels` has been called, the customs declaration cannot be changed. If corrections are needed, contact your carrier directly.
- **Can booking rules fully replace my customs data?**  
No. Booking rules auto-fill static per-route fields, but item-level data (HS codes, values, weights, country of origin) must always come from your systems per order.
- **I'm getting a validation error on **`unit_value`** — what format should I use?**  
`unit_value` is a `uint32` field and must be an integer in the smallest currency unit (cents, öre, pence). For example, €128.25 should be sent as `12825`. Sending a decimal value like `128.25` will be rejected with an `invalid value for uint32 field unitValue` error.
- **Who do I contact to set up booking rules?**  
Contact your Ingrid integration manager or email [support@ingrid.com](mailto:support@ingrid.com) with your route setup and which fields are static per origin country, destination, or carrier product.

---

## Related documentation

- [Migration guide: General Customs Declaration](https://developer.ingrid.com/som/migrations/general-customs-declaration/) — migrating from deprecated declaration types (`cn22`, `cn23`, `cp72`, etc.) to `GeneralCustomsDeclaration`
- [Migration guide: Customs Tax ID](https://developer.ingrid.com/som/migrations/customs-tax-id/) — migrating from string-based tax ID fields to structured `TaxIdentificationNumbers` objects
- [Customs Declarations](https://ingrid-ab.atlassian.net/wiki/spaces/KB/pages/11436337)