Integrate Weels delivery into your platform. Create shipments, check rates, and manage deliveries programmatically.
All API requests require an API token. You can find your token in the Developer tab of your Organization settings.
Include your token in one of two ways:
X-API-Key header
X-API-Key: your_api_token_here
Authorization header (Bearer token)
Authorization: Bearer your_api_token_here
Test mode lets you develop and test your integration against the Weels API using real validation, real zone data, and real pricing — without dispatching shipments or being charged. It uses your same API token and the same endpoints. Shipments are stored in a separate test database so they never mix with live data.
This is useful for:
Toggle test mode on or off from the Developer tab in your Organization settings. When enabled, every API response will include a "test_mode": true field so your code can distinguish sandbox responses from live ones.
| Endpoint | Sandbox Behaviour |
|---|---|
/api/shipment/rates |
Returns real zone rates with your organization’s discounts applied. Zone availability is checked against live data. Response includes "test_mode": true. |
/api/shipment/create |
Runs full validation and real pricing. The shipment is saved to test_tasks (not production). Real shipping labels are generated. No credit is deducted, no dispatch occurs, and no SMS is sent. |
/api/shipment/void |
Voids the test shipment in test_tasks. No credit refund or dispatch cancellation occurs. |
/api/shipment/label |
Returns a real shipping label generated from the test shipment data. All formats (PDF, ZPL, base64) are supported. |
{
"success": true,
"test_mode": true,
"task_id": 47,
"total_price": 10.15,
"tracking_url": "https://www.weels.ca/track/TEST-A1B2C3D4",
"label_pdf": "JVBERi0xLjcK... (base64-encoded PDF)",
"label_zpl": "^XA\\n^PW812\\n... (ZPL code)",
"message": "Test mode: shipment created in test_tasks. No credit charged, no dispatch."
}
"test_mode": true in responses to add conditional logic in your integration — for example, showing a sandbox banner in your UI or logging test shipments separately.
Ship your first package in minutes. Weels supports two shipping modes — choose the one that fits your needs, then follow the steps below.
Same-day / next-day local delivery within Weels service zones. A Weels driver picks up from you and delivers to your customer.
Canada Post & UPS for out-of-zone, long-distance, or international shipments. Labels are generated automatically on creation.
This example walks through the full flow: check rates, create a shipment, and retrieve the label.
# 1. Check rates
curl -X POST https://www.weels.ca/api/shipment/rates \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"postal":"M5V3L9","packages":[{"weight":2,"length":10,"width":8,"height":4,"qty":1}]}'
# 2. Create shipment (use a service code from the rates response)
curl -X POST https://www.weels.ca/api/shipment/create \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destination_name":"Jane Doe",
"destination_phone":"4165551234",
"destination_address":"100 Queen St W",
"destination_city":"Toronto",
"destination_province":"ON",
"destination_postal":"M5H2N2",
"destination_country":"CA",
"packages":[{"weight":2,"length":10,"width":8,"height":4,"qty":1}],
"shipping_method":"canada_post",
"carrier_service_code":"DOM.EP"
}'
# 3. Get label (use task_id from create response)
curl "https://www.weels.ca/api/shipment/label?task_id=12345&format=pdf" \
-H "Authorization: Bearer YOUR_TOKEN"
https://www.weels.ca/api/shipment/rates
Check if delivery is available at a postal code and get pricing. Returns Weels rates for in-zone destinations and, when carrier shipping is enabled, carrier rates from Canada Post and UPS.
weight, width, length, height). For out-of-zone or international destinations where Weels delivery is not available, carrier rates provide an alternative. To create a carrier shipment, pass shipping_method and carrier_service_code to the Create Shipment endpoint. International shipments (destination_country other than CA) require a customs declaration. A default 11 AM ET pickup cutoff applies — delivery estimates are automatically adjusted for orders placed after cutoff.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
postal | string | Yes | — | Destination postal/ZIP code. Spaces are stripped automatically. |
destination_country | string | No | Default: CA |
2-letter ISO country code. Non-CA destinations skip the Weels zone lookup and return only carrier rates. |
age_verification | integer | No | 0 18 19 21 |
Minimum age the recipient must verify upon delivery. 0 = none (default). Any other value adds a $1.00/pkg surcharge. |
signature | boolean | No | true false |
Require the recipient's signature upon delivery. Default: false. Adds a $1.00/pkg surcharge when enabled. |
identity_verification | boolean | No | true false |
Require the driver to scan the recipient’s government ID at the door. Name on ID must match the delivery. Default: false. Adds a $5.00/pkg surcharge. Weels only — carrier rates are excluded when enabled. |
fragile | boolean | No | true false |
Flag the shipment for special handling of delicate/perishable items. A visible *** FRAGILE *** tag is printed on the label. Default: false. Adds a $1.00/pkg surcharge. Weels only — carrier rates are excluded when enabled. |
Packages — repeat with [0], [1], [2]... for multiple parcels | ||||
packages[n][qty] | integer | No | Default: 1 |
Quantity of identical items in this parcel. Combined total across all parcels determines the volume discount tier (5% for 2, 10% for 3, 15% for 4+). |
packages[n][weight] | decimal | No | — | Parcel weight in lbs. Required for carrier rates. |
packages[n][width] | decimal | No | — | Parcel width in inches. Required for carrier rates. |
packages[n][length] | decimal | No | — | Parcel length in inches. Required for carrier rates. |
packages[n][height] | decimal | No | — | Parcel height in inches. Required for carrier rates. |
qty is needed for Weels rate calculation. To also receive carrier rates (Canada Post, UPS), include weight, width, length, and height for at least the first package. Carrier rates are only returned when your organization has carrier shipping enabled. Note: identity_verification and fragile are Weels-only features — when either is enabled, carrier rates are suppressed and only Weels rates are returned.
curl -X POST https://www.weels.ca/api/shipment/rates \ -H "X-API-Key: your_api_token_here" \ -d "postal=L6A1G2" \ -d "packages[0][qty]=1" \ -d "packages[0][weight]=2.5" \ -d "packages[0][width]=12" \ -d "packages[0][length]=10" \ -d "packages[0][height]=6" \ -d "signature=true"
{
"available": true,
"city": "Maple",
"province": "ON",
"delivery_date": "2026-03-02",
"qty": 1,
"rate": {
"base_rate": 8.99,
"surcharges": 1.00,
"discount_pct": 10.00,
"discount_amount": 1.00,
"subtotal": 8.99,
"tax_hst": 1.17,
"total": 10.16
},
"carrier_rates": [
{
"carrier": "canada_post",
"service_code": "DOM.EP",
"service_name": "Canada Post Expedited",
"estimated_days": 2,
"delivery_date": "2026-03-07",
"tracked": true,
"carrier_cost": 9.27,
"subtotal": 11.12,
"tax_hst": 1.45,
"total": 12.57
},
{
"carrier": "ups",
"service_code": "11",
"service_name": "UPS Standard",
"estimated_days": 1,
"delivery_date": "2026-03-06",
"tracked": true,
"carrier_cost": 12.50,
"subtotal": 15.00,
"tax_hst": 1.95,
"total": 16.95
}
]
}
carrier_rates is an empty array when carrier shipping is not enabled for your organization or no package dimensions are provided. The delivery_date reflects an 11 AM ET pickup cutoff — orders placed after 11 AM show the next available date.
{
"available": false,
"postal": "V5K",
"carrier_rates": [
{
"carrier": "canada_post",
"service_code": "DOM.XP",
"service_name": "Canada Post Xpresspost",
"estimated_days": 3,
"delivery_date": "2026-03-08",
"tracked": true,
"carrier_cost": 14.85,
"subtotal": 17.82,
"tax_hst": 2.32,
"total": 20.14
}
]
}
{
"available": false,
"postal": "V5K"
}
| Field | Type | Description |
|---|---|---|
available | boolean | true if the postal code is within the Weels delivery zone. |
city | string | Delivery city (only when available is true). |
province | string | Delivery province (only when available is true). |
delivery_date | string | Earliest available Weels delivery date (YYYY-MM-DD). Accounts for the 11 AM ET cutoff, allowed delivery days, and blackout dates. |
qty | integer | Total parcel quantity used for pricing. |
rate | object | Weels pricing breakdown (only when available is true). |
rate.base_rate | decimal | Zone base rate × quantity (before discounts). |
rate.surcharges | decimal | Total surcharges (age verification, signature, etc.) × quantity. |
rate.discount_pct | decimal | Combined discount percentage (includes volume and organization discounts). |
rate.discount_amount | decimal | Total dollar amount saved from all discounts. |
rate.subtotal | decimal | Amount after all discounts (before tax). |
rate.tax_hst | decimal | HST (13%) on the subtotal. |
rate.total | decimal | Final price including tax. |
| carrier_rates[] — array of carrier shipping options (requires package dimensions) | ||
carrier | string | Carrier identifier: canada_post or ups. |
service_code | string | Carrier service code. Pass this as carrier_service_code when creating a carrier shipment. |
service_name | string | Human-readable service name (e.g. “Canada Post Expedited”, “UPS Standard”). |
estimated_days | integer | Estimated transit days from the carrier. |
delivery_date | string | Estimated delivery date from the carrier (YYYY-MM-DD). Adjusted for the 11 AM ET cutoff. |
tracked | boolean | Whether the shipment includes tracking. |
subtotal | decimal | Rate after markup (pre-tax). |
tax_hst | decimal | HST on the subtotal. |
total | decimal | Total price including tax. This is the amount that will be charged. |
https://www.weels.ca/api/shipment/create
Create a new shipment. The recipient address is automatically verified. If address verification fails, the request is rejected with a descriptive error.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
| Sender (Origin) | ||||
origin_fname | string | Yes | — | Sender first name |
origin_lname | string | Yes | — | Sender last name |
origin_company | string | No | — | Sender company or business name |
origin_phone | string | No | — | Sender phone number (digits only, e.g. 4165551234) |
origin_email | string | No | — | Sender email address |
origin_address1 | string | Yes | — | Sender street address (e.g. 100 King St W) |
origin_address2 | string | No | — | Sender unit, suite, or apartment number |
origin_city | string | Yes | — | Sender city |
origin_province | string | No | Default: ON | Sender province (2-letter code) |
origin_postalcode | string | No | — | Sender postal code |
origin_country | string | No | Default: CA | Sender country code (2-letter ISO) |
| Recipient (Destination) | ||||
destination_fname | string | Yes | — | Recipient first name |
destination_lname | string | Yes | — | Recipient last name |
destination_company | string | No | — | Recipient company or business name |
destination_phone | string | Yes | — | Recipient phone number (digits only, e.g. 4165551234) |
destination_email | string | Yes | — | Recipient email address (used for delivery notifications) |
destination_address1 | string | Yes | — | Recipient street address. Verified automatically for accuracy. |
destination_address2 | string | No | — | Recipient unit, suite, or apartment number |
destination_city | string | Yes | — | Recipient city |
destination_province | string | No | Default: ON | Recipient province (2-letter code) |
destination_postalcode | string | Yes | — | Recipient postal/ZIP code. Must be within Weels delivery zones for Weels shipments; any valid postal for carrier shipments. |
destination_country | string | No | Default: CA | Recipient country code (2-letter ISO). Non-CA destinations require carrier shipping and customs declaration. |
Package Details — repeat with [0], [1], [2]... for multiple parcels | ||||
packages[n][qty] | integer | No | Default: 1 | Quantity of identical items in this parcel. Combined total across all parcels determines volume discount tier. |
packages[n][weight] | decimal | Yes | — | Weight of the parcel in lbs (e.g. 2.5) |
packages[n][width] | decimal | Yes | — | Width of the parcel in inches |
packages[n][length] | decimal | Yes | — | Length of the parcel in inches |
packages[n][height] | decimal | Yes | — | Height of the parcel in inches |
| Shipment Options | ||||
reference | string | No | Max 100 chars | Your internal reference or tracking number. Displayed on the shipment label and included in webhooks. |
order_num | string | No | Max 100 chars | Your order ID from your system (e.g. Shopify order number). |
notes | string | No | Max 500 chars | Special delivery instructions for the courier (e.g. "Leave at side door", "Call on arrival"). |
delivery_date | string | Yes | Format: YYYY-MM-DD | Requested delivery date. Cannot be in the past. Automatically adjusted forward if past the 11 AM ET cutoff, or if the date falls on a non-delivery day or blackout. |
age_verification | integer | No | 0 18 19 21 | Minimum age the recipient must verify at the door. 0 = none (default). Adds a $1.00/pkg surcharge when set. |
signature_required | boolean | No | true false | Require the recipient's signature on delivery. Default: false. Adds a $1.00/pkg surcharge when enabled. |
identity_verification | boolean | No | true false | Require the driver to scan the recipient’s government ID. Name on the ID must match the name on the delivery — if verification fails, the delivery cannot be completed. Default: false. Adds a $5.00/pkg surcharge. Weels only. |
fragile | boolean | No | true false | Flag the shipment for special handling. A prominent *** FRAGILE *** tag is printed on the shipping label. Default: false. Adds a $1.00/pkg surcharge. Weels only. |
| Carrier Shipping — for Canada Post / UPS shipments (optional) | ||||
shipping_method | string | No | weels canada_post ups | Shipping carrier. Default: weels. Carrier shipping must be enabled for your organization. |
carrier_service_code | string | Conditional | — | Required when shipping_method is canada_post or ups. Use the service_code value from the Check Rates carrier_rates response. |
label_size | string | No | 4x6 8.5x11 | Label format for carrier shipments. Default: 4x6 (thermal). |
Customs Declaration — required for international (destination_country ≠ CA) carrier shipments | ||||
customs_items[n][description] | string | Yes* | Max 45 chars | Description of the item (e.g. “Cotton T-Shirt”). At least one item is required for international shipments. |
customs_items[n][quantity] | integer | Yes* | — | Number of units of this item. |
customs_items[n][unit_value] | decimal | Yes* | — | Value per unit in the specified currency. |
customs_items[n][hs_tariff_code] | string | No | — | Harmonized System tariff code for customs classification. |
customs_items[n][origin_country] | string | No | Default: CA | Country of origin for the goods (2-letter ISO). |
customs_currency | string | No | Default: CAD | Currency for customs values. |
customs_reason | string | No | Default: SOG | Reason for export. SOG = Sale of Goods. |
packages[0][...], packages[1][...], etc. Each parcel can have its own quantity and dimensions. Note: identity_verification and fragile require shipping_method to be weels (or omitted). These options are not compatible with carrier shipments.
curl -X POST https://www.weels.ca/api/shipment/create \ -H "X-API-Key: your_api_token_here" \ -d "origin_fname=John" \ -d "origin_lname=Doe" \ -d "origin_address1=100 King St W" \ -d "origin_city=Toronto" \ -d "destination_fname=Jane" \ -d "destination_lname=Smith" \ -d "destination_phone=4165551234" \ -d "[email protected]" \ -d "destination_address1=30 Pamela Crt" \ -d "destination_city=Maple" \ -d "destination_postalcode=L6A1G2" \ -d "packages[0][qty]=1" \ -d "packages[0][weight]=2.5" \ -d "packages[0][width]=12" \ -d "packages[0][length]=10" \ -d "packages[0][height]=6" \ -d "delivery_date=2026-02-15" \ -d "order_num=ORD-12345" \ -d "reference=REF-001"
{
"success": true,
"task_id": 142,
"total_price": 10.15,
"tracking_url": "https://www.weels.ca/track/abc123def",
"label_pdf": "JVBERi0xLjcK... (base64-encoded PDF)",
"label_zpl": "^XA\n^PW812\n... (ZPL code)",
"message": "Shipment created successfully."
}
{
"success": true,
"task_id": 30000712,
"total_price": 16.95,
"tracking_url": "https://www.ups.com/track?tracknum=1Z...",
"tracking_number": "1Z999AA10123456784",
"carrier": "ups",
"service_name": "UPS Standard",
"label_pdf": "JVBERi0xLjcK... (base64-encoded PDF)",
"label_zpl": "",
"message": "Shipment created via UPS Standard."
}
label_pdf (base64-encoded PDF). For Weels shipments, label_zpl is also provided for thermal printers. For carrier shipments, tracking_number, carrier, and service_name are included. Decode the PDF with base64 to save or print it. You can also retrieve labels later via the Get Label endpoint.
400 Validation Error
{
"error": "Recipient first name is required. Recipient postal code is required."
}
400 Address Verification Failed
{
"code": "address_verification_failed",
"error": "The postal code doesn't match the address. Expected: L6A1G3.",
"details": ["The postal code doesn't match the address. Expected: L6A1G3."]
}
402 Insufficient Credit (prepay accounts only)
{
"code": "insufficient_credit",
"error": "Insufficient balance.",
"balance": 5.00,
"required": 10.15,
"shortfall": 5.15
}
https://www.weels.ca/api/shipment/void
Cancel a pending shipment or pickup request that has not yet been picked up. Only shipments with a “Pending” status can be voided. For prepay accounts, the cost is refunded to your credit balance. This endpoint works for both deliveries and scheduled pickups.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
task_id | integer | Yes | — | The Weels shipment ID to void. Returned as task_id in the Create Shipment response. |
curl -X POST https://www.weels.ca/api/shipment/void \ -H "X-API-Key: your_api_token_here" \ -d "task_id=142"
{
"success": true,
"message": "Shipment #142 has been voided.",
"refunded": true,
"refund_amount": 10.15
}
400 Not Voidable
{
"error": "This shipment cannot be voided. Only pending shipments can be voided."
}
404 Not Found
{
"error": "Shipment not found."
}
https://www.weels.ca/api/shipment/label
Retrieve a shipping label for a previously created shipment. Available as a PDF (for standard printers) or ZPL (for Zebra thermal printers).
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
task_id | integer | Yes | — | The Weels shipment ID. |
format | string | No | pdf zpl pdf_base64 | Label format. pdf (default) streams the PDF inline. zpl returns raw ZPL text. pdf_base64 returns JSON with base64-encoded PDF. |
curl -H "X-API-Key: your_api_token_here" \ "https://www.weels.ca/api/shipment/label?task_id=142&format=pdf" \ --output label-142.pdf
curl -H "X-API-Key: your_api_token_here" \ "https://www.weels.ca/api/shipment/label?task_id=142&format=zpl"
Returns the raw PDF binary with Content-Type: application/pdf. Open directly in a browser or save to file.
Returns raw ZPL text with Content-Type: text/plain. Send directly to a Zebra thermal printer.
{
"success": true,
"task_id": 142,
"label_pdf": "JVBERi0xLjcK... (base64-encoded PDF)"
}
https://www.weels.ca/api/shipment/change
Reschedule the delivery date for an active shipment. Only shipments with status 0 (Label Created), 1 (At Sorting Facility), or 2 (With Courier) can be rescheduled. Optionally sends an SMS notification to the recipient.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
task_id | integer | Yes | — | The Weels shipment ID to reschedule. |
delivery_date | string | Yes | Format: YYYY-MM-DD | The new delivery date. |
notify_customer | boolean | No | true false | Send an SMS to the recipient about the date change. Default: false. |
curl -X POST https://www.weels.ca/api/shipment/change \
-H "X-API-Key: your_api_token_here" \
-H "Content-Type: application/json" \
-d '{"task_id": 142, "delivery_date": "2026-03-01", "notify_customer": true}'
{
"success": true,
"task_id": 142,
"delivery_date": "2026-03-01",
"old_date": "2026-02-15",
"message": "Delivery date updated successfully.",
"sms_sent": true
}
400 Not Modifiable
{
"error": "This shipment can no longer be modified. Only pending or in-progress shipments can be rescheduled."
}
404 Not Found
{
"error": "Shipment not found."
}
https://www.weels.ca/api/shipment/update-ref
Update the reference string on an existing shipment. The shipment must belong to your organization.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
id | integer | Yes | — | The Weels shipment ID to update. |
ref | string | Yes | Max 100 chars | The new reference string. |
curl -X POST https://www.weels.ca/api/shipment/update-ref \
-H "X-API-Key: your_api_token_here" \
-H "Content-Type: application/json" \
-d '{"id": 142, "ref": "ORD-20260412-001"}'
{
"success": true,
"task_id": 142,
"reference": "ORD-20260412-001"
}
400 Missing Parameters
{
"error": "Missing id parameter"
}
403 Forbidden
{
"error": "Task does not belong to your organization"
}
404 Not Found
{
"error": "Task not found"
}
https://www.weels.ca/api/shipment/pickup-estimate
Get the estimated cost for a pickup from your organization’s registered address. No task is created — this is a read-only estimate. Pickups are free when your organization has 10 or more pending deliveries.
No fields are required. The API token identifies your organization, and the pickup address is your registered business address on file.
curl -X POST https://www.weels.ca/api/shipment/pickup-estimate \ -H "X-API-Key: your_api_token_here"
{
"covered": true,
"base_rate": 16.00,
"discount_pct": 15,
"discount_amount": 2.40,
"subtotal": 13.60,
"tax_hst": 1.77,
"total": 15.37,
"free_pickup": false,
"pending_deliveries": 4
}
{
"covered": true,
"base_rate": 16.00,
"discount_pct": 15,
"discount_amount": 2.40,
"subtotal": 0.00,
"tax_hst": 0.00,
"total": 0.00,
"free_pickup": true,
"pending_deliveries": 12
}
| Field | Type | Description |
|---|---|---|
covered | boolean | Whether your organization’s address is within the pickup service area. |
base_rate | decimal | Zone base rate for your postal code. |
discount_pct | decimal | Your organization’s discount percentage. |
discount_amount | decimal | Dollar amount of discount applied. |
subtotal | decimal | Amount after discount (before tax). 0.00 if free pickup applies. |
tax_hst | decimal | HST (13%) applied to subtotal. |
total | decimal | Total charge including tax. |
free_pickup | boolean | true if your organization has 10+ pending deliveries (pickup is free). |
pending_deliveries | integer | Number of pending deliveries your organization currently has. |
https://www.weels.ca/api/shipment/pickup-create
Schedule a pickup from your organization’s registered address. A driver will be dispatched to collect your packages on the requested date. Your organization’s address on file is used as the pickup location.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
pickup_date | string | Yes | Format: YYYY-MM-DD | Requested pickup date. Cannot be in the past. |
qty | integer | No | Default: 1 | Estimated number of packages to be picked up. |
reference | string | No | Max 100 chars | Your internal reference number. |
order_num | string | No | Max 100 chars | Your order ID from your system. |
notes | string | No | Max 500 chars | Special instructions for the driver (e.g. “Packages at the back door”, “Ask for reception”). |
Custom Pickup Address — optional. If pickup_address1, pickup_city, and pickup_postalcode are all provided, the pickup will use this address instead of your organization’s registered address. The address must be within the Weels service area. | ||||
pickup_address1 | string | No | — | Pickup street address (e.g. 200 Front St W) |
pickup_address2 | string | No | — | Unit, suite, or loading dock number |
pickup_city | string | No | — | Pickup city |
pickup_province | string | No | Default: org province | Pickup province (2-letter code) |
pickup_postalcode | string | No | — | Pickup postal code. Must be within Weels service area. |
pickup_country | string | No | Default: CA | Pickup country code (2-letter ISO) |
pickup_company | string | No | Default: org name | Company name at the pickup location |
pickup_phone | string | No | Default: org phone | Contact phone at the pickup location |
pickup_email | string | No | Default: org email | Contact email at the pickup location |
pickup_fname | string | No | Default: org contact | Contact first name at the pickup location |
pickup_lname | string | No | Default: org contact | Contact last name at the pickup location |
curl -X POST https://www.weels.ca/api/shipment/pickup-create \ -H "X-API-Key: your_api_token_here" \ -d "pickup_date=2026-03-02" \ -d "qty=5" \ -d "notes=Packages at the loading dock"
{
"success": true,
"task_id": 287,
"pricing": {
"base_rate": 16.00,
"discount_pct": 15,
"discount": 2.40,
"subtotal": 13.60,
"tax_hst": 1.77,
"total": 15.37,
"free_pickup": false
},
"message": "Pickup request created."
}
{
"success": true,
"task_id": 288,
"pricing": {
"base_rate": 16.00,
"discount_pct": 15,
"discount": 2.40,
"subtotal": 0.00,
"tax_hst": 0.00,
"total": 0.00,
"free_pickup": true
},
"message": "Pickup request created (free — 12 pending deliveries)."
}
400 Validation Error
{
"error": "Pickup date is required."
}
400 No Address
{
"error": "Your organization does not have a complete address on file. Please contact support."
}
402 Insufficient Credit (prepay accounts, non-free pickup)
{
"code": "insufficient_credit",
"error": "Insufficient balance.",
"balance": 5.00,
"required": 15.37,
"shortfall": 10.37
}
task_id.
https://www.weels.ca/api/shipment/carrier-pickup-estimate
Get a price estimate for an on-demand carrier pickup (Canada Post or UPS) at your organization’s address. This does not schedule the pickup — use Schedule Carrier Pickup to confirm.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
carrier | string | Yes | canada_post, ups | Which carrier to request a pickup from |
pickup_date | string | No | YYYY-MM-DD | Requested pickup date. Defaults to today. |
ready_time | string | No | HH:MM (24h) | Earliest time packages are ready. Defaults to your organization’s pickup window start or 09:00. |
close_time | string | No | HH:MM (24h) | Latest time the carrier can pick up. Defaults to your organization’s pickup window end or 17:00. |
curl -X POST https://www.weels.ca/api/shipment/carrier-pickup-estimate \
-H "X-API-Key: your_api_token_here" \
-H "Content-Type: application/json" \
-d '{"carrier": "ups", "pickup_date": "2026-04-15"}'
{
"success": true,
"carrier": "ups",
"carrier_cost": 6.50,
"markup_pct": 5,
"markup_amount": 0.33,
"subtotal": 6.83,
"tax_hst": 0.89,
"total": 7.72,
"pending_packages": 3,
"existing_pickup": null
}
| Field | Type | Description |
|---|---|---|
carrier | string | The carrier quoted (canada_post or ups) |
carrier_cost | number | Base cost charged by the carrier |
markup_pct | number | Your organization’s markup percentage |
markup_amount | number | Dollar amount of markup applied |
subtotal | number | Pre-tax total (carrier cost + markup) |
tax_hst | number | HST charged |
total | number | Total amount that will be charged |
pending_packages | integer | Number of pending carrier shipments awaiting pickup |
existing_pickup | object|null | If a pickup is already scheduled for this date, returns task_id and confirmation |
https://www.weels.ca/api/shipment/carrier-pickup-create
Schedule an on-demand carrier pickup (Canada Post or UPS) at your organization’s registered address. The carrier will dispatch a driver to collect your packages. Your prepay balance is charged immediately.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
carrier | string | Yes | canada_post, ups | Which carrier to request a pickup from |
pickup_date | string | Yes | YYYY-MM-DD | Requested pickup date (today or future business day) |
ready_time | string | No | HH:MM (24h) | Earliest time packages are ready. Defaults to your organization’s pickup window or 09:00. |
close_time | string | No | HH:MM (24h) | Latest time the carrier can pick up. Defaults to your organization’s pickup window or 17:00. |
pickup_location | string | No | — | Specific location at the address (e.g. “Loading dock”, “Front desk”) |
instructions | string | No | — | Special instructions for the carrier driver |
notes | string | No | — | Internal notes (stored on the pickup task) |
curl -X POST https://www.weels.ca/api/shipment/carrier-pickup-create \
-H "X-API-Key: your_api_token_here" \
-H "Content-Type: application/json" \
-d '{"carrier": "ups", "pickup_date": "2026-04-15", "pickup_location": "Loading dock", "instructions": "Ring buzzer #3"}'
{
"success": true,
"task_id": 30004012,
"carrier_pickup_id": "WLP3E843243",
"pricing": {
"carrier_cost": 6.50,
"markup_pct": 5,
"markup_amount": 0.33,
"subtotal": 6.83,
"tax_hst": 0.89,
"total": 7.72
},
"message": "UPS pickup scheduled for 2026-04-15."
}
400 Validation Error
{
"success": false,
"error": "Valid carrier is required (canada_post or ups)."
}
422 No Pending Packages
{
"success": false,
"error": "No pending carrier deliveries found for pickup."
}
402 Insufficient Credit
{
"success": false,
"code": "insufficient_credit",
"error": "Insufficient balance.",
"balance": 2.50,
"required": 7.72,
"shortfall": 5.22
}
https://www.weels.ca/api/shipment/carrier-pickup-cancel
Cancel a previously scheduled carrier pickup. The carrier’s API is called to cancel the pickup, the task status is updated, and prepay accounts receive a refund to their credit balance.
| Field | Type | Required | Description |
|---|---|---|---|
task_id | integer | Yes | The pickup task ID returned from Schedule Carrier Pickup |
curl -X POST https://www.weels.ca/api/shipment/carrier-pickup-cancel \
-H "X-API-Key: your_api_token_here" \
-H "Content-Type: application/json" \
-d '{"task_id": 30004012}'
{
"success": true,
"message": "Carrier pickup cancelled.",
"refund": 7.72
}
| Field | Type | Description |
|---|---|---|
message | string | Confirmation message |
refund | number | Amount refunded to your credit balance (prepay accounts only) |
400 Missing Fields
{
"success": false,
"error": "vendor_id and task_id are required."
}
404 Not Found
{
"success": false,
"error": "Pickup task not found or does not belong to this vendor."
}
https://www.weels.ca/api/drivers/{mm/dd/yyyy}
List all delivery buckets (route groups) and their packages for a specific delivery date. Each bucket shows the assigned driver, if any. Only includes shipments with status 0, 1, or 2 (active, pre-delivery). If no date is provided, defaults to today.
| Parameter | Type | Required | Description |
|---|---|---|---|
{mm/dd/yyyy} | string | No | Delivery date in mm/dd/yyyy format. Defaults to today if omitted. |
curl -H "X-API-Key: your_api_token_here" \ "https://www.weels.ca/api/drivers/02/18/2026"
{
"buckets": [
{
"bucket_id": 12,
"label": "Markham North",
"status": "claimed",
"driver": "John Smith",
"packages": [
{
"reference": "REF-001",
"shipment_id": 142,
"status": 1,
"confirmed": 0,
"order_num": "ORD-12345",
"name": "Jane Doe"
}
]
},
{
"bucket_id": 13,
"label": "Scarborough East",
"status": "published",
"driver": null,
"packages": [
{
"reference": "REF-002",
"shipment_id": 143,
"status": 0,
"confirmed": 0,
"order_num": "ORD-12346",
"name": "Bob Wilson"
}
]
},
{
"bucket_id": null,
"label": "Unbucketed",
"status": null,
"driver": null,
"packages": [
{
"reference": "REF-003",
"shipment_id": 144,
"status": 0,
"confirmed": 0,
"order_num": "ORD-12347",
"name": "Alice Chen"
}
]
}
]
}
| Field | Type | Description |
|---|---|---|
bucket_id | integer|null | The delivery bucket ID, or null for shipments not yet assigned to a bucket. |
label | string | The bucket name (e.g. "Markham North"). "Unbucketed" for unassigned shipments. |
status | string|null | Bucket lifecycle status: draft, published, claimed, in_progress, completed, or cancelled. null for unbucketed shipments. |
driver | string|null | Full name of the driver assigned to this bucket, or null if unclaimed. |
packages[].reference | string | Your reference/tracking number. |
packages[].shipment_id | integer | Weels shipment ID. |
packages[].status | integer | Numeric shipment status (see Shipment Statuses). |
packages[].confirmed | integer | 1 if the delivery has been completed, 0 otherwise. |
packages[].order_num | string | Your order number. |
packages[].name | string | Recipient full name. |
"Unbucketed" entry at the end. The driver field shows who has claimed the bucket — it is null until a driver claims it.
https://www.weels.ca/api/cities
Returns a list of distinct city names within the Weels delivery network. This endpoint is public and does not require authentication.
curl "https://www.weels.ca/api/cities"
[
{ "name": "Ajax" },
{ "name": "Aurora" },
{ "name": "Brampton" },
{ "name": "Etobicoke" },
{ "name": "Maple" },
{ "name": "Markham" },
{ "name": "Mississauga" },
{ "name": "Toronto" }
]
https://www.weels.ca/api/days
Returns the available delivery days for a postal code. Uses longest-prefix matching to find the most specific zone. This endpoint is public and does not require authentication.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
postal | string | Yes | — | Canadian postal code (at least the 3-character FSA). Spaces and special characters are stripped automatically. |
curl "https://www.weels.ca/api/days?postal=L6A1G2"
{
"success": true,
"covered": true,
"days": ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday"],
"dday": "Saturday,Sunday,Monday,Tuesday,Wednesday"
}
{
"success": false,
"covered": false
}
400 Invalid Postal Code
{
"error": "Postal code must be at least 3 characters."
}
days array contains full day names. The dday field provides the same data as a comma-separated string for convenience. If a zone is found but has no delivery days configured, defaults to Saturday through Wednesday.
https://www.weels.ca/api/blackouts
Returns all active, future blackout dates — days when deliveries are not available, labels cannot be created, and rate ETAs are adjusted. Each entry includes a preferred date (the next available delivery day after the blackout) for use in scheduling.
curl -H "X-API-Key: your_api_token_here" \ "https://www.weels.ca/api/blackouts"
{
"success": true,
"blackouts": [
{
"date": "2026-04-03",
"description": "Good Friday",
"recurring": 0,
"preferred": "2026-04-04"
},
{
"date": "2026-07-01",
"description": "Canada Day",
"recurring": 1,
"preferred": "2026-07-02"
},
{
"date": "2026-12-25",
"description": "Christmas Day",
"recurring": 1,
"preferred": "2026-12-27"
}
]
}
| Field | Type | Description |
|---|---|---|
date | string | The blackout date (YYYY-MM-DD). For recurring dates, projected to the current or next year. |
description | string|null | Human-readable label (e.g. "Christmas Day"). |
recurring | integer | 1 if the blackout repeats every year, 0 if one-time. |
preferred | string | The next available delivery day after the blackout (YYYY-MM-DD). Skips consecutive blackout dates. |
preferred date to adjust ETAs when a delivery would land on a blackout date. If multiple blackout dates are consecutive (e.g. Dec 25 & 26), preferred will be the first available day after all of them. Only active, future blackout dates are returned. Recurring dates are automatically projected to the current or next year.
https://www.weels.ca/api/shipment/manifest
Manage Canada Post manifests. Manifests must be transmitted to Canada Post before your packages can be picked up. This endpoint lets you check pending shipments, transmit manifests, and retrieve manifest history and PDFs.
| Field | Type | Required | Options | Description |
|---|---|---|---|---|
action | string | Yes | pending, transmit, list, detail, download | The manifest operation to perform. |
manifest_id | integer | Conditional | — | Required for detail. Optional for download (defaults to latest manifest). |
page | integer | No | Default: 1 | Page number for paginated results (used with list). |
limit | integer | No | Default: 25, Max: 100 | Results per page (used with list). |
| Action | Description |
|---|---|
pending | List all unmanifested Canada Post shipments awaiting transmission. |
transmit | Transmit all pending shipments to Canada Post as a manifest. Returns the manifest PDF. |
list | Paginated history of all transmitted manifests. |
detail | List shipments within a specific manifest (packing list). Requires manifest_id. |
download | Get signed download URLs for manifest PDFs. Optional manifest_id (defaults to latest). |
Returns all carrier shipments that have not yet been transmitted to Canada Post.
curl -X POST https://www.weels.ca/api/shipment/manifest \ -H "X-API-Key: your_api_token_here" \ -d "action=pending"
{
"success": true,
"unmanifested_count": 3,
"shipments": [
{
"task_id": 1234,
"reference": "ORD-001",
"order_num": "WC-5890",
"tracking_number": "1234567890123456",
"service_code": "DOM.EP",
"destination": "Toronto, ON",
"created_at": "2026-04-13 10:30:00"
},
{
"task_id": 1235,
"reference": "ORD-002",
"order_num": "",
"tracking_number": "1234567890123457",
"service_code": "DOM.XP",
"destination": "Ottawa, ON",
"created_at": "2026-04-13 11:15:00"
}
]
}
Transmits all pending shipments to Canada Post as a manifest. Once transmitted, the shipments are finalized and a manifest PDF is generated. This is equivalent to “closing out” the day’s shipments.
curl -X POST https://www.weels.ca/api/shipment/manifest \ -H "X-API-Key: your_api_token_here" \ -d "action=transmit"
{
"success": true,
"manifest_id": 42,
"task_count": 5,
"documents": [
{
"label": "Manifest",
"s3_key": "manifests/canada_post/vendor-8/...",
"url": "https://..."
}
],
"manifest_pdf": "https://..."
}
Returns a paginated list of all transmitted manifests for your organization, with signed download URLs for the manifest PDFs.
curl -X POST https://www.weels.ca/api/shipment/manifest \ -H "X-API-Key: your_api_token_here" \ -d "action=list" \ -d "page=1" \ -d "limit=10"
{
"success": true,
"manifests": [
{
"id": 42,
"manifest_id": "12345678",
"task_count": 5,
"status": "transmitted",
"transmitted_at": "2026-04-13 16:00:00",
"download_url": "https://..."
},
{
"id": 41,
"manifest_id": "12345677",
"task_count": 3,
"status": "transmitted",
"transmitted_at": "2026-04-12 16:00:00",
"download_url": "https://..."
}
],
"total": 15,
"page": 1,
"pages": 2
}
Returns the list of shipments included in a specific manifest (packing list). Useful for verifying which packages were included in a transmission.
curl -X POST https://www.weels.ca/api/shipment/manifest \ -H "X-API-Key: your_api_token_here" \ -d "action=detail" \ -d "manifest_id=42"
{
"success": true,
"manifest_id": 42,
"carrier": "canada_post",
"task_count": 5,
"status": "transmitted",
"transmitted_at": "2026-04-13 16:00:00",
"shipments": [
{
"id": 1234,
"reference": "ORD-001",
"order_num": "WC-5890",
"carrier_tracking_number": "1234567890123456",
"carrier_service_code": "DOM.EP",
"destination_fname": "John",
"destination_lname": "Doe",
"destination_company": "",
"destination_address1": "200 Front St W",
"destination_city": "Toronto",
"destination_province": "ON",
"destination_postalcode": "M5V3K2",
"qty": 1,
"weight": "0.500"
}
]
}
Returns signed download URLs for the manifest PDF files. If manifest_id is omitted, returns the most recent manifest. URLs expire after 1 hour.
curl -X POST https://www.weels.ca/api/shipment/manifest \ -H "X-API-Key: your_api_token_here" \ -d "action=download" \ -d "manifest_id=42"
{
"success": true,
"documents": [
{
"label": "Manifest",
"url": "https://...",
"vendor": true
}
]
}
400 Not Enabled
{
"error": "Carrier manifest management is not enabled for this organization."
}
422 No Pending Shipments
{
"success": false,
"error": "No unmanifested Canada Post shipments for this vendor."
}
404 Manifest Not Found
{
"error": "Manifest not found."
}
transmit once at end-of-day to close out the manifest. The transmit call may take a few seconds as it communicates with Canada Post’s servers and generates the PDF artifact. Download URLs expire after 1 hour — use the download action to generate fresh URLs.
All errors return a JSON object with an error field. Some errors also include a code field for programmatic handling.
| HTTP Code | Meaning |
|---|---|
400 | Bad Request -- validation errors, invalid input, address verification failed |
401 | Unauthorized -- invalid or missing API token |
402 | Payment Required -- insufficient credit balance (prepay accounts) |
403 | Forbidden -- token valid but not authorized for this resource |
404 | Not Found -- shipment does not exist |
405 | Method Not Allowed -- wrong HTTP method |
429 | Too Many Requests -- rate limit exceeded |
502 | Bad Gateway -- delivery service error |
Each shipment has a numeric status code. These are the possible values:
| Code | Label |
|---|---|
0 | Delivery label has been created |
1 | Package received at sorting facility |
2 | Package is with courier |
3 | Out for delivery |
4 | Delivered |
5 | Delivery label has been cancelled |
6 | Failed to deliver |
7 | Package picked up from vendor |
8 | New shipment created |
9 | Package en route to transfer hub |
10 | Package held after failed delivery |
11 | Package reported lost — insurance claim filed |
12 | Refund requested |
Webhooks let Weels push real-time event notifications to your server when task statuses change — no polling required. You register an HTTPS endpoint and choose which events to subscribe to. Weels sends a signed POST request to your URL whenever a matching event occurs.
2xx response — this is verified at registration time.
| Event | Fired when |
|---|---|
task.shipped | A shipment is created and assigned to a delivery date |
task.started | A driver starts a delivery or pickup |
task.arrived | The driver marks arrival at the destination |
task.completed | The delivery or pickup is successfully completed |
task.failed | The delivery or pickup attempt was unsuccessful |
Every webhook request is an HTTP POST with a Content-Type: application/json body in the following shape:
{
"event": "task.completed",
"timestamp": "2026-02-20T14:32:00-05:00",
"data": {
"task_id": 48291,
"order_num": "WLS-10042",
"task_type": "delivery",
"status": 4,
"driver": "Sam B.",
"tracking": "https://www.weels.ca/track/48291",
"destination": {
"name": "Jane Smith",
"address": "123 King St W, Toronto, ON M5H 1J9"
},
"started_at": "2026-02-20T13:58:00-05:00",
"completed_at": "2026-02-20T14:32:00-05:00"
}
}
| Field | Type | Description |
|---|---|---|
event | string | The event name (see Events above) |
timestamp | string | ISO 8601 datetime when the event was fired |
data.task_id | integer | Internal Weels task ID |
data.order_num | string|null | Your order/reference number as submitted |
data.task_type | string | delivery or pickup |
data.status | integer | Numeric task status code (see Shipment Statuses) |
data.driver | string|null | Driver's first name and last initial (e.g. Sam B.) |
data.tracking | string | Public tracking page URL |
data.destination.name | string | Recipient full name |
data.destination.address | string | Full destination address |
data.started_at | string|null | ISO 8601 datetime when the driver started the task |
data.completed_at | string|null | ISO 8601 datetime when the task was completed |
Every request includes an X-Weels-Signature header. Verify it before processing the payload to confirm the request came from Weels and hasn't been tampered with.
The signature is an HMAC-SHA256 of <timestamp>.<raw_body>, keyed with your secret. Both the signature and timestamp are sent as headers:
X-Weels-Signature: sha256=<HMAC-SHA256(timestamp + "." + raw_body, secret)> X-Weels-Timestamp: 1740000000
To verify, reconstruct the signed content from the timestamp header and the raw body, then compare signatures. Reject payloads older than 5 minutes to prevent replay attacks:
$payload = file_get_contents('php://input');
$secret = 'your_webhook_secret';
$timestamp = $_SERVER['HTTP_X_WEELS_TIMESTAMP'] ?? '';
$received = $_SERVER['HTTP_X_WEELS_SIGNATURE'] ?? '';
// Reject payloads older than 5 minutes
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(401);
exit('Timestamp too old');
}
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
if (!hash_equals($expected, $received)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
// process $event...
| Header | Value |
|---|---|
Content-Type | application/json |
X-Weels-Event | The event name (e.g. task.completed) |
X-Weels-Signature | HMAC-SHA256 signature of timestamp.body, prefixed with sha256= |
X-Weels-Timestamp | Unix timestamp (seconds) when the request was signed — use for replay protection |
User-Agent | Weels-Webhook/1.0 |
2xx status within 10 seconds. Any other response (including timeouts) is considered a failure.webhook.test ping and confirm your endpoint is reachable at any time.200 immediately and handle processing in a background job.
Embed a delivery zone checker on any website with a single script tag. The widget lets your customers verify whether their postal code is within our service area — no API key required.
Add this snippet anywhere on your page:
<div id="weels-service-area"></div> <script src="https://www.weels.ca/js/embed-service-area.js"></script>
The widget is self-contained — zero dependencies, no jQuery, no external stylesheets. It injects its own scoped styles and calls the public /api/service-area endpoint directly.
Add data- attributes to the script tag to customize:
| Attribute | Default | Description |
|---|---|---|
data-theme | light | light or dark |
data-accent | #10b981 | Accent color for button and focus ring |
data-button-text | Check availability | Button label |
data-placeholder | Enter your postal code | Input placeholder |
data-target | #weels-service-area | CSS selector for container element |
<div id="weels-service-area"></div> <script src="https://www.weels.ca/js/embed-service-area.js" data-theme="dark" data-accent="#6366f1" data-button-text="Check my area"> </script>