> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voyantcloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulk Upsert Transport Addons

> Create or replace addons for a transport config in a single request.

## Method

`PATCH` `/v1/products/:id/transport/configs/:configId/addons`

## Path Parameters

<ParamField path="id" type="uuid">Product ID that owns the config.</ParamField>
<ParamField path="configId" type="uuid">Transport config ID.</ParamField>

## Body Parameters

<ParamField name="rows" type="array" required>Array of addon definitions to upsert.</ParamField>

<Expandable title="Addon row object">
  <ParamField name="rows[].id" type="uuid">Existing addon ID to replace. Omit to create a new addon.</ParamField>
  <ParamField name="rows[].name" type="string" required>Display name.</ParamField>
  <ParamField name="rows[].pricing" type="object" required>Pricing configuration.</ParamField>
  <ParamField name="rows[].pricing.type" type="string" required>Pricing mode (e.g., `per_pax`, `flat`).</ParamField>
  <ParamField name="rows[].pricing.price" type="number" required>Price amount (major units).</ParamField>
  <ParamField name="rows[].pricing.currency" type="string" required>ISO 4217 currency.</ParamField>
  <ParamField name="rows[].required" type="boolean">Whether the addon is mandatory.</ParamField>
  <ParamField name="rows[].selectable" type="boolean">Whether customers can toggle the addon.</ParamField>
</Expandable>

## Headers

<ParamField header="Authorization" type="string">Bearer token (requires `products:write`).</ParamField>
<ParamField header="content-type" type="string">`application/json`</ParamField>

## Request Example

<RequestExample>
  ```bash cURL theme={null}
  curl -X PATCH "https://api.voyantcloud.com/v1/products/prod_123/transport/configs/cfg_001/addons" \
    -H "Authorization: Bearer $VOYANT_API_KEY" \
    -H "content-type: application/json" \
    -d '{
      "rows": [
        {
          "name": "Extra checked bag (23kg)",
          "pricing": { "type": "per_pax", "price": 40, "currency": "EUR" },
          "required": false,
          "selectable": true
        },
        {
          "id": "addon_002",
          "name": "Priority boarding",
          "pricing": { "type": "per_pax", "price": 25, "currency": "EUR" },
          "required": false,
          "selectable": true
        }
      ]
    }'
  ```

  ```javascript Node.js theme={null}
  await fetch("https://api.voyantcloud.com/v1/products/prod_123/transport/configs/cfg_001/addons", {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${process.env.VOYANT_API_KEY}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      rows: [
        {
          name: "Extra checked bag (23kg)",
          pricing: { type: "per_pax", price: 40, currency: "EUR" },
        },
      ],
    }),
  })
  ```

  ```python Python theme={null}
  import os, requests

  payload = {
    "rows": [
      {
        "name": "Upgrade to Premium Economy",
        "pricing": {"type": "per_pax", "price": 120, "currency": "EUR"},
        "required": False,
        "selectable": True
      }
    ]
  }

  resp = requests.patch(
    "https://api.voyantcloud.com/v1/products/prod_123/transport/configs/cfg_001/addons",
    headers={
      "Authorization": f"Bearer {os.environ['VOYANT_API_KEY']}",
      "content-type": "application/json",
    },
    json=payload,
  )
  result = resp.json()
  ```
</RequestExample>

## Response

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "items": [
      {
        "id": "addon_001",
        "name": "Extra checked bag (23kg)",
        "pricing": { "type": "per_pax", "price": 40, "currency": "EUR" },
        "required": false,
        "selectable": true
      },
      {
        "id": "addon_003",
        "name": "Priority boarding",
        "pricing": { "type": "per_pax", "price": 25, "currency": "EUR" },
        "required": false,
        "selectable": true
      }
    ]
  }
  ```
</ResponseExample>

<Info>
  Rows with an `id` are replaced; rows without an `id` create new addons. The endpoint returns the full set of addons after upsert.
</Info>
