Introduction
Welcome to the expedite API! Our platform provides a powerful toolset for integrating with expedite delivery endpoints, allowing you to effortlessly access delivery data and manage batch bookings, updates, and cancellations.
Designed for flexibility and ease of use, the API enables interaction through JSON, making it compatible with any programming language of your choice. Below, you’ll find a detailed overview of the core concepts and data structures that drive the API.
Deliveries
- Deliveries/Orders represent a single delivery order encapsulating either single pickup and single drop-off, single pickup and multiple drop-offs or multiple pickups and single drop-off (NOTE: We do not process multi pickups and multi drop-offs at the moment).
- These deliveries are "requested" via DeliveryEvents sent to our application's webhook endpoint.
- You can retrieve the details of a Delivery by requesting from expedite API described below.
- Additionally, any modifications made to the delivery details should be promptly transmitted to our application's webhook endpoint.
Drivers Integration Overview
- In our system, drivers represent individual members of the fleet. Each driver is uniquely identified by their
fleet_id
, which serves as a primary identifier across all operations.
Assignment and Delivery
- Delivery Assignment: Each delivery is assigned to a single driver. This ensures a streamlined and accountable delivery process.
- Large Orders: For large orders that cannot be fit into a single car, you can request additional drivers via support team. But you will be creating just one single large order on our end
Driver Data Transmission
- Webhooks: We utilize webhooks to send driver-related data to your system in real-time. You are required to provide the necessary webhook endpoints to facilitate this integration.
- Driver JSON Object: Along with the
fleet_id
, we transmit a JSON object containing detailed information about each driver. This object includes essential attributes, ensuring comprehensive data delivery for accurate processing and integration.
Authentication
Setup
We will provide you with an API token and API secret to authenticate the requests you make to our API. These credentials are used to validate the signature of each request, ensuring the security and integrity of the data transmitted.
Token
The request token must be included in the X-expedite-token
header. No additional calculations are required.
Please ensure this token is sent with both GET and POST requests.
Signature
# example in python
import time
import json
import hmac
from hashlib import sha256
data = {"key": "this is example json"}
data_to_post = json.dumps(data)
timestamp = str(int(time.time()))
message = timestamp + "." + data_to_post
headers = {}
signature = hmac.new(bytes("API secret", "utf-8"), msg=bytes(message, "utf-8"), digestmod=sha256,).hexdigest()
headers['X-expedite-signature'] = timestamp + '.' + signature
headers['X-expedite-token'] = 'API token'
// example in javascript
const crypto = require('crypto');
const data = {"key": "this is example json"};
data_to_post = JSON.stringify(data);
const timestamp = Math.floor(Date.now() / 1000).toString();
const message = timestamp + '.' + data_to_post
const headers = {};
const signature = crypto.createHmac('sha256', 'API secret').update(message).digest('hex');
headers['X-expedite-signature'] = timestamp + '.' + signature;
headers['X-expedite-token'] = 'API token';
The request signature will be included in the X-expedite-signature
header. It is calculated as follows:
- The payload is constructed as:
integer_timestamp.request_body
- The payload is hashed using the SHA256 algorithm with the webhook API secret provided to you.
- This signature is required only for POST requests (e.g., quote, create, update, and cancel operations).
If the request_body matches the JSON body of the request then the signature, and therefore request, are valid.
API Request Format
This section outlines the API endpoints, event type identifiers, and the structure of the request payload body.
Type Identifier
Since a single endpoint is used to receive delivery data from delivery partners, requests are distinguished by the event type specified in the X-expedite-Event
header.
Service Areas
- This endpoint allows integrating partner to retrieve the available delivery service areas in which expedite operates.
- Coverage areas will be specified as GeoJson polygons
example of Get servicearea:
> GET: /batch/servicearea
{
"delivery_areas": [
{
"features": [
{
"geometry": {
"coordinates": [
[
[
[
-73.777187,
40.884149
],
[
-73.745227,
40.870206
],
[
-73.715259,
40.871714
]
]
]
],
"type": "MultiPolygon"
},
"properties": {
"name": "New York, NY"
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}
]
}
To retrieve service areas from our system, follow these steps:
- Perform a simple GET request.
- Include only the
X-expedite-token
header. No other headers are necessary. - The response will contain delivery_areas which include all the areas expedite is currently operating in as GeoJsons.
Events
Quotations
example of get_quotation payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string",
"order": {
"subtotal": "float (dollars)",
"tip_cents": "integer (cents)",
"total_items_count": "integer",
"client_name": "string",
"order_fulfillment_method": "string",
"store_id": "string"
},
"tasks": [
{
"type": "pickup",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
}
],
"simulate": "boolean"
}
Event Type Identifier: get_quotation
- Use this identifier to retrieve a delivery quotation.
- The retrieved quotation is valid for 4.5 minutes.
- Deliveries for which quotations are generated cannot be created using the
delivery_created
event.
Accept Quotations
example of accept_quotation payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string"
}
Event Type Identifier: accept_quotation
- Use this event type to accept a delivery quotation generated via the
get_quotation
event. - Include the
external_delivery_id
in the payload. This should correspond to the quotation you intend to accept. - Sending this event for deliveries that have already been created is not supported.
- Quotations cannot be accepted after their expiration time has elapsed.
Ensure compliance with these guidelines to successfully process quotations.
Quotation Process Flow:
Create Delivery
example of delivery_created payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string",
"order": {
"subtotal": "float (dollars)",
"tip_cents": "integer (cents)",
"total_items_count": "integer",
"client_name": "string",
"order_fulfillment_method": "string",
"store_id": "string"
},
"tasks": [
{
"type": "pickup",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
}
],
"simulate": "boolean"
}
Event Type Identifier: delivery_created
- Use this event type to directly create a delivery.
- Ensure that each
external_delivery_id
is unique. Deliveries cannot be created multiple times using the sameexternal_delivery_id
.
Adherence to this requirement ensures proper tracking and avoids duplication.
Creation Process Flow:
Modifications
example of delivery_modified payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string",
"order": {
"subtotal": "float (dollars)",
"tip_cents": "integer (cents)",
"total_items_count": "integer",
"client_name": "string",
"order_fulfillment_method": "string",
"store_id": "string"
},
"tasks": [
{
"type": "pickup",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
}
],
"simulate": "boolean"
}
Event Type Identifier: delivery_modified
- Use this event type to modify an existing delivery.
- Follow the same payload structure as the
delivery_created
event. - The
external_id
at the task level must align with the IDs used in the previousdelivery_created
orget_quotation
requests. - Deliveries that are still in the quotation state are not eligible for modification.
- Address modifications are not allowed in delivery modifications
Ensure these guidelines are followed to successfully modify a delivery.
Modification Process Flow:
Cancellations
example of delivery_cancelled payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string"
}
Event Type Identifier: delivery_cancelled
- Use this event type to cancel a previously created delivery.
- Provide the
external_delivery_id
in the payload to specify the delivery to be canceled. - The
delivery_cancelled
event cancels the entire delivery. - For multi-drop or multi-pick deliveries, task-level cancellations can be handled using the
delivery_modified
event. - A cancellation fee may apply for orders cancelled close to their scheduled delivery time.
- The fee amount will be included in the return payload of a successful cancellation request if any.
- Detailed guidelines for canceling single task/route deliveries are provided below.
Eligibility::
- Deliveries marked as successful are not eligible for cancellation.
- Deliveries still in the quotation stage cannot be canceled.
Cancellation Process Flow:
Get Delivery
example of Get Delivery:
> GET: /batch/deliveries/<external_delivery_id>
{
"external_delivery_id": "string",
"order": {
"subtotal": "float (dollars)",
"gratuity": "float (dollars)",
"wait_time": "float (dollars)",
"tip_cents": "integer (cents)",
"total_items_count": "integer",
"client_name": "string",
"order_fulfillment_method": "string",
"store_id": "string"
},
"tasks": [
{
"type": "pickup",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
],
"job_status": "integer",
"job_state": "string",
"proof_of_delivery": ["Url-1", "Url-2", "..."]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
],
"job_status": "integer",
"job_state": "string",
"proof_of_delivery": ["Url-1", "Url-2", "..."]
}
],
"fleet_id": "integer",
"driver": {
"firstName": "string",
"lastName": "string"
}
}
To retrieve a delivery from our system, follow these steps:
- Perform a simple GET request.
- Include only the
X-expedite-token
header. No other headers are necessary. - Pass the
external_delivery_id
as a path parameter to specify the delivery you want to retrieve. - The response will contain the same structure as the payload returned by the
delivery_created
event, with the addition of:- Task-level statuses
- Driver information (if available)
- Proof of delivery (if available)
This ensures that you receive the updated details for the specified delivery.
Parameter Details
Parameter | Required | Default value | Description |
---|---|---|---|
external_delivery_id | true | id of the delivery | |
subtotal | true | subtotal of the order | |
tip_cents | true | ||
total_items_count | false | 1 | |
client_name | false | name of the client | |
order_fulfillment_method | false | catering | type of fulfillment required for the Delivery. Enum: catering or on-demand |
type | true | type of the task, pickup or dropoff |
|
event_at | true | for either pickup or dropoff at-least one event_at is required | |
timezone_identifier | true | IANA format. Learn more about IANA format | |
location_name | true | ||
recipient_name | false | either location_name or recipient_name is required | |
phone | false | ||
instructions | false | ||
street1 | true | ||
street2 | false | ||
city | true | ||
state | true | ||
zip | true | ||
latitude | true | ||
longitude | true | ||
canceled | false | false | |
external_id | false | ||
items_count | false | 1 | |
simulate | false | can be used to simulate the delivery to its completion according to the task event_at | |
store_id | false | can be used to identify different stores of a partner for the purpose of store level mapping |
Delivery Simulation
- If you pass
simulate
:true
as parameter within json payload of the request, the system will automatically simulate the delivery based on the given pickup/dropoff datetime. - It will go though all the status webhooks and location pings that we will send to you in actual delivery and you can opt for webhooks that are required by your system and ingest them.
simulate
parameter is used exclusively in the sandbox environment to simulate a delivery to completion.- The
simulate
parameter will be ignored in the production environment.
Eligibility:
- This feature only works with single-pick / single-drop deliveries.
Ensure that you are using the sandbox environment when testing delivery simulations.
example of delivery_created/get_quotation (single pick and multiple dropoff) / delivery_modified payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string",
"order": {
"subtotal": "float",
"tip_cents": "integer",
"total_items_count": "integer",
"client_name": "string",
"order_fulfillment_method": "string",
"parcel_size": "string",
"store_id": "string"
},
"tasks": [
{
"type": "pickup",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"ref_images": ["Url-1", "Url-2", "..."],
"items_count": "integer",
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"ref_images": ["Url-1", "Url-2", "..."],
"items_count": "integer",
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string (with country code)",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"canceled": "boolean",
"external_id": "string",
"ref_images": ["Url-1", "Url-2", "..."],
"items_count": "integer",
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
}
]
}
example of delivery_cancelled payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string",
"cancelled_at": "string",
"reason": "string"
}
sample response of a cancelled_delivery
{
"external_delivery_id": "string",
"status": "string",
"message": "string",
"cancellation_fee": "float"
}
example request to fetch the order
> POST: /batch/deliveries/<external_delivery_id>
example of accept_quotation payload:
> POST: /batch/deliveries
{
"external_delivery_id": "string"
}
Webhook Events
To receive task status updates for a specified order, you need to provide an endpoint and an API key. We support two types of webhooks:
- Task Status Updates
- Driver Tracking Event (enabled on a need-basis; please contact support to enable this feature)
Event Type Differentiation
You can differentiate between these two types of webhooks via the Event-Type
header:
order_update
: Used for task status updates.tracking_update
: Used for driver tracking events.
The order_update
event sends the same JSON body as the GET delivery response.
Task Statuses
- We handle one task at a time in each delivery, in chronological order.
- Each webhook response includes the full order details along with an additional parameter named
job_status
, which holds the status of the task. - Task status values range from 0 to 10, with each value representing a specific status. Detailed information on task statuses is provided below.
Status | Value | Description |
---|---|---|
Assigned | 0 | The task has been assigned to a agent. |
Started | 1 | The task has been started and the agent is on the way. |
Successful | 2 | The task has been completed successfully |
Failed | 3 | The task has been completed unsuccessfully. |
InProgress/Arrived | 4 | The task is being performed and the agent has reached the destination of the task. |
Unassigned (default) | 6 | The task has not yet assigned to any agent |
Accepted/Acknowledged | 7 | The task has been accepted by the agent. |
Decline | 8 | The task has been declined by the driver/agent. |
Cancel | 9 | The task has been cancelled. |
Deleted | 10 | The task has been cancelled by the integrtating partner (you). |
Driver Tracking Event
Example data we send
{
"coordinate": {
"latitude": "float",
"longitude": "float"
},
"external_delivery_id": "string",
"timestamp": "ISO8601DateTime"
}
Example response we expect
{
"success": "boolean"
}
Driver tracking is not enabled by default. Please contact us to request activation of this feature.
Parameter | Default | Type | Description |
---|---|---|---|
coordinate | true | object | latitude and longitude of the driver's location |
external_delivery_id | true | string | id of the delivery |
timestamp | true | ISO8601DateTime | timestamp in iso8601 format |
latitude | true | float | latitude of driver's vehicle |
longitude | true | float | longitude of the driver's vehicle |
Scenarios
New Delivery Created
When a new delivery is created, you will send a delivery_created
webhook notification.
We will respond with a 200 status code to confirm that the delivery has been successfully recorded in our system.
New Delivery Quotation
When you request a quote for a delivery, you will send a get_quotation
webhook notification.
We will respond with a 200 status code, along with the quotation data and the quotation’s expiry time.
Accept Quotation
When you decide to accept a quotation provided by our system, you will send an accept_quotation
webhook notification.
We will respond with a 200 status code to confirm that the delivery has been successfully accepted and recorded in our system.
Existing Delivery Modified
If the delivery details are updated by the client, you must send a delivery_modified
webhook notification.
The process is the same as the initial delivery creation, and we will send a 200 status code to acknowledge receipt of the update.
Existing Delivery Cancelled
When a delivery is canceled, you will send a delivery_cancelled
webhook notification.
We will respond with a 200 status code, confirming the cancellation and processing it on our end.
Task/Route Cancelled
{
"external_delivery_id": "string",
"order": {
"subtotal": "float",
"tip_cents": "float",
"total_items_count": "integer",
"store_id": "string"
},
"tasks": [
{
"type": "pickup",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"external_id": "string",
"canceled": false,
"ref_images": ["Url-1", "Url-2", "..."],
"items_count": "integer",
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"external_id": "string",
"canceled": true,
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
},
{
"type": "dropoff",
"event_at": "iso8601",
"timezone_identifier": "iso8601",
"location_name": "string",
"recipient_name": "string",
"phone": "string",
"instructions": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"zip": "string",
"latitude": "float",
"longitude": "float",
"external_id": "string",
"canceled": false,
"items_count": "integer",
"ref_images": ["Url-1", "Url-2", "..."],
"items": [
{
"name": "string",
"count": "int",
"descriptions": "string",
"value": "integer (cents)"
}
]
}
]
}
When a task or route is canceled, you will send a delivery_modified
webhook notification.
We will respond with a 200 status code to confirm receipt and proceed with canceling the task on our end.
For instance, if a delivery consists of three tasks—one pickup and two drop-offs—and you wish to cancel one of the drop-offs, the payload should include the full order details with the canceled
: true
flag set for the specific task you want to cancel (e.g., the first drop-off).
It is important to include the complete order information in the delivery_modified
notification to ensure proper handling of the cancellation.
Response Statuses
Code | Meaning |
---|---|
200 | Request received and being processed. |
209 | Request received but Order Already Exists. |
The API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. |
401 | Unauthorized -- Headers incomplete no Auth. Your API key is wrong, auth failure or Hash mismatch. |
403 | Forbidden -- The requested is Forbidden. |
404 | Not Found -- The specified page could not be found. |
405 | Method Not Allowed -- You tried to access with an invalid method. |
406 | Not Acceptable -- You requested a format that isn't json. |
410 | Gone -- The requested page has been removed from our servers. |
429 | Too Many Requests -- You're requesting too many page! Slow down! |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |