---
title: "Events: shipments"
description: "When shipment webhooks are sent (creation, update, deletion), what they contain and which cascades trigger them from other objects."
url: https://www.ciklik.academy/en/webhooks/evenements-expeditions/
lang: en
lastUpdated: 2026-10-09
---

# Events: shipments

> Box and PrestaShop
>
> This page applies to both box stores and PrestaShop stores. Shipping slips only exist on box stores.

This page details the three shipment-related event keys: `created_shippingbox`, `updated_shippingbox`, `deleted_shippingbox`. A shipment (“shippingbox”) is a scheduled parcel: a subscription generates one per cycle, and a shop order can generate one directly. For general configuration, see [Understanding a webhook delivery](https://www.ciklik.academy/en/webhooks/comprendre-un-envoi-de-webhook/).

## Shipment object

Every shipment-related delivery carries the full object.

| Field                          | Type          | Nullable | Meaning                                                                                                                   |
| ------------------------------ | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `tenant_id`                    | integer       | no       | owning shop                                                                                                               |
| `id`                           | integer       | no       | internal identifier                                                                                                       |
| `uuid`                         | string        | no       | public identifier                                                                                                         |
| `address`                      | object        | yes      | see [Address object](https://www.ciklik.academy/en/webhooks/evenements-clients-adresses-optins/#address-object)           |
| `transporter`                  | object        | yes      | see [Carrier object](#carrier-object)                                                                                     |
| `created_at`                   | ISO 8601 date | no       | creation                                                                                                                  |
| `updated_at`                   | ISO 8601 date | no       | last modification                                                                                                         |
| `scheduled_at`                 | ISO 8601 date | yes      | scheduled departure                                                                                                       |
| `tracking_link`                | string        | yes      | null without a tracking number (combined with the carrier’s tracking URL) nor a tracking URL set directly on the shipment |
| `subscription_uuid`            | string        | yes      | originating subscription; null for a shop shipment                                                                        |
| `address_id`                   | integer       | yes      | address id                                                                                                                |
| `phone`                        | string        | yes      | recipient phone number                                                                                                    |
| `status`                       | string        | no       | free-form (`created`, `shipped`…), **not** a closed enumeration                                                           |
| `tracking_number`              | string        | yes      | tracking number                                                                                                           |
| `customer_id`                  | string        | yes      | **public** customer id (`cus_...`), **not** the numeric one                                                               |
| `supply_id`                    | string        | yes      | logistics batch                                                                                                           |
| `transporter_id`               | integer       | yes      | carrier id                                                                                                                |
| `first_name`                   | string        | yes      | recipient first name                                                                                                      |
| `last_name`                    | string        | yes      | recipient last name                                                                                                       |
| `postcode`                     | string        | yes      | postal code                                                                                                               |
| `address1`                     | string        | yes      | address                                                                                                                   |
| `address2`                     | string        | yes      | address line 2                                                                                                            |
| `division`                     | string        | yes      | administrative subdivision                                                                                                |
| `city`                         | string        | yes      | city                                                                                                                      |
| `country`                      | string        | yes      | country                                                                                                                   |
| `mail`                         | string        | yes      | customer e-mail at the time of delivery                                                                                   |
| `subscriptions_count`          | string        | yes      | customer’s subscriptions, **as a string**                                                                                 |
| `transporter_name`             | string        | yes      | carrier name                                                                                                              |
| `shipped_count`                | string        | yes      | shipments per cycle, **as a string**                                                                                      |
| `site_name`                    | string        | yes      | shop                                                                                                                      |
| `options`                      | string        | yes      | variant, values separated by `\|`                                                                                         |
| `iso_code`                     | string        | yes      | ISO country code                                                                                                          |
| `relay`                        | object        | yes      | selected pickup point                                                                                                     |
| `relay_id`                     | string        | yes      | pickup point id                                                                                                           |
| `orderable_name`               | string        | yes      | name of the shipped product                                                                                               |
| `orderable_id`                 | string        | yes      | product id, **as a string**                                                                                               |
| `orderable_type`               | string        | yes      | type of shipped product: plan (`App\Plan`) or product (`App\Product`)                                                     |
| `order_id`                     | integer       | yes      | related order                                                                                                             |
| `ref`                          | string        | yes      | product reference                                                                                                         |
| `customization_products`       | array         | yes      | customization choices                                                                                                     |
| `extra_customization_products` | array         | yes      | customizations added afterwards                                                                                           |

## Carrier object

The `transporter` object follows the structure described below. It is null when the shipment has no assigned carrier.

| Field              | Type             | Nullable | Meaning                          |
| ------------------ | ---------------- | -------- | -------------------------------- |
| `id`               | integer          | no       | internal identifier              |
| `countries`        | array of objects | no       | covered countries (`id`, `name`) |
| `plan_blacklisted` | array of objects | no       | excluded plans (`id`, `name`)    |
| `name`             | string           | no       | carrier name                     |
| `description`      | string           | yes      | marketing description            |
| `price`            | number           | no       | price, float                     |
| `gift`             | boolean          | no       | available for a gift card        |
| `active`           | boolean          | no       | carrier is active                |
| `shipped_count`    | integer          | no       | shipments per cycle              |
| `type`             | string           | no       | carrier type                     |
| `relayOptions`     | object           | yes      | see below                        |

`relayOptions` is a **non-contractual structure**: its contents vary with the selected pickup-point carrier (Mondial Relay, Colissimo, DPD) and may change without notice. Do not rely on its individual keys. In the examples on this page it is `null` (no pickup point).

## `created_shippingbox`

Object sent: full shipment. Delay before delivery: none. Full example: in the OpenAPI contract (`/openapi/ciklik-webhooks.yaml`), webhook `created_shippingbox`.

### When it is sent

- Creation or renewal of a subscription (standard generation, including the composable shop).
- Shop order generating a shipment directly, outside any subscription.
- **Anti-churn postponement**: postponing a due date produces an `updated_subscription` followed by **as many `created_shippingbox` as months postponed**. See [Events: subscriptions](https://www.ciklik.academy/en/webhooks/evenements-abonnements/#updated_subscription).

### When it is not sent

No known case: every shipment creation triggers the delivery.

### What changed contains

Always an empty array (`[]`): by definition, a `created_*` has no previous state to compare against.

### Cascading effects

None, beyond its own origin. The anti-churn postponement case is itself a cascading effect of an `updated_subscription`, not the other way round.

### Example

```json
{
    "tenant_id": 1,
    "id": 1,
    "uuid": "c636e863-bdf5-4914-b108-05e117cb0c12",
    "address": {
        "id": 1,
        "user_id": 1,
        "address": "12 rue des Lilas",
        "address1": "Bâtiment B, 3e étage",
        "postcode": "69003",
        "city": "Lyon",
        "phone": "+33612345678",
        "first_name": "Claire",
        "last_name": "Martin",
        "region_id": 1,
        "division": null,
        "division_name": null,
        "deletable": false,
        "company_name": null,
        "country": {
            "id": 1,
            "name": "France",
            "alphaCode": "FR"
        },
        "external_id": 4821
    },
    "transporter": {
        "id": 1,
        "countries": [
            {
                "id": 1,
                "name": "France"
            }
        ],
        "plan_blacklisted": [],
        "name": "Colissimo domicile",
        "description": "Livraison à domicile sous 48h",
        "price": 4.9,
        "gift": false,
        "active": true,
        "shipped_count": 1,
        "type": "subs",
        "relayOptions": null
    },
    "created_at": "2026-09-10T08:15:42.000000Z",
    "updated_at": "2026-09-10T08:15:42.000000Z",
    "scheduled_at": "2026-09-15T00:00:00.000000Z",
    "tracking_link": null,
    "subscription_uuid": "sub_N8PxGUEdS2U7DP",
    "address_id": 1,
    "phone": "+33612345678",
    "status": "created",
    "tracking_number": null,
    "customer_id": "cus_Qx7hR3eaEowcv1DX",
    "supply_id": null,
    "transporter_id": 1,
    "first_name": "Claire",
    "last_name": "Martin",
    "postcode": "69003",
    "address1": "12 rue des Lilas",
    "address2": "Bâtiment B, 3e étage",
    "division": null,
    "city": "Lyon",
    "country": "France",
    "mail": "claire.martin@example.com",
    "subscriptions_count": "1",
    "transporter_name": "Colissimo domicile",
    "shipped_count": "1",
    "site_name": "Boutique Exemple",
    "options": null,
    "iso_code": "fr",
    "relay": null,
    "relay_id": null,
    "orderable_name": "Box mensuelle",
    "orderable_id": "1",
    "orderable_type": "App\\Plan",
    "order_id": 1,
    "ref": "BOX-MENSUELLE",
    "customization_products": [
        {
            "id": 1,
            "quantity": 1
        }
    ],
    "extra_customization_products": null,
    "changed": []
}
```

## `updated_shippingbox`

Object sent: full shipment, in its state at the time of delivery. Delay before delivery: none. Full example: in the OpenAPI contract (`/openapi/ciklik-webhooks.yaml`), webhook `updated_shippingbox`.

### When it is sent

- Direct modification of the shipment (address, status, tracking number…) through the vendors API or from the back office (**Sales > Shipping Slips**).
- Cascade from a modified address, subscription or customer: see “Cascading effects”.

### When it is not sent

- Linking a shipment to its originating order (silent write).
- Adding extra customizations from the internal interface (`extra_customization_products`, silent write).
- Recalculating the `shipped_count` counter or fixing options through an internal maintenance command.

> The transition to “shipped” is not always notified
>
> Changing the status to `shipped` triggers an `updated_shippingbox` when it is made through the vendors API (`POST /deliveries/{id}`, `status` or `tracking_number` field) or through the **Add Tracking Numbers** action of the Site page, with the shipped status option checked. It triggers **none** when it comes from the Wonderweb logistics connector: this is one of the most costly pitfalls for an integrator who would wait for this webhook to notify a customer or update stock on those channels. When in doubt about the origin of a transition to `shipped`, query the API rather than wait for a webhook.

### What changed contains

An object `{column: raw value}`.

> Beware of interpretation
>
> Before delivery, Ciklik resynchronizes from the linked address and subscription the fields `first_name`, `last_name`, `phone`, `postcode`, `address1`, `address2`, `city`, `country`, `mail`, `subscriptions_count`, `transporter_name`, `iso_code`, `relay` and `relay_id`: text fields are rewritten in **uppercase without accents**, regardless of what the caller actually modified. `changed` therefore contains these synchronized fields **in addition to** those modified by the caller, with no way to tell them apart: do not conclude that the customer typed their address in uppercase. A single change may also produce **two** `updated_shippingbox` deliveries for the same shipment, when an internal process saves the same shipment twice.

### Cascading effects

Three origins each produce one `updated_shippingbox` per shipment scheduled since the first day of the month before last (M-2, for example July 1st for a shipment in September), shipments already sent included:

| Origin       | Trigger                                                                    | Scope                                                                 |
| ------------ | -------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Address      | `updated_address`, whatever the modified field                             | every subscription linked to the address                              |
| Subscription | change of address, carrier, variant, pickup point or product customization | the modified subscription                                             |
| Customer     | **change of the customer’s e-mail**                                        | every subscription of the customer, in addition to the `updated_user` |

The e-mail change cascade is established in the code: a customer whose e-mail changes and who has 12 shipments in that window triggers 1 `updated_user` followed by **12 `updated_shippingbox`** (details in [Events: customers, addresses and opt-ins](https://www.ciklik.academy/en/webhooks/evenements-clients-adresses-optins/#updated_user)). A change on the subscription additionally triggers one or two `updated_checkoutorder` per order being created (see [Events: orders, transactions and invoices](https://www.ciklik.academy/en/webhooks/evenements-commandes-transactions-factures/)).

### Example

```json
{
    "changed": {
        "phone": "06 12 34 56 78",
        "first_name": "CLAIRE",
        "last_name": "MARTIN",
        "postcode": "69007",
        "address1": "27 AVENUE JEAN JAURES",
        "address2": "",
        "city": "LYON",
        "country": "FRANCE",
        "mail": "claire.martin-dupont@example.com",
        "status": "shipped",
        "tracking_number": "6A12345678901"
    }
}
```

The rest of the payload is identical to that of `created_shippingbox`. Here, `first_name`, `last_name`, `address1`, `city`, `country`, `phone`, `postcode` and `mail` come from resynchronization; only `status` and `tracking_number` are actually modified by the caller.

## `deleted_shippingbox`

Object sent: full shipment, even after deletion (the state is re-read at the time of delivery, regardless of the deletion). Delay before delivery: none. Full example: in the OpenAPI contract (`/openapi/ciklik-webhooks.yaml`), webhook `deleted_shippingbox`.

### When it is sent

- Deletion through the vendors API, `DELETE /deliveries/{id}`.
- Validation of a withdrawal request (**Validate the withdrawal** action on the order), with the **Delete Shipping Boxes** option: only **future** shipments are deleted.
- Refund of a transaction (**Refund** action on the transaction), with the **Delete Shipping Boxes** option: **all** shipments of the order are deleted, past and future.

### When it is not sent

> Shipments deleted without any delivery
>
> Cancelling a subscription from the back office (**Cancel the subscription** action), with the **Delete future shipments** option, removes them through a bulk write that does not trigger a webhook. No `deleted_shippingbox` is sent in that case: an integrator who synchronizes shipments only through webhooks keeps in their database shipments that no longer exist at Ciklik.

### What changed contains

Always `{"deleted": true}`, whatever the shipment.

### Cascading effects

No cascading effect specific to deletion is documented: it occurs at the end of the journey (validated withdrawal or refund), with no other associated webhook.

### Example

```json
{
    "changed": {
        "deleted": true
    }
}
```

The rest of the payload is identical to that of `created_shippingbox`.

## See also

[Understanding a webhook delivery](https://www.ciklik.academy/en/webhooks/comprendre-un-envoi-de-webhook/)

[Events: subscriptions](https://www.ciklik.academy/en/webhooks/evenements-abonnements/)

[Best practices and troubleshooting](https://www.ciklik.academy/en/webhooks/bonnes-pratiques-et-depannage/)
