Skip to main content

Migration Guide

Delivery API Migration

There have been notable changes to the Delivery API to support multiple couriers per delivery and a new requirement for specifying the delivery provider source. This guide outlines how to handle these changes.

Deadline

January 5th, 2026

To meet the January 5th, 2026 deadline, your integration must be updated to use the new providerSource and providerName arguments when assigning a courier through courierAssign, courierEventCreate, courierImagesCreate, and courierTrackingEventCreate.

Migrating to use courierId for mutations courierEventCreate, courierImagesCreate, courierTrackingEventCreate, and courierUnassign is not required for this deadline but is highly recommended as the next step in your integration upgrade.

Action Required by Deadline

The deliveryServiceProvider argument on courierAssign is now deprecated. It has been replaced by two new fields that must be provided within the courier object itself:

  • providerSource: A required enum (IN_HOUSE or THIRD_PARTY) that specifies who is fulfilling the delivery.

  • providerName: The name of the service provider. This is only necessary/required if providerSource is THIRD_PARTY (e.g., "DoorDash", "Uber Direct").

You must send these new arguments when using courierEventCreate, courierImagesCreate, courierTrackingEventCreate, and courierUnassign.

A Note on Changes

To assist with the January 5th, 2026 deadline, the new providerSource and providerName arguments have also been added to the CourierInput object.

This was done to support integrations that have not yet migrated away from the deprecated inline courier assignment (i.e., you are still passing the courier object to courierEventCreate, courierImagesCreate, courierTrackingEventCreate, and courierUnassign.

This change allows you to pass the new required providerSource and providerName arguments through the deprecated courier argument, enabling you to meet the deadline without immediately refactoring for the Recommended Next Steps.


Examples

Migrating a courierAssign Call

This example shows the specific change required to meet the deadline.

Before

{
"input": {
"courier": {
"id": "your-courier-id",
"firstName": "Jane",
"lastName": "Doe",
"phone": "+16175551234"
},
"deliveryId": "ezcater-delivery-id",
"deliveryServiceProvider": "DoorDash"
}
}

After

{
"input": {
"courier": {
"id": "your-courier-id",
"firstName": "Jane",
"lastName": "Doe",
"phone": "+16175551234",
"providerName": "DoorDash",
"providerSource": "THIRD_PARTY",
},
"deliveryId": "ezcater-delivery-id"
}
}

Note: deliverySericeProvider is removed and providerName and providerSource is added inside the courier object

Meeting the Deadline with courierEventCreate (Deprecated Flow)

{
"input": {
"courier": {
"id": "your-courier-id",
"firstName": "Jane",
"lastName": "Doe",
"phone": "+16175551234",
"providerSource": "IN_HOUSE"
},
"deliveryId": "ezcater-delivery-id",
"eventType": "PICKED_UP",
"occurredAt": "2025-11-01T22:03:03Z"
}
}

While this path provides a bridge to compliance, we strongly recommend prioritizing the migration to the two-step process (only assigning couriers through courierAssign or couriersAssign) as outlined in the Recommended Next Steps.


Recommended Next Steps

Migrating to courierId

This migration is not required for the January 5th, 2026 deadline but is the next step to fully modernize your integration.

Passing the courier object to mutations courierEventCreate, courierImagesCreate, courierTrackingEventCreate, and courierUnassign will not be allowed in the near future. This means a courier must be created and assigned to a delivery before you can reference them in other operations.

New Two-Step Process

Your integration must eventually be updated to follow this two-step process:

  1. Assign Courier(s): Use courierAssign or couriersAssign to create/update and assign the courier(s) to the delivery.

  2. Perform Action: Use the courierId from the prior step to call other mutations.

All courier creation, updates, and assignments are being centralized to courierAssign and couriersAssign.


couriersAssign (The New Standard)

The new couriersAssign mutation is the standard for managing assignments.

Behavior: It accepts a list of CourierAssignmentInput objects.

  • Use Case: Use this to set or overwrite the complete list of couriers. To remove all couriers, pass an empty list.

Assigning Two couriers With couriersAssign

{
"input": {
"couriers": [
{
"id": "courier-id-1",
"firstName": "Jane",
"lastName": "Doe",
"phone": "+16175551234",
"providerSource": "IN_HOUSE"
},
{
"id": "courier-id-2",
"firstName": "John",
"lastName": "Smith",
"phone": "+16175555678",
"providerSource": "THIRD_PARTY",
"providerName": "DoorDash"
}
],
"deliveryId": "ezcater-delivery-id"
}
}


courierAssign (Transition Mutation)

The existing courierAssign mutation is being phased out but has been updated to help you transition.

We've added a new optional boolean argument, allowMultipleCouriers. This is an opt-in flag for new behavior.

  • Legacy Behavior (omitted or false): The mutation replaces all existing couriers with the single courier provided.

  • New Behavior (true): The mutation adds the provided courier to the delivery's existing list of assignments without removing others.

Once your application is ready to support multiple couriers, you should always pass true for allowMultipleCouriers.

Handling New Error Responses

Migrating to the courierId argument introduces stricter validation and new potential errors. These errors will only happen when using the new courierId argument.


Error Cases

Courier Does Not Exist

If the courier for the provided courierId does not exist, the mutation will fail.

{
"errors": [
{
"message": "Courier not found",
"path": [
"courierEventCreate"
],
"extensions": {
"type": "request",
"statusCode": 404,
"serviceName": "delivery-public",
"code": "DOWNSTREAM_SERVICE_ERROR",
"exception": {
"message": "Courier not found",
"locations": [
{
"line": 1,
"column": 72
}
],
"path": [
"courierEventCreate"
]
}
}
}
],
"data": {
"courierEventCreate": null
}
}

Courier Is Not Assigned

If the courier exists but has not been assigned to the specified deliveryId, the mutation will fail.

{
"errors": [
{
"message": "Courier assignment not found",
"path": [
"courierEventCreate"
],
"extensions": {
"type": "request",
"statusCode": 404,
"serviceName": "delivery-public",
"code": "DOWNSTREAM_SERVICE_ERROR",
"exception": {
"message": "Courier assignment not found",
"locations": [
{
"line": 1,
"column": 72
}
],
"path": [
"courierEventCreate"
]
}
}
}
],
"data": {
"courierEventCreate": null
}
}
Did this answer your question?