# Testing guide

Use mock locker providers to test parcel and locker status flows without a physical locker.
For request contracts and field enums, open the [Mock Service API](#tag/Mock-Service-API).

> **Staging only**
>
> These test tools are available only in staging. You need Carrier Integration API staging access
> and test details that GLS/NXT supplies.

## 1. How the mock works

In staging, some lockers are not physical lockers. They are test lockers that a mock provider simulates.
You recognise a test locker by its ID: it starts with `996633` or `QA`. GLS/NXT gives you the test lockers for your account.

The mock replaces the locker provider. It does not replace the OOH platform.
When the mock fires an event, the event goes through the same platform processing as a real provider event.
Your parcel status changes in the platform, and you receive the same webhooks as in production.

You can use the mock in two ways:

- **Booking with a sequence code** (section 3.1): you send a normal booking, and the mock plays a complete scenario for it. You do not call the mock service.
- **Trigger endpoints** (sections 3.2 and 3.3): you call the mock service to fire one event or one sequence at a time.

## 2. Setup

- **Base URL**: `https://api.staging.glsnxt.com/ooh-mock-service/v1`. This URL is different from the Carrier Integration API base URL.
- **Authentication**: use your regular carrier staging `X-API-Key`. This is the same key that you use for the Carrier Integration API. You do not need a separate mock-service key.
- **Field names**: mock service request bodies use `snake_case` (for example `provider_locker_id`). The Carrier Integration API uses `camelCase` (for example `lockerUid`).
- **Parcel IDs**: start every test parcel ID with `000` and use a new ID for every test. Booking calls reach the mock because of the test locker. Other calls for the parcel, for example a cancellation, reach the mock only when the parcel ID starts with `000`.
- **Asynchronous result**: a `200` response from the mock means only that the mock accepted your request. The mock sends the event a few seconds later. The status change then comes to you through your webhooks.

### 2.1 The values in a trigger request

A parcel trigger identifies the parcel, the locker, the provider and the carrier. A locker trigger has no `parcel_id`; it identifies only the locker, the provider and the carrier.
Take these values from the platform. Do not take them from the examples in this document.

| Trigger field | Value to send | Where to find it |
| --- | --- | --- |
| `carrier_name` | Your own carrier name, for example `KLEINANZEIGEN_DE` | The carrier that owns your `X-API-Key`. GLS/NXT tells you this name with your staging access. |
| `provider_name` | The provider of the test locker, for example `BLOQ` | `provider.name` in `GET /lockers/by-uid` (query with the platform `lockerUid`), or `providerName` in `GET /parcels` |
| `provider_locker_id` | The locker ID on the provider side | `provider.lockerUid` in `GET /lockers/by-uid` (query with the platform `lockerUid`), or `providerLockerId` in `GET /parcels` |
| `parcel_id` (parcel triggers only) | Your parcel ID | For a booked parcel: the `carrierParcelId` of the booking. For a new test parcel: a new ID that starts with `000`. |

> **Send your own carrier name in `carrier_name`**
>
> The mock does not compare `carrier_name` with your API key. If you send a different carrier, or leave the field out, the mock still returns `200`.
> The field is required. If a parcel trigger arrives without it, the mock uses `GLS_NXT`.
> The platform then looks for the parcel and the locker under that other carrier. It does not find them, and it drops the event.
> Your parcel status does not change, and you get no webhook.

### 2.2 Check the result

Wait a few seconds after the `200` response. Then do one of these checks:

- Look for the new status in your Parcel Updates webhooks.
- Call `GET https://api.staging.glsnxt.com/ooh/carrier-connector/v1/parcels?ids=<PARCEL_ID>` and read `shipmentStatus` and `events`.

## 3. What you can do

### 3.1 Book a last-mile parcel with a sequence code

Send a normal last-mile booking through the Carrier Integration API. The mock then plays a complete scenario for the parcel. You do not call the mock service.

1. Send a last-mile booking to `POST https://api.staging.glsnxt.com/ooh/carrier-connector/v1/parcels/data` with your carrier staging `X-API-Key`.
2. Use a new `carrierParcelId` that starts with `000`.
3. Use a test `lockerUid` that GLS/NXT gives you. Its ID starts with `996633` or `QA`.
4. Set `dimensions.depth` to one of the sequence codes below. The code selects the scenario.
5. Follow the status changes in your Parcel Updates webhooks.

```bash
curl --request POST \
  --url https://api.staging.glsnxt.com/ooh/carrier-connector/v1/parcels/data \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <CARRIER_STAGING_API_KEY>' \
  --data '{
    "eventType": "BOOKING",
    "shipmentType": "LAST_MILE",
    "allocationType": "HARD_RESERVATION",
    "carrierParcelId": "000<UNIQUE_PARCEL_ID>",
    "lockerUid": "<GLSNXT_TEST_LOCKER_UID>",
    "dimensions": { "depth": 200, "height": 100, "width": 150 }
  }'
```

#### Sequence codes

| Code | Scenario |
| --- | --- |
| `200` | Normal delivery flow: `COURIER_DELIVERED` then `CONSIGNEE_COLLECTED` |
| `400` | Delivery, followed by consignee collection expiry, then courier pick-up |
| `450` | Booking cancellation: `BOOKING_CANCELLED` |

Any other depth value starts no scenario. The parcel then stays at `BOOKING_CREATED` until you trigger the next event (section 3.3).
Sequence codes work only for test lockers in staging. They are not a feature of the Carrier Integration API, and the trigger endpoints do not use them.

### 3.2 Trigger a first-mile or return sequence

Use [Trigger first-mile sequence](#operation/triggerFirstMileSequence) to run a complete first-mile or return lifecycle in one call.

- Do not send `event_type`. The mock selects the sequence from `provider_name`, `shipment_type` and `labelless`.
- Set `labelless` to `true` only for combinations that GLS/NXT confirms as label-less.

### 3.3 Trigger one parcel or locker event

Use these endpoints to set one specific status.

**First-mile or return event**: call [Trigger first-mile event](#operation/triggerFirstMileEvent) with an `event_type`, for example `CONSIGNEE_DELIVERED`. You do not need a booking first.

**Last-mile event**: call [Trigger last-mile event](#operation/triggerLastMileEvent). You can start with or without a booking:

- **With a booking**: book the parcel through `POST /parcels/data` (the status becomes `BOOKING_CREATED`). Then send `COURIER_DELIVERED` with the same parcel ID.
- **Without a booking**: send `COURIER_DELIVERED` as the first event for a new `parcel_id`. The platform creates the shipment and sets this status in one step. If the first event for a new `parcel_id` is a different event, the platform ignores it.

After `COURIER_DELIVERED`, send the next statuses, for example `CONSIGNEE_COLLECTED` or `CONSIGNEE_COLLECTION_EXPIRED`, for the same parcel.

Example: move a booked parcel into the locker. Replace each placeholder with the values from section 2.1.

```bash
curl --request POST \
  --url https://api.staging.glsnxt.com/ooh-mock-service/v1/parcel/last-mile/event \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <CARRIER_STAGING_API_KEY>' \
  --data '{
    "parcel_id": "<YOUR_CARRIER_PARCEL_ID>",
    "provider_locker_id": "<PROVIDER_LOCKER_ID>",
    "provider_name": "<PROVIDER_NAME>",
    "carrier_name": "<YOUR_CARRIER_NAME>",
    "shipment_type": "LAST_MILE",
    "event_type": "COURIER_DELIVERED"
  }'
```

**Locker event**: call [Trigger locker event](#operation/triggerLockerEvent) to set a test locker to `ACTIVE` or `INACTIVE`.

## 4. Troubleshooting

| What you see | Possible cause | What to do |
| --- | --- | --- |
| `200`, but the parcel status does not change | `carrier_name` is not your own carrier, or it is missing | Send your own carrier name. See section 2.1. |
| `200`, but the parcel status does not change | `provider_name` or `provider_locker_id` does not match the locker of the parcel | Read both values from `GET /parcels` for the parcel. |
| `200`, but the parcel status does not change | The parcel is new, and the first last-mile event is not `COURIER_DELIVERED` | Send `COURIER_DELIVERED` first. |
| `400` with `Invalid provider name` or `unsupported ... provider` | The mock does not simulate this provider for this endpoint | Use a provider from the `provider_name` list of the endpoint. |
| `400` with `provider does not support event type` | The provider cannot send this event | Use a different `event_type`. |
| `401` | The `X-API-Key` is missing, or it is not a staging key | Use your carrier staging key. |

If the status still does not change, send GLS/NXT the parcel ID, the request body and the time of the request.

## 5. Limitations

The mock simulates only the providers, carriers and events in the [Mock Service API](#tag/Mock-Service-API) reference. Not every combination of provider, carrier, shipment type and event is supported. Confirm your combination with GLS/NXT before you test.
The mock does not reproduce every condition of a physical locker or a provider.
