Introduction
Welcome to the Vanlo API! You can use our API to verify addresses, rate and create shipments and shipping labels, and monitor tracking codes.
This is an EasyPost-compatible API, so switching from EasyPost to Vanlo is as simple as changing your request URL and API key!
We have client libraries / SDKs for Ruby, Python, PHP and C#. You can view code examples on the right, and you can switch the programming language of the examples with the tabs in the top right.
Request URL
Test: https://test.vanlo.com/api/v1/...
Production: https://www.vanlo.com/api/v1/...
Authentication
Authentication is performed by including your API key with every request (cURL), or by setting it globally in one of our client libraries / SDKs:
curl -X METHOD https://www.vanlo.com/api/v1/... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
require_once("/path/to/lib/vanlo.php");
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Make sure to replace
VANLO_API_KEYwith your API key.
Vanlo uses API keys for authentication and identification.
Vanlo expects for the API key to be included in all API requests as an authorization bearer token:
Authorization: Bearer VANLO_API_KEY
Test Environment
In the client libraries / SDKs you can access the test environment by setting the API base value before performing any actions:
curl -X METHOD https://test.vanlo.com/api/v1/... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo.api_base = 'https://test.vanlo.com/api/v1'
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.api_base = 'https://test.vanlo.com/api/v1'
require_once("/path/to/lib/vanlo.php");
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
\Vanlo\Vanlo::setApiBase('https://test.vanlo.com/api/v1');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY", "https://test.vanlo.com/api/v1");
Vanlo offers a test environment which you can develop against without incurring any real charges or generating any live postage labels or tracking codes.
You can find your test API Key by logging in to the Vanlo Dashboard, entering "test mode" by clicking the toggle in the bottom of the left side bar, and then visiting the API Keys page: https://dashboard.vanlo.com/apikey
Shipments
Shipment Object
A purchased Shipment:
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042",
"usps_zone": "08",
"custom_id": "order-1042",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "pdf",
"label_size": "4X6",
"label_date": "2026-10-20",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
}
A Shipment holds the addresses, parcel and customs details of one package. Creating it returns a rate for each available service, and buying one of those rates purchases the label and fills in selected_rate, postage_label, tracker and tracking_code.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "shp_" |
| object | string | "Shipment" |
| usps_ |
string | The USPS zone of the shipment. An integer such as 8 until the label is bought, then a string such as "08". Present only on USPS shipments |
| to_ |
Address | The destination address |
| from_ |
Address | The origin address |
| parcel | Parcel | The dimensions and weight of the package |
| customs_ |
CustomsInfo | Information for the processing of customs |
| rates | Rate[] | All associated Rate objects |
| selected_ |
Rate | The specific rate purchased for the shipment, or null if unpurchased or purchased through another mechanism |
| tracker | Tracker | The associated Tracker object |
| postage_ |
PostageLabel | The associated PostageLabel object |
| reference | string | Your reference for the shipment, as sent on create |
| custom_ |
string | Your key for the shipment, as sent on create |
| refund_ |
string | The current status of the shipment refund process. Possible values are "submitted", "refunded", "rejected" |
| refund_ |
string | Why the refund was rejected, present only when it was |
| tracking_ |
string | If purchased, the tracking code will appear here as well as within the Tracker object |
| status | string | The current tracking status of the shipment. Null until the carrier reports the first scan |
| is_ |
boolean | Set true to create as a return |
| options | Options | The options sent with the shipment |
| insurance | float | The declared insurance amount, if insurance was bought with the insurance_amount option |
| return_ |
Address | Optional return address, if different from the origin address |
| buyer_ |
Address | Optional buyer address, if different from the destination address |
| usps_ |
string | USPS tracking code, present when a non-USPS service hands the package to USPS for delivery |
| usps_ |
Tracker | Tracker for usps_tracking_code, present with it |
| forms | object[] | The commercial invoice of an international FedEx label, as one { object: "Form", form_type: "commercial_invoice", form_url, submitted_electronically, created_at } entry. Present only when one was generated |
| created_ |
datetime | When the shipment was created |
| updated_ |
datetime | When the shipment was last updated |
Carrier Services
The services each carrier returns on rates, and the options it accepts. Which services you are quoted depends on your account.
Services
| Service | Name | What it is for |
|---|---|---|
| GroundAdvantage | Ground Advantage | Ground delivery for packages, the standard domestic choice. |
| First | First | Lightweight domestic mail, priced for small parcels. |
| Priority | Priority | Faster domestic delivery, in one to three days. |
| Express | Express | The fastest domestic option, in one to two days. |
| ParcelSelect | Parcel Select | Economy ground delivery for larger or high-volume shipments. |
| MediaMail | Media Mail | Discounted rate restricted to books and media contents. |
| LibraryMail | Library Mail | Discounted rate restricted to library materials. |
| FirstClassMailInternational | First Class Mail International | Lightweight international mail. |
| FirstClassPackageInternationalService | First Class Package International Service | Economy international delivery for small packages. |
| PriorityMailInternational | Priority Mail International | Faster international delivery for packages. |
| ExpressMailInternational | Express Mail International | The fastest international option. |
Options only for USPS
insurance_amounthazmatfetch_express_delivery_datemachinablespecial_rates_eligibility
Fees entries in rate_detail.services
USPS entries are 15-character USPS codes. The first is the postage, and each one below is an extra fee. Every code here ends in 0000.
| Code | Fee | When it applies |
|---|---|---|
| DXSP0EXXXXX0000 DXSV0EXXXXX0000 DXSL0EXXXXX0000 DXSM0EXXXXX0000 |
Signature confirmation | You asked for signature confirmation. The code differs by service: Priority Mail and Ground Advantage, then Parcel Select, Library Mail and Media Mail. |
| DXSP0EJXXXX0000 DXSV0EJXXXX0000 DXSL0EJXXXX0000 DXSM0EJXXXX0000 DXSF0EJPXXX0000 |
Signature confirmation, restricted delivery | You asked for signature confirmation restricted to the named recipient. |
| DXAX0XXXXXX0000 | Adult signature | You asked for an adult signature. |
| DXBX0XXXXXX0000 | Adult signature, restricted delivery | You asked for an adult signature restricted to the named recipient. |
| DX1F0XXLXRX0000 | Non-machinable letter | A First-Class letter USPS cannot run through its letter equipment - the wrong length-to-width ratio, or too thin for its size. |
| D811XUXXXXX0000 D811XXXXXXX0000 |
Long parcel | The longest side measures more than 22 inches. |
| D812XUXXXXX0000 D812XXXXXXX0000 |
Long parcel, over 30 inches | The longest side measures more than 30 inches. The code differs by service: Ground Advantage, then every other service. |
| D813XUXXXXX0000 D813XXXXXXX0000 |
Oversized parcel | The parcel measures more than 2 cubic feet. The code differs by service: Ground Advantage, then every other service. |
| DX0P0HXXXCX0000 DX0E0HXXXCX0000 DX0U0HXXXCX0000 DX0V0HXXXCX0000 |
Hazardous materials | You declared hazardous contents. The code differs by service: Priority Mail, Priority Mail Express, Ground Advantage, then Parcel Select. It is charged on Priority Mail and Priority Mail Express, and free on Ground Advantage and Parcel Select. |
Priority Mail Express carries no separate signature fee. That service already includes a signature, so no signature code appears on it. An adult signature is still charged.
The two length fees never both appear. A parcel over 30 inches is charged the over-30 fee instead of the over-22 one, not on top of it. An oversized parcel is separate and can appear alongside either.
Media Mail and Library Mail carry no length or oversized fee.
International shipments carry almost nothing. No signature, adult signature, length, oversized or non-machinable fee can appear on an international USPS shipment. Hazardous materials is the one exception.
USPS publishes the current price for each of these fees in Notice 123, the USPS price list.
Services
| Service | Name | What it is for |
|---|---|---|
| FEDEX_ |
Ground | Ground delivery to businesses. |
| GROUND_ |
Home Delivery | Ground delivery to residential addresses. |
| FEDEX_ |
FedEx 2Day | Delivery in two business days. |
| FEDEX_ |
FedEx 2Day AM | Delivery in two business days by the morning. |
| FEDEX_ |
ExpressSaver | Express delivery in three business days. |
| STANDARD_ |
FedEx Standard Overnight | Next business day by the end of day. |
| PRIORITY_ |
FedEx Priority Overnight | Next business day by the morning. |
| FIRST_ |
FedEx First Overnight | Next business day, earliest available delivery. |
| INTERNATIONAL_ |
FedEx Intl Economy | Economy international delivery. |
| INTERNATIONAL_ |
International Ground | Ground delivery to Canada. |
| INTERNATIONAL_ |
InternationalFirst | The earliest international express delivery. |
| INTERNATIONAL_ |
FedEx Intl Priority | Fast international delivery. |
| SMART_ |
SmartPost | Economy delivery with final handoff to USPS. |
Options only for FedEx
duty_paymentendorsementsmartpost_hubsmartpost_manifestsaturday_delivery
Services
| Service | Name | What it is for |
|---|---|---|
| Ground | Ground | Ground delivery, the standard domestic choice. |
| 3DaySelect | 3 Day Select | Delivery in three business days. |
| 2ndDayAir | 2nd Day Air | Delivery in two business days. |
| 2ndDayAirAM | 2nd Day Air AM | Delivery in two business days by the morning. |
| NextDayAirSaver | Next Day Air Saver | Next business day by the end of day. |
| NextDayAir | Next Day Air | Next business day by midday. |
| NextDayAirEarlyAM | Next Day Air Early AM | Next business day, earliest available delivery. |
| UPSStandard | UPS Standard | Ground delivery to Canada and Mexico. |
| UPSSaver | UPS Saver | International express by the end of day. |
| Express | Express | International express by the morning. |
| ExpressPlus | Express Plus | International express, earliest available delivery. |
| Expedited | Expedited | Economy international delivery. |
Options only for UPS
Services
| Service | Name | What it is for |
|---|---|---|
| UniUni | UniUni | Last-mile delivery, the single UniUni service. |
Options only for UniUni
total_valuehub_idbatch_numberbag_numberbuzz_codedriver_notes
Services
| Service | Name | What it is for |
|---|---|---|
| Parcel | Parcel | Economy parcel delivery. |
| GroundAdvantage | Ground Advantage | Ground delivery with final handoff to USPS. |
| Priority | Priority | Faster delivery with final handoff to USPS. |
| GlobalStandard | Global Standard | Economy international delivery. |
| GlobalPriority | Global Priority | Faster international delivery. |
| GlobalEPacket | Global E Packet | International delivery for lightweight packets. |
| GlobalParcel | Global Parcel | International delivery for parcels. |
Options
Services
| Service | Name |
|---|---|
| ECOCE | OneParcel Economy Central |
| ECOEA | OneParcel Economy East |
| ECONE | OneParcel Economy Northeast |
| ECONJ | OneParcel Economy New Jersey |
| ECOSE | OneParcel Economy Southeast |
| ECOSL | OneParcel Economy Salt Lake City |
| ECOSO | OneParcel Economy South |
| ECOWE | OneParcel Economy West |
| STDCE | OneParcel Standard Central |
| STDEA | OneParcel Standard East |
| STDNE | OneParcel Standard Northeast |
| STDNJ | OneParcel Standard New Jersey |
| STDSE | OneParcel Standard Southeast |
| STDSL | OneParcel Standard Salt Lake City |
| STDSO | OneParcel Standard South |
| STDWE | OneParcel Standard West |
| EXPNJ | OneParcel Expedited New Jersey |
| REGSL | OneParcel Regional Salt Lake |
| BPMCE | Bound Printed Matter Central |
| BPMNE | Bound Printed Matter Northeast |
| BPMSO | Bound Printed Matter South |
| BPMWE | Bound Printed Matter West |
Some OneParcel rates come from partner networks, so codes outside this list can appear.
Options
Services
| Service | Name | What it is for |
|---|---|---|
| Drive | DoorDash Drive | Same-day local delivery by a driver, the single DoorDash service. |
Options only for DoorDash
Services
| Service | Name | What it is for |
|---|---|---|
| RD | Routine Delivery | Regional ground delivery, the standard OnTrac service. |
| SD | Same Day | Same-day regional delivery. |
OnTrac quotes whatever services your contract carries; these are the two standard ones.
Options only for OnTrac
total_valuedelivery_instructionspickup_begin_timepickup_typepickup_end_time
Services
| Service | Name |
|---|---|
| groundPlus | Ground Plus |
| groundPlusOne | Ground Plus 1 |
| groundPlusTwo | Ground Plus 2 |
| groundPlusThree | Ground Plus 3 |
| groundPlusFour | Ground Plus 4 |
| nextDay | Next Day |
| sameDay | Same Day |
| twoDay | Two Day |
| expressAir | Express Air |
| premiumEconomy | Premium Economy |
| vehoValue | Veho Value |
Services
| Service | Name |
|---|---|
| StandardDdu | Standard DDU |
| StandardDduDelcon | Standard DDU Delcon |
| PriorityDdu | Priority DDU |
| PriorityDduDelcon | Priority DDU Delcon |
| PriorityDdp | Priority DDP |
| PriorityDdpDelcon | Priority DDP Delcon |
| ExpeditedDdpDelcon | Expedited DDP Delcon |
| ExpeditedDduDelcon | Expedited DDU Delcon |
| ExpressDdp | Express DDP |
| ExpressDdpDelcon | Express DDP Delcon |
| ExpressDduDelcon | Express DDU Delcon |
| epacketDdp | ePacket DDP |
| GlobalPlus | Global Plus |
Services
| Service | Name |
|---|---|
| DHLParcelGround | DHL SM Parcel Ground |
| DHLParcelExpedited | DHL SM Parcel Expedited |
| DHLParcelExpeditedMax | DHL SM Parcel Expedited Max |
| DHLBPMGround | DHL SM Bound Printed Matter Ground |
| DHLBPMExpedited | DHL SM Bound Printed Matter Expedited |
| DHLSmartMailParcelReturnGround | DHL SM Parcel Return Ground |
| DHLSmartMailParcelReturnPlus | DHL SM Parcel Return Plus |
| DHLSmartMailParcelReturnLight | DHL SM Parcel Return Light |
| DHLPacketInternational | DHL Packet International |
| DHLParcelInternationalStandard | DHL Parcel International Standard |
| DHLParcelInternationalDirect | DHL Parcel International Direct |
| DHLParcelInternationalDirectPriority | DHL Parcel International Direct Priority |
| DHLParcelInternationalDirectStandard | DHL Parcel International Direct Standard |
| DHLParcelInternationalDirectSMB | DHL Parcel International Direct SMB |
| DHLParcelInternationalStandardSMB | DHL Parcel International Standard SMB |
Services
| Service | Name |
|---|---|
| Amazon Shipping Ground | Amazon Shipping Ground |
Create a Shipment
POST/api/v1/shipments
curl -X POST https://www.vanlo.com/api/v1/shipments \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"shipment": {
"reference": "order-1042",
"custom_id": "order-1042",
"to_address": {
"name": "John Doe",
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true
},
"from_address": {
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example"
},
"parcel": {
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
},
"carrier_accounts": [
"ca_..."
],
"options": {
"label_format": "PDF",
"label_size": "4X6",
"label_date": "2026-10-20",
"delivery_confirmation": "SIGNATURE",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
}
}'
# OR reference previously created objects
curl -X POST https://www.vanlo.com/api/v1/shipments \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"shipment": {
"to_address": {
"id": "adr_..."
},
"from_address": {
"id": "adr_..."
},
"parcel": {
"id": "prcl_..."
},
"customs_info": {
"id": "cstinfo_..."
}
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Shipment.create(
reference: 'order-1042',
custom_id: 'order-1042',
to_address: {
name: 'John Doe',
street1: '148 W 51st St',
street2: 'Apt 4B',
city: 'New York',
state: 'NY',
zip: '10019',
country: 'US',
phone: '2125550199',
email: 'john.doe@example.com',
residential: true
},
from_address: {
name: 'Jane Smith',
company: 'Acme Goods',
street1: '417 Montgomery St',
street2: 'Floor 5',
city: 'San Francisco',
state: 'CA',
zip: '94104',
country: 'US',
phone: '4155550100',
email: 'shipping@acme.example'
},
parcel: {
length: 10.0,
width: 8.0,
height: 4.0,
weight: 32.0
},
carrier_accounts: ['ca_...'],
options: {
label_format: 'PDF',
label_size: '4X6',
label_date: '2026-10-20',
delivery_confirmation: 'SIGNATURE',
print_custom: [
{
name: 'Order',
value: '1042'
}
]
}
)
# OR reference previously created objects
Vanlo::Shipment.create(
to_address: { id: 'adr_...' },
from_address: { id: 'adr_...' },
parcel: { id: 'prcl_...' },
customs_info: { id: 'cstinfo_...' }
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
shipment = vanlo.Shipment.create(
reference="order-1042",
custom_id="order-1042",
to_address={
"name": "John Doe",
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": True
},
from_address={
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example"
},
parcel={
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
},
carrier_accounts=["ca_..."],
options={
"label_format": "PDF",
"label_size": "4X6",
"label_date": "2026-10-20",
"delivery_confirmation": "SIGNATURE",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
)
# OR reference previously created objects
shipment = vanlo.Shipment.create(
to_address={"id": "adr_..."},
from_address={"id": "adr_..."},
parcel={"id": "prcl_..."},
customs_info={"id": "cstinfo_..."}
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$shipment = \Vanlo\Shipment::create(array(
'reference' => 'order-1042',
'custom_id' => 'order-1042',
'to_address' => array(
'name' => 'John Doe',
'street1' => '148 W 51st St',
'street2' => 'Apt 4B',
'city' => 'New York',
'state' => 'NY',
'zip' => '10019',
'country' => 'US',
'phone' => '2125550199',
'email' => 'john.doe@example.com',
'residential' => true
),
'from_address' => array(
'name' => 'Jane Smith',
'company' => 'Acme Goods',
'street1' => '417 Montgomery St',
'street2' => 'Floor 5',
'city' => 'San Francisco',
'state' => 'CA',
'zip' => '94104',
'country' => 'US',
'phone' => '4155550100',
'email' => 'shipping@acme.example'
),
'parcel' => array(
'length' => 10.0,
'width' => 8.0,
'height' => 4.0,
'weight' => 32.0
),
'carrier_accounts' => array('ca_...'),
'options' => array(
'label_format' => 'PDF',
'label_size' => '4X6',
'label_date' => '2026-10-20',
'delivery_confirmation' => 'SIGNATURE',
'print_custom' => array(
array(
'name' => 'Order',
'value' => '1042'
)
)
)
));
// OR reference previously created objects
$shipment = \Vanlo\Shipment::create(array(
'to_address' => array('id' => 'adr_...'),
'from_address' => array('id' => 'adr_...'),
'parcel' => array('id' => 'prcl_...'),
'customs_info' => array('id' => 'cstinfo_...')
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Shipment shipment = Shipment.Create(new Dictionary<string, object>() {
{ "reference", "order-1042" },
{ "custom_id", "order-1042" },
{ "to_address", new Dictionary<string, object>() {
{ "name", "John Doe" },
{ "street1", "148 W 51st St" },
{ "street2", "Apt 4B" },
{ "city", "New York" },
{ "state", "NY" },
{ "zip", "10019" },
{ "country", "US" },
{ "phone", "2125550199" },
{ "email", "john.doe@example.com" },
{ "residential", true }
} },
{ "from_address", new Dictionary<string, object>() {
{ "name", "Jane Smith" },
{ "company", "Acme Goods" },
{ "street1", "417 Montgomery St" },
{ "street2", "Floor 5" },
{ "city", "San Francisco" },
{ "state", "CA" },
{ "zip", "94104" },
{ "country", "US" },
{ "phone", "4155550100" },
{ "email", "shipping@acme.example" }
} },
{ "parcel", new Dictionary<string, object>() {
{ "length", 10.0 },
{ "width", 8.0 },
{ "height", 4.0 },
{ "weight", 32.0 }
} },
{ "carrier_accounts", new List<string>() { "ca_..." } },
{ "options", new Dictionary<string, object>() {
{ "label_format", "PDF" },
{ "label_size", "4X6" },
{ "label_date", "2026-10-20" },
{ "delivery_confirmation", "SIGNATURE" },
{ "print_custom", new List<Dictionary<string, object>>() {
new Dictionary<string, object>() {
{ "name", "Order" },
{ "value", "1042" }
}
} }
} }
});
// OR reference previously created objects
Shipment shipment = Shipment.Create(new Dictionary<string, object>() {
{ "to_address", new Dictionary<string, object>() {
{ "id", "adr_..." }
} },
{ "from_address", new Dictionary<string, object>() {
{ "id", "adr_..." }
} },
{ "parcel", new Dictionary<string, object>() {
{ "id", "prcl_..." }
} },
{ "customs_info", new Dictionary<string, object>() {
{ "id", "cstinfo_..." }
} }
});
Creates a shipment and returns it with a rate for each service your carrier accounts offer. Buy one of the rates to purchase the label, or send service with options.create_and_buy to buy in the same request.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| from_ |
Address | Your warehouse address |
| to_ |
Address | Recipient address |
| parcelrequired | Parcel | Package properties. To ship several packages from one address to one recipient, create an Order. |
| customs_ |
CustomsInfo | Only required for international shipments and shipments to APO/DPO/FPO. |
| options | Options | Shipment options. On an international shipment that may ship with FedEx or UPS, send options.duty_payment to say who pays duties and taxes. |
| service | string | The service to buy. With options.create_and_buy the label is bought in the same request; without it only this service is rated, and its rate is set as selected_rate. |
| carrier | string | A carrier name, such as USPS, to rate only that carrier's accounts. Ignored when carrier_accounts is sent. |
| carrier_ |
string[] | One or more Carrier Account ids to get rates from. Without it, or carrier, every account you hold rates the shipment, narrowed to the accounts offering service when one is sent. |
| reference | string | Arbitrary string that you can use later to look up the shipment or filter all the shipments with the same reference to include in a ScanForm. |
| custom_ |
string | Your key for this shipment. While the shipment can still be bought, sending the same custom_id again updates it instead of creating another one. After that it answers 409 CONFLICT with the shipment. |
| return_ |
Address | Distinct return address if it differs from from_address. |
| is_ |
boolean | Set true to create a return shipment. The same as options.is_return. |
| buyer_ |
Address | Distinct buyer address if it differs from to_address. |
Returns
Response:
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:04:12Z",
"reference": "order-1042",
"usps_zone": 8,
"custom_id": "order-1042",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": null,
"tracker": null,
"postage_label": null,
"refund_status": null,
"tracking_code": null,
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "pdf",
"label_size": "4X6",
"label_date": "2026-10-20",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "to_address",
"message": "is missing"
}
]
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "Address not found by id for to_address field. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
INVALID_OPTIONS:
{
"error": {
"code": "INVALID_OPTIONS",
"message": "Invalid options. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "options",
"message": "label_format must be one of: png, pdf, zpl, epl2"
}
]
}
}
Response for
CONFLICT:
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042",
"usps_zone": "08",
"custom_id": "order-1042",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "pdf",
"label_size": "4X6",
"label_date": "2026-10-20",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
},
"error": {
"code": "CONFLICT",
"message": "A shipment with this custom_id already exists and cannot be updated. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
PAYMENT_REQUIRED:
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient funds. Please check your billing settings at http://www.vanlo.com/balance. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Balance",
"message": "Your balance is too low to purchase this label. Please add funds on the Balance page before buying."
}
]
}
}
Response for
CARRIER_REJECTED_ADDRESS:
{
"error": {
"code": "CARRIER_REJECTED_ADDRESS",
"message": "USPS rejected this shipment: bad zip code. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "USPS rejected this shipment: bad zip code"
}
]
}
}
Response for
EXTERNAL_SERVICE_ERROR:
{
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "OnTrac could not create this label. Please contact support if it does not clear. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "OnTrac could not create this label. Please contact support if it does not clear."
}
]
}
}
Response for
TOO_MANY_REQUESTS:
{
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many label purchases in flight for this account. Please retry shortly. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [],
"details": {
"retry_after": 2
}
}
}
Returns the Shipment with a rate for each available service, and with the label already bought when options.create_and_buy is set.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A required field is missing or has the wrong shape, such as no to_address or a parcel without weight and dimensions. error.errors names each field. |
NOT_ |
404 | An address, parcel or customs info sent by id is not one of yours. |
INVALID_ |
422 | An options value is not allowed, such as an unknown label_format, a hazmat value the carrier does not take, or a malformed duty_payment. |
CONFLICT |
409 | The custom_id belongs to a shipment that can no longer be updated. That shipment is returned beside error. |
PAYMENT_ |
402 | With options.create_and_buy, your balance does not cover the label. |
CARRIER_ |
422 | The carrier refused the destination address. error.message carries its reason. |
EXTERNAL_ |
424 | The carrier rejected or failed the request. error.message carries its reason. |
TOO_ |
429 | Too many label purchases are running for your account at once. The Retry-After header gives the wait in seconds. |
Retrying a create or a purchase after a timeout is covered in the Retries and Timeouts Guide.
Buy a Shipment
POST/api/v1/shipments/:id/buy
curl -X POST https://www.vanlo.com/api/v1/shipments/shp_.../buy \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"rate": {
"id": "rate_..."
}
}'
require 'vanlo'
Vanlo.api_key = "VANLO_API_KEY"
shipment = Vanlo::Shipment.retrieve("shp_...")
shipment.buy(rate: shipment.lowest_rate)
import vanlo
vanlo.api_key = "VANLO_API_KEY"
shipment = vanlo.Shipment.retrieve("shp_...")
shipment.buy(rate=shipment.lowest_rate())
require_once("path/to/lib/vanlo.php");
\Vanlo\Vanlo::setApiKey("VANLO_API_KEY");
$shipment = \Vanlo\Shipment::retrieve("shp_...");
$shipment->buy(array(
'rate' => $shipment->lowest_rate()
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Shipment shipment = Shipment.Retrieve("shp_...");
Rate lowestRate = shipment.LowestRate();
shipment.Buy(lowestRate);
Buys the label for one of the shipment's rates, in the format of the shipment's options.label_format.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| rate | object | The rate to buy, as { "id": "rate_..." }
|
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Postage already exists for this shipment. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
PAYMENT_REQUIRED:
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient funds. Please check your billing settings at http://www.vanlo.com/balance. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Balance",
"message": "Your balance is too low to purchase this label. Please add funds on the Balance page before buying."
}
]
}
}
Response for
RATE_EXPIRED:
{
"error": {
"code": "RATE_EXPIRED",
"message": "Rate expired. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "Rate expired"
}
]
}
}
Response for
CARRIER_REJECTED_ADDRESS:
{
"error": {
"code": "CARRIER_REJECTED_ADDRESS",
"message": "USPS rejected this shipment: bad zip code. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "USPS rejected this shipment: bad zip code"
}
]
}
}
Response for
VALIDATION_ERROR:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The maximum per package weight for the selected service from the selected country or territory is 150 pounds. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "The maximum per package weight for the selected service from the selected country or territory is 150 pounds."
}
]
}
}
Response for
LOCKED:
{
"error": {
"code": "LOCKED",
"message": "Another resource is creating at the moment. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "LockedError",
"message": "This shipment is already being purchased. Please wait for it to finish."
}
]
}
}
Response for
EXTERNAL_SERVICE_ERROR:
{
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "OnTrac could not create this label. Please contact support if it does not clear. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "OnTrac could not create this label. Please contact support if it does not clear."
}
]
}
}
Response for
TOO_MANY_REQUESTS:
{
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many label purchases in flight for this account. Please retry shortly. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [],
"details": {
"retry_after": 2
}
}
}
Returns the Shipment with selected_rate, postage_label, tracker and tracking_code filled in.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | The shipment already has a label, or is past its 72-hour purchase window. |
NOT_ |
404 | No shipment has this id, or the rate is not one of its rates. |
PAYMENT_ |
402 | Your balance does not cover the label. |
RATE_ |
409 | The carrier no longer honours the rate. |
CARRIER_ |
422 | The carrier refused the destination address. error.message carries its reason. |
VALIDATION_ |
422 | The carrier refused the shipment as invalid, such as a parcel over the service's weight limit. error.message carries its reason. |
LOCKED |
429 | This shipment is already being bought, or Vanlo is confirming an earlier purchase with the carrier. |
EXTERNAL_ |
424 | The carrier rejected or failed the request. error.message carries its reason. |
TOO_ |
429 | Too many label purchases are running for your account at once. The Retry-After header gives the wait in seconds. |
Refund a Shipment
POST/api/v1/shipments/:id/refund
curl -X POST https://www.vanlo.com/api/v1/shipments/shp_.../refund \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = "VANLO_API_KEY"
shipment = Vanlo::Shipment.retrieve("shp_...")
shipment.refund
import vanlo
vanlo.api_key = "VANLO_API_KEY"
shipment = vanlo.Shipment.retrieve("shp_...")
shipment.refund()
require_once("path/to/lib/vanlo.php");
\Vanlo\Vanlo::setApiKey("VANLO_API_KEY");
$shipment = \Vanlo\Shipment::retrieve("shp_...");
$shipment->refund();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Shipment shipment = Shipment.Retrieve("shp_...");
shipment.Refund();
Asks the carrier to cancel the label and refund its cost.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the shipment to refund |
Returns
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
VALIDATION_ERROR:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Return label orders cannot be canceled. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
EXTERNAL_SERVICE_ERROR:
{
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "Unexpected response from our service provider has been received while processing your request. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Shipment with refund_status set: submitted while the carrier decides, then refunded or rejected. A refund the carrier declines is not an error.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No shipment has this id. |
VALIDATION_ |
422 | The carrier will not cancel this kind of label, such as a return label. error.message carries its reason. |
EXTERNAL_ |
424 | The carrier failed to answer the cancel request. |
List Shipments
GET/api/v1/shipments
curl -G https://www.vanlo.com/api/v1/shipments \
-H 'Authorization: Bearer VANLO_API_KEY' \
-d 'page_size=5' \
-d 'purchased=true'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Shipment.all(page_size: 5)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Shipment.all(page_size=5)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$shipments = \Vanlo\Shipment::all(array('page_size' => 5));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
var listParams = new Dictionary<string, object>() {
{ "page_size", 5 }
};
ShipmentList shipmentList = Shipment.List(listParams);
Lists your shipments a page at a time. Pass before_id or after_id to say where the next page begins.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| purchased | boolean | When present, only return purchased shipments (shipments with a tracking code) |
| before_ |
string | Return shipments created before this id |
| after_ |
string | Return shipments created after this id |
| start_ |
datetime | Only return shipments created after this timestamp |
| end_ |
datetime | Only return shipments created before this timestamp |
| page_ |
integer | Number of shipments to return per page (default 20, max 100) |
Returns
Response:
{
"shipments": [
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042",
"usps_zone": "08",
"custom_id": "order-1042",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "pdf",
"label_size": "4X6",
"label_date": "2026-10-20",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
}
],
"has_more": true
}
Returns an object with shipments, an array of Shipment, and has_more, which says whether another page exists.
On failure it returns one of the common errors; this call has none of its own.
Retrieve a Shipment
GET/api/v1/shipments/:id
curl https://www.vanlo.com/api/v1/shipments/shp_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Shipment.retrieve('shp_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Shipment.retrieve('shp_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$shipment = \Vanlo\Shipment::retrieve('shp_...');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Shipment shipment = Shipment.Retrieve("shp_...");
Retrieves a shipment by its id, or by its tracking_code, custom_id or reference.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the shipment, or a tracking code, custom_id, or reference |
Returns
Response:
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042",
"usps_zone": "08",
"custom_id": "order-1042",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "pdf",
"label_size": "4X6",
"label_date": "2026-10-20",
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Shipment.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No shipment of yours matches the id, tracking code, custom_id or reference. |
Dispute a Transaction
POST/api/v1/transactions/:id/dispute
curl -X POST https://www.vanlo.com/api/v1/transactions/paylog_.../dispute \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"reason": "INCORRECT_ASSESSED_WEIGHT",
"description": "Package weighed 4 lbs, USPS billed for 7 lbs"
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
transaction = Vanlo::Transaction.retrieve('paylog_...')
transaction.dispute(
reason: 'INCORRECT_ASSESSED_WEIGHT',
description: 'Package weighed 4 lbs, USPS billed for 7 lbs'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
transaction = vanlo.Transaction.retrieve('paylog_...')
transaction.dispute(
reason='INCORRECT_ASSESSED_WEIGHT',
description='Package weighed 4 lbs, USPS billed for 7 lbs'
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$transaction = \Vanlo\Transaction::retrieve('paylog_...');
$transaction->dispute(array(
'reason' => 'INCORRECT_ASSESSED_WEIGHT',
'description' => 'Package weighed 4 lbs, USPS billed for 7 lbs'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Transaction transaction = Transaction.Retrieve("paylog_...");
transaction.Dispute("INCORRECT_ASSESSED_WEIGHT", "Package weighed 4 lbs, USPS billed for 7 lbs");
Disputes an adjustment USPS made after a shipment, such as a reassessment of its weight, zone or dimensions. Vanlo files it with USPS, and a refund for an accepted dispute is credited to your account.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| reasonrequired | string | Reason for the dispute. USPS accepts INCORRECT_ASSESSED_WEIGHT, INCORRECT_ASSESSED_ZONE, INCORRECT_ASSESSED_PACKAGING, INCORRECT_ASSESSED_DIMENSIONS, INCORRECT_ASSESSED_DUPLICATE, UNDOCUMENTED, NONCOMPLIANT_DIMENSIONS, RETURN_LABEL, MISSHIPPED, or OTHER. |
| description | string | Free-text description providing more context for the dispute. Defaults to the reason when omitted. |
Returns
Response:
{
"id": 123,
"dispute_id": "DSP-2026-001",
"status": "NEW",
"reason": "INCORRECT_ASSESSED_WEIGHT",
"message": "Dispute submitted to USPS"
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "This charge can't be disputed through USPS. USPS only reviews disputes for adjustments it makes after a shipment (its reassessments of weight, zone, or dimensions). Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the dispute: its dispute_id at USPS and its status.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | The charge is not a USPS adjustment, such as the original purchase, a duplicate charge or a failed refund, or it was already disputed, or reason is missing. |
NOT_ |
404 | No transaction of yours has this id. |
Nested Objects
Objects a Shipment carries or accepts. Each one also expands in place wherever a table names it.
Rate Object
A Rate:
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
}
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with 'rate_' |
| object | string | "Rate" |
| carrier | string | Name of the carrier |
| service | string | Name of the service. Each carrier's services are listed under Carrier Services |
| rate | string | The price of this service, in USD |
| rate_ |
object | How the rate was priced: total_freight and total_surcharges, the zone, billing_weight and sku, and on a discounted USPS rate the commercial_freight before the discount. Each carrier's fees are listed under Carrier Services
|
| shipment_ |
string | The shipment this rate belongs to, or null on a quote |
| carrier_ |
string | The Carrier Account that priced this rate |
| delivery_ |
string | Estimated delivery date, when the carrier gives one |
| delivery_ |
datetime | Estimated delivery date and time, when the carrier gives one |
| delivery_ |
boolean | Whether the carrier guarantees the delivery date |
| delivery_ |
integer | Estimated days in transit, when the carrier gives them |
| usps_ |
boolean | Whether the rate is USPS cubic pricing. Present only on rates that carry the flag |
| created_ |
datetime | When the rate was created |
PostageLabel Object
A PostageLabel:
{
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
}
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with 'pl_' |
| object | string | "PostageLabel" |
| integrated_ |
string | Always null |
| label_ |
string | The ship date printed on the label, as YYYY-MM-DD |
| label_ |
string | Always null |
| label_ |
string | URL of the PDF label, when one exists |
| label_ |
string | URL of the ZPL label, when one exists |
| label_ |
string | Always null |
| label_ |
string | Always null |
| label_ |
string | Always null |
| label_ |
string | Label file type. Ends in " - base64" when label_file holds the label |
| label_ |
string | The label itself, base64-encoded, when the shipment was bought with postage_label_inline. label_url is then null |
| label_ |
string | URL of the label in the format it was bought in |
| created_ |
datetime | When the label was created |
| updated_ |
datetime | When the label was last updated |
Options Object
Every option, across carriers:
{
"bag_number": "BAG-07",
"batch_number": "B-20261020-01",
"buzz_code": "1042",
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"delivery_instructions": "Leave with the concierge",
"driver_notes": "Leave at the front desk",
"duty_payment": {
"type": "THIRD_PARTY",
"account": "123456789",
"country": "US",
"postal_code": "10001"
},
"endorsement": "RETURN_SERVICE",
"fetch_express_delivery_date": true,
"hazmat": "LITHIUM",
"hub_id": 12,
"insurance_amount": 150.0,
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"machinable": false,
"pickup_begin_time": "2026-10-20T20:00:00",
"pickup_end_time": "2026-10-20T22:00:00",
"pickup_type": "LaserShip",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
],
"saturday_delivery": true,
"smartpost_hub": "5531",
"smartpost_manifest": "02912345",
"special_rates_eligibility": "USPS.MEDIAMAIL",
"total_value": 45.0
}
Options for USPS:
{
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"fetch_express_delivery_date": true,
"hazmat": "LITHIUM",
"insurance_amount": 150.0,
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"machinable": false,
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
],
"special_rates_eligibility": "USPS.MEDIAMAIL"
}
Options for FedEx:
{
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"duty_payment": {
"type": "THIRD_PARTY",
"account": "123456789",
"country": "US",
"postal_code": "10001"
},
"endorsement": "RETURN_SERVICE",
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
],
"saturday_delivery": true,
"smartpost_hub": "5531",
"smartpost_manifest": "02912345"
}
Options for UPS:
{
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"duty_payment": {
"type": "THIRD_PARTY",
"account": "123456789",
"country": "US",
"postal_code": "10001"
},
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
Options for UniUni:
{
"bag_number": "BAG-07",
"batch_number": "B-20261020-01",
"buzz_code": "1042",
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"driver_notes": "Leave at the front desk",
"hub_id": 12,
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
],
"total_value": 45.0
}
Options for OSM:
{
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
Options for OneParcel:
{
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
]
}
Options for DoorDash:
{
"create_and_buy": true,
"delivery_instructions": "Leave with the concierge",
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"pickup_begin_time": "2026-10-20T20:00:00",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
],
"total_value": 45.0
}
Options for OnTrac:
{
"carrier_insurance_amount": 150.0,
"create_and_buy": true,
"delivery_confirmation": "SIGNATURE",
"delivery_instructions": "Leave with the concierge",
"is_return": false,
"label_date": "2026-10-20T09:00:00-07:00",
"label_format": "PDF",
"label_size": "4X6",
"pickup_begin_time": "2026-10-20T20:00:00",
"pickup_end_time": "2026-10-20T22:00:00",
"pickup_type": "LaserShip",
"postage_label_inline": true,
"print_custom": [
{
"name": "Order",
"value": "1042"
}
],
"total_value": 45.0
}
Every option a shipment accepts. A badge marks an option only some carriers accept; pick a carrier to see just its options and values.
| Parameter | Type | Specification |
|---|---|---|
| bag_ UniUni
|
string | Bag number printed on the label. |
| batch_ UniUni
|
string | Batch to associate the shipment with. |
| buzz_ UniUni
|
string | Recipient's buzz code printed on the label. |
| carrier_ |
float | Declared value in USD, to buy the carrier's insurance. Cannot be combined with insurance_amount.
OnTracUsed ahead of
total_value.
|
| create_ |
boolean | Set to true to create and buy the label in one request, with the service sent beside it. |
| delivery_ |
string | Signature required at delivery.
USPS
NO_SIGNATUREdefault SIGNATURE ADULT_SIGNATURE SIGNATURE_RESTRICTED ADULT_SIGNATURE_RESTRICTED
OnTrac
NO_SIGNATUREdefault SIGNATURE ADULT_SIGNATURE ADULT_SIGNATURE_RESTRICTED
OnTrac
SIGNATURE_RESTRICTED is treated as NO_SIGNATURE.
|
| delivery_
DoorDashOnTrac
|
string | Instructions for the driver at the drop-off. |
| driver_ UniUni
|
string | Notes for the driver printed on the label. |
| duty_
FedExUPS
|
DutyPayment | Who pays duties and taxes on an international shipment. |
| endorsement FedEx
|
string | Ancillary endorsement for SmartPost.
Values
ADDRESS_CORRECTION CARRIER_LEAVE_IF_NO_RESPONSE CHANGE_SERVICE FORWARDING_SERVICE RETURN_SERVICE
|
| fetch_ USPS
|
boolean | Set to true to get the guaranteed delivery date for Express. |
| hazmat
USPSFedExUniUni
|
string | Hazardous materials in the package.
USPSFedEx
PRIMARY_CONTAINED PRIMARY_PACKED PRIMARY SECONDARY_CONTAINED SECONDARY_PACKED SECONDARY ORMD LIMITED_QUANTITY LITHIUM AIR_ELIGIBLE_ETHANOL CLASS_1 CLASS_3 CLASS_7 CLASS_8_CORROSIVE CLASS_8_WET_BATTERY CLASS_9_NEW_LITHIUM_INDIVIDUAL CLASS_9_USED_LITHIUM CLASS_9_NEW_LITHIUM_DEVICE CLASS_9_DRY_ICE CLASS_9_UNMARKED_LITHIUM CLASS_9_MAGNETIZED DIVISION_4_1 DIVISION_5_1 DIVISION_5_2 DIVISION_6_1 DIVISION_6_2 EXCEPTED_QUANTITY_PROVISION GROUND_ONLY ID8000 LIGHTERS SMALL_QUANTITY_PROVISION
UniUni
UN3481_LIBA UN3481_LICA UN3091_LMBA UN3091_LMCA UN3481_LIBG UN3481_LICG UN3091_LMBG UN3091_LMCG UN1993_NPRM UN1263_PAIN UN1170_SANI UN1266_PERF UN1170_MWAL UN1219_BWIP UN3295_ISWB UN3175_WWIP UN3175_PWIP UN1791_BSPR UN1950_FAMC UN1950_NAMC
|
| hazmat_
OSMOneParcel
|
integer | USPS hazardous-materials extra service code of the contents, from 810 to 832. |
| hub_ UniUni
|
integer | Pickup warehouse ID. Required. Values are in the hub sheet at docs.uniuni.com. |
| insurance_ USPS
|
float | Declared value in USD to buy shipment insurance. Cannot be combined with carrier_insurance_amount. |
| is_ |
boolean | Set to true to use the return service sub-type. |
| label_ |
string | Ship date printed on the label, as YYYY-MM-DD or an ISO 8601 datetime with a time zone offset. |
| label_ |
string | Label file format. Defaults to ZPL when the default label format at dashboard.vanlo.com/shipments is ZPL, and to PNG otherwise, as on a new account. A ZPL label cannot be converted later, such as into a PDF batch label.
Values
PNG PDF ZPL EPL2
|
| label_ |
string | Label size in inches. 8.5X11 prints the same label with blank space around it, for sheet printers.
Values
4X6default 8.5X11
|
| machinable USPS
|
boolean | Set to false to mark the package non-machinable. Applies to First. Default true. |
| pickup_
DoorDashOnTrac
|
string | When the package is ready for pickup.
DoorDashPrinted on the pickup instructions.
OnTracEarliest UTC time, such as
2026-07-28T20:00:00.
|
| pickup_ OnTrac
|
string | UTC time the package leaves the origin. Defaults to label_date, or to now. |
| pickup_ OnTrac
|
string | How the package reaches OnTrac.
Values
Nonedefaultyou hand it over LaserShipOnTrac collects it
|
| postage_ |
boolean | Set to true to get the label as base64 in label_file instead of a URL. |
| print_ |
PrintCustom[] | Custom text printed on the label. How many entries print depends on the carrier and service. |
| saturday_ FedEx
|
boolean | Set to true to request Saturday delivery. |
| smartpost_ FedEx
|
string | SmartPost hub ID. |
| smartpost_ FedEx
|
string | Accepted and returned in options, but not sent to FedEx. |
| special_ USPS
|
string | Request restricted rates.
Values
USPS.MEDIAMAIL USPS.LIBRARYMAIL
|
| total_
UniUniDoorDashOnTrac
|
float | Value of the contents in USD.
UniUniHelps with lost packages.
DoorDashPart of the price, so send it on every shipment.
OnTracThe declared value when
carrier_insurance_amount is not set.
|
PrintCustom Object
Custom text on a label:
[
{
"name": "Order",
"value": "1042"
}
]
| Parameter | Type | Specification |
|---|---|---|
| name | string | First part of text to print on label |
| value | string | Last part of text to print on label |
DutyPayment Object
Send the duties payer inside
options:
{
"shipment": {
"options": {
"duty_payment": {
"type": "BUYER"
}
}
}
}
A payer that bills another carrier account carries that account beside
type:
{
"shipment": {
"options": {
"duty_payment": {
"type": "THIRD_PARTY",
"account": "123456789",
"country": "US",
"postal_code": "10001"
}
}
}
}
duty_payment says who pays the duties and taxes on a FedEx or UPS shipment. Vanlo sends it to
the carrier only when the origin and destination are in different duties areas, such as the
United States and Canada. The United States, Puerto Rico, the US Virgin Islands and Guam are one
area, though Guam needs a customs declaration. American Samoa and the Northern Mariana Islands
are areas of their own.
| Value | Meaning | Also send |
|---|---|---|
| SENDER | The sender pays. Duties and taxes are billed to the carrier account that buys the label, which has to be your own account with the carrier. | Nothing |
| BUYER | The recipient pays the carrier on delivery. | Nothing |
| RECEIVER | The recipient's carrier account is billed. | account |
| THIRD_ |
A third-party carrier account is billed. | account and country, and postal_code when the account has one |
Rates
Get a Rate Quote
POST/api/v1/rate
curl -X POST https://www.vanlo.com/api/v1/rate \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"shipment": {
"to_address": {
"name": "John Doe",
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true
},
"from_address": {
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example"
},
"parcel": {
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
},
"carrier_accounts": [
"ca_..."
],
"options": {
"delivery_confirmation": "SIGNATURE"
}
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Rate.create(
to_address: {
name: 'John Doe',
street1: '148 W 51st St',
street2: 'Apt 4B',
city: 'New York',
state: 'NY',
zip: '10019',
country: 'US',
phone: '2125550199',
email: 'john.doe@example.com',
residential: true
},
from_address: {
name: 'Jane Smith',
company: 'Acme Goods',
street1: '417 Montgomery St',
street2: 'Floor 5',
city: 'San Francisco',
state: 'CA',
zip: '94104',
country: 'US',
phone: '4155550100',
email: 'shipping@acme.example'
},
parcel: {
length: 10.0,
width: 8.0,
height: 4.0,
weight: 32.0
},
carrier_accounts: ['ca_...'],
options: {
delivery_confirmation: 'SIGNATURE'
}
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
rates = vanlo.Rate.create(
to_address={
"name": "John Doe",
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": True
},
from_address={
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example"
},
parcel={
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
},
carrier_accounts=["ca_..."],
options={
"delivery_confirmation": "SIGNATURE"
}
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$rates = \Vanlo\Rate::create(array(
'to_address' => array(
'name' => 'John Doe',
'street1' => '148 W 51st St',
'street2' => 'Apt 4B',
'city' => 'New York',
'state' => 'NY',
'zip' => '10019',
'country' => 'US',
'phone' => '2125550199',
'email' => 'john.doe@example.com',
'residential' => true
),
'from_address' => array(
'name' => 'Jane Smith',
'company' => 'Acme Goods',
'street1' => '417 Montgomery St',
'street2' => 'Floor 5',
'city' => 'San Francisco',
'state' => 'CA',
'zip' => '94104',
'country' => 'US',
'phone' => '4155550100',
'email' => 'shipping@acme.example'
),
'parcel' => array(
'length' => 10.0,
'width' => 8.0,
'height' => 4.0,
'weight' => 32.0
),
'carrier_accounts' => array('ca_...'),
'options' => array(
'delivery_confirmation' => 'SIGNATURE'
)
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
List<Rate> rates = Rate.Create(new Dictionary<string, object>() {
{ "to_address", new Dictionary<string, object>() {
{ "name", "John Doe" },
{ "street1", "148 W 51st St" },
{ "street2", "Apt 4B" },
{ "city", "New York" },
{ "state", "NY" },
{ "zip", "10019" },
{ "country", "US" },
{ "phone", "2125550199" },
{ "email", "john.doe@example.com" },
{ "residential", true }
} },
{ "from_address", new Dictionary<string, object>() {
{ "name", "Jane Smith" },
{ "company", "Acme Goods" },
{ "street1", "417 Montgomery St" },
{ "street2", "Floor 5" },
{ "city", "San Francisco" },
{ "state", "CA" },
{ "zip", "94104" },
{ "country", "US" },
{ "phone", "4155550100" },
{ "email", "shipping@acme.example" }
} },
{ "parcel", new Dictionary<string, object>() {
{ "length", 10.0 },
{ "width", 8.0 },
{ "height", 4.0 },
{ "weight", 32.0 }
} },
{ "carrier_accounts", new List<string>() { "ca_..." } },
{ "options", new Dictionary<string, object>() {
{ "delivery_confirmation", "SIGNATURE" }
} }
});
Quotes rates for a shipment without creating one. The parameters are nested under shipment, as on Create a Shipment.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| shipment[to_ |
Address | Destination address (zip and country are required) |
| shipment[from_ |
Address | Origin address (zip and country are required) |
| shipment[parcel]required | Parcel | Package dimensions and weight |
| shipment[customs_ |
CustomsInfo | Customs declaration, or the id of a saved one, for an international quote |
| shipment[carrier] | string | Filter rates to a specific carrier |
| shipment[carrier_ |
string[] | One or more Carrier Account ids to get rates from |
| shipment[options] | Options | Shipping options that may affect rates, such as special_rates_eligibility or hazmat. On an international quote, send the same duty_payment you will send on the shipment. |
Returns
Response:
{
"rates": [
{
"id": "",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": null,
"created_at": null,
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": null,
"created_at": null,
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": null,
"created_at": null,
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
]
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "to_address",
"message": "is missing"
}
]
}
}
Response for
INVALID_OPTIONS:
{
"error": {
"code": "INVALID_OPTIONS",
"message": "Invalid options. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "options",
"message": "delivery_confirmation must be one of: NO_SIGNATURE, SIGNATURE, ADULT_SIGNATURE, SIGNATURE_RESTRICTED, ADULT_SIGNATURE_RESTRICTED"
}
]
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns an object with rates, an array of Rate. A quoted rate has an empty id and null shipment_id and created_at, so it cannot be bought: create a shipment to buy one.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A required field is missing or has the wrong shape, such as no to_address or a parcel without weight, or no carrier account matches carrier_accounts. error.errors names each field. |
INVALID_ |
422 | An options value is not allowed for the shipment, such as an unknown delivery_confirmation or a duty_payment with an unknown type. |
NOT_ |
404 | No carrier could rate the shipment. A carrier that cannot rate it is left out of the results, so this means none could. |
Addresses
Address Object
An Address verified on creation:
{
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": false,
"verifications": {
"delivery": {
"success": true,
"errors": [],
"details": {
"latitude": 37.79342,
"longitude": -122.40288,
"time_zone": "America/Los_Angeles"
}
},
"verify": [
"delivery"
]
}
}
A postal address, used as a shipment's origin, destination, return or buyer address.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "adr_" |
| object | string | "Address" |
| name | string | Name of the person or contact |
| company | string | Company name associated with the address |
| street1 | string | First line of the street address |
| street2 | string | Second line of the street address |
| city | string | City |
| state | string | State or province (2-letter code for US, CA, AU) |
| zip | string | Zip or postal code |
| country | string | Two-letter ISO 3166 country code |
| phone | string | Phone number associated with the address |
| string | Email address | |
| residential | boolean | Whether the address is a residential address |
| verifications | object | One { success, errors, details } result per check you asked for, keyed delivery or zip4, and verify listing the checks. Null when the address was not verified |
| created_ |
datetime | When the address was created |
| updated_ |
datetime | When the address was last updated |
Create an Address
POST/api/v1/addresses
curl -X POST https://www.vanlo.com/api/v1/addresses \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"address": {
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": false
},
"verify": [
"delivery"
]
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Address.create(
name: 'Jane Smith',
company: 'Acme Goods',
street1: '417 Montgomery St',
street2: 'Floor 5',
city: 'San Francisco',
state: 'CA',
zip: '94104',
country: 'US',
phone: '4155550100',
email: 'shipping@acme.example',
residential: false,
verify: ['delivery']
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
address = vanlo.Address.create(
name="Jane Smith",
company="Acme Goods",
street1="417 Montgomery St",
street2="Floor 5",
city="San Francisco",
state="CA",
zip="94104",
country="US",
phone="4155550100",
email="shipping@acme.example",
residential=False,
verify=["delivery"]
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$address = \Vanlo\Address::create(array(
'name' => 'Jane Smith',
'company' => 'Acme Goods',
'street1' => '417 Montgomery St',
'street2' => 'Floor 5',
'city' => 'San Francisco',
'state' => 'CA',
'zip' => '94104',
'country' => 'US',
'phone' => '4155550100',
'email' => 'shipping@acme.example',
'residential' => false,
'verify' => array('delivery')
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Address address = Address.Create(new Dictionary<string, object>() {
{ "name", "Jane Smith" },
{ "company", "Acme Goods" },
{ "street1", "417 Montgomery St" },
{ "street2", "Floor 5" },
{ "city", "San Francisco" },
{ "state", "CA" },
{ "zip", "94104" },
{ "country", "US" },
{ "phone", "4155550100" },
{ "email", "shipping@acme.example" },
{ "residential", false },
{ "verify", new List<string>() { "delivery" } }
});
Creates an address, and verifies it when verify or verify_strict is sent. The fields go inside address; verify and verify_strict sit beside it.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| name | string | Name of the person or contact |
| company | string | Company name associated with the address |
| street1 | string | First line of the street address |
| street2 | string | Second line of the street address |
| city | string | City |
| state | string | State or province (2-letter code for US, CA, AU) |
| zip | string | Zip or postal code |
| country | string | Two-letter ISO 3166 country code |
| phone | string | Phone number |
| string | Email address | |
| residential | boolean | Whether the address is residential |
| verify | string[] | Set to ["delivery"], or ["delivery", "zip4"] for a US address, to verify the address on creation. The address is saved even when it cannot be verified, with the problems in verifications. |
| verify_ |
string[] | Takes the same values as verify, but requires a clean verification. An address that cannot be verified is not saved. |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "zip",
"message": "Invalid ZIP code format. US ZIP codes must be 5 digits (e.g., 90210) or 5+4 format (e.g., 90210-1234)."
}
]
}
}
Response for
CARRIER_REJECTED_ADDRESS:
{
"error": {
"code": "CARRIER_REJECTED_ADDRESS",
"message": "The address could not be verified. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "address",
"message": "Address not found"
},
{
"field": "street1",
"message": "House number is missing"
}
]
}
}
Response for
PROVIDER_503:
{
"error": {
"code": "PROVIDER_503",
"message": "No response from service provider, please try again or contact support. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Address, with the results in verifications when verification was requested.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A field is missing or invalid, or the verification provider rejected the request. error.errors names each field. |
CARRIER_ |
422 | With verify_strict, the address could not be verified. error.errors lists the problems. |
PROVIDER_ |
503 | The address verification provider did not respond. |
Retrieve an Address
GET/api/v1/addresses/:id
curl https://www.vanlo.com/api/v1/addresses/adr_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Address.retrieve('adr_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Address.retrieve('adr_...')
require_once("/path/to/lib/vanlo.php");
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
\Vanlo\Address::retrieve('adr_...');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Address address = Address.Retrieve("adr_...");
Retrieves an address by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the address |
Returns
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Address.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No address of yours has this id. |
Parcels
Parcel Object
A Parcel:
{
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
}
The dimensions and weight of one package. Send a predefined_package when shipping in carrier-supplied packaging.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "prcl_" |
| object | string | "Parcel" |
| length | float | Length of the parcel in inches |
| width | float | Width of the parcel in inches |
| height | float | Height of the parcel in inches |
| weight | float | Weight of the parcel in ounces |
| predefined_ |
string | Carrier predefined package type, if applicable |
| created_ |
datetime | When the parcel was created |
| updated_ |
datetime | When the parcel was last updated |
Create a Parcel
POST/api/v1/parcels
curl -X POST https://www.vanlo.com/api/v1/parcels \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"parcel": {
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Parcel.create(
length: 10.0,
width: 8.0,
height: 4.0,
weight: 32.0
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
parcel = vanlo.Parcel.create(
length=10.0,
width=8.0,
height=4.0,
weight=32.0
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$parcel = \Vanlo\Parcel::create(array(
'length' => 10.0,
'width' => 8.0,
'height' => 4.0,
'weight' => 32.0
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Parcel parcel = Parcel.Create(new Dictionary<string, object>() {
{ "length", 10.0 },
{ "width", 8.0 },
{ "height", 4.0 },
{ "weight", 32.0 }
});
Creates a parcel. Its id can stand in for the parcel on any later shipment.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| length | float | Length of the parcel in inches |
| width | float | Width of the parcel in inches |
| height | float | Height of the parcel in inches |
| weight | float | Weight of the parcel in ounces |
| predefined_ |
string | Carrier predefined package type |
| Package Type | Description |
|---|---|
| Card | Postcard or greeting card |
| Letter | Standard letter envelope |
| Flat | Large envelope or flat |
| SoftPack | Padded or poly mailer |
| Parcel | Standard parcel |
| LargeParcel | Large parcel (over 1 cubic foot) |
| IrregularParcel | Non-rectangular parcel |
| FlatRateEnvelope | USPS Flat Rate Envelope |
| FlatRateLegalEnvelope | USPS Flat Rate Legal Envelope |
| FlatRatePaddedEnvelope | USPS Flat Rate Padded Envelope |
| FlatRateGiftCardEnvelope | USPS Flat Rate Gift Card Envelope |
| FlatRateWindowEnvelope | USPS Flat Rate Window Envelope |
| FlatRateCardboardEnvelope | USPS Flat Rate Cardboard Envelope |
| SmallFlatRateEnvelope | USPS Small Flat Rate Envelope |
| SmallFlatRateBox | USPS Small Flat Rate Box |
| MediumFlatRateBox | USPS Medium Flat Rate Box |
| LargeFlatRateBox | USPS Large Flat Rate Box |
| LargeFlatRateBoxAPOFPO | USPS Large Flat Rate Box (APO/FPO/DPO) |
| RegionalRateBoxA | USPS Regional Rate Box A |
| RegionalRateBoxB | USPS Regional Rate Box B |
| Package Type | Description |
|---|---|
| FedExEnvelope | FedEx Envelope |
| FedExBox | FedEx Box |
| FedExPak | FedEx Pak |
| FedExTube | FedEx Tube |
| FedEx10kgBox | FedEx 10kg Box |
| FedEx25kgBox | FedEx 25kg Box |
| FedExSmallBox | FedEx Small Box |
| FedExMediumBox | FedEx Medium Box |
| FedExLargeBox | FedEx Large Box |
| FedExExtraLargeBox | FedEx Extra Large Box |
| Package Type | Description |
|---|---|
| UPSLetter | UPS Letter |
| Tube | UPS Tube |
| Pak | UPS Pak |
| UPSExpressBox | UPS Express Box |
| SmallExpressBox | UPS Small Express Box |
| MediumExpressBox | UPS Medium Express Box |
| LargeExpressBox | UPS Large Express Box |
| UPS10kgBox | UPS 10kg Box |
| UPS25kgBox | UPS 25kg Box |
| Pallet | Pallet |
| BPMParcel | Bound Printed Matter Parcel |
| BPMFlat | Bound Printed Matter Flat |
| Flat | Flat |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "weight",
"message": "Package weight must be greater than 0. Please enter a valid weight."
}
]
}
}
Returns the Parcel.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A field is missing or invalid, such as no weight or a weight of 0. error.errors names each field. |
Retrieve a Parcel
GET/api/v1/parcels/:id
curl https://www.vanlo.com/api/v1/parcels/prcl_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Parcel.retrieve("prcl_...")
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Parcel.retrieve("prcl_...")
require_once("/path/to/lib/vanlo.php");
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
\Vanlo\Parcel::retrieve("prcl_...");
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Parcel parcel = Parcel.Retrieve("prcl_...");
Retrieves a parcel by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the parcel |
Returns
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Parcel.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No parcel of yours has this id. |
CustomsInfos
CustomsInfo Object
A CustomsInfo:
{
"id": "cstinfo_...",
"object": "CustomsInfo",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"contents_type": "merchandise",
"contents_explanation": null,
"customs_certify": true,
"customs_signer": "Jane Smith",
"eel_pfc": "NOEEI 30.37(a)",
"non_delivery_option": "return",
"restriction_comments": null,
"restriction_type": "none",
"customs_items": [
{
"description": "Cotton T-shirt",
"quantity": 2,
"value": 30.0,
"weight": 12.0,
"currency": "USD",
"hs_tariff_number": "610910",
"code": "TSHIRT-M-BLU",
"origin_country": "US"
},
{
"description": "Ceramic mug",
"quantity": 1,
"value": 14.0,
"weight": 18.0,
"currency": "USD",
"hs_tariff_number": "691200",
"code": "MUG-11OZ",
"origin_country": "CN"
}
]
}
The customs declaration for an international shipment, or one to an APO/FPO/DPO address, with a CustomsItem for each kind of goods.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "cstinfo_" |
| object | string | "CustomsInfo" |
| contents_ |
string | Type of item being shipped: "documents", "gift", "merchandise", "returned_goods", "sample", or "other" |
| contents_ |
string | Human-readable description of content, required if contents_type is "other" |
| customs_ |
boolean | Whether the customs form has been signed by the customs_signer |
| customs_ |
string | Name of the person signing the customs form |
| eel_ |
string | Electronic Export License or PFC number. For items valued under $2,500 use "NOEEI 30.37(a)" |
| non_ |
string | Action to take if the package cannot be delivered: "abandon" or "return" (default) |
| restriction_ |
string | Additional comments for restricted shipments, required if restriction_type is "other" |
| restriction_ |
string | Type of restriction: "none", "other", "quarantine", or "sanitary_phytosanitary_inspection" |
| customs_ |
CustomsItem[] | Array of CustomsItem objects describing the contents |
| created_ |
datetime | When the customs info was created |
| updated_ |
datetime | When the customs info was last updated |
Create a CustomsInfo
POST/api/v1/customs_infos
curl -X POST https://www.vanlo.com/api/v1/customs_infos \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"customs_info": {
"contents_type": "merchandise",
"customs_certify": true,
"customs_signer": "Jane Smith",
"eel_pfc": "NOEEI 30.37(a)",
"non_delivery_option": "return",
"restriction_type": "none",
"customs_items": [
{
"description": "Cotton T-shirt",
"quantity": 2,
"value": 30.0,
"weight": 12.0,
"currency": "USD",
"hs_tariff_number": "610910",
"code": "TSHIRT-M-BLU",
"origin_country": "US"
},
{
"description": "Ceramic mug",
"quantity": 1,
"value": 14.0,
"weight": 18.0,
"currency": "USD",
"hs_tariff_number": "691200",
"code": "MUG-11OZ",
"origin_country": "CN"
}
]
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::CustomsInfo.create(
contents_type: 'merchandise',
customs_certify: true,
customs_signer: 'Jane Smith',
eel_pfc: 'NOEEI 30.37(a)',
non_delivery_option: 'return',
restriction_type: 'none',
customs_items: [
{
description: 'Cotton T-shirt',
quantity: 2,
value: 30.0,
weight: 12.0,
currency: 'USD',
hs_tariff_number: '610910',
code: 'TSHIRT-M-BLU',
origin_country: 'US'
},
{
description: 'Ceramic mug',
quantity: 1,
value: 14.0,
weight: 18.0,
currency: 'USD',
hs_tariff_number: '691200',
code: 'MUG-11OZ',
origin_country: 'CN'
}
]
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
customs_info = vanlo.CustomsInfo.create(
contents_type="merchandise",
customs_certify=True,
customs_signer="Jane Smith",
eel_pfc="NOEEI 30.37(a)",
non_delivery_option="return",
restriction_type="none",
customs_items=[
{
"description": "Cotton T-shirt",
"quantity": 2,
"value": 30.0,
"weight": 12.0,
"currency": "USD",
"hs_tariff_number": "610910",
"code": "TSHIRT-M-BLU",
"origin_country": "US"
},
{
"description": "Ceramic mug",
"quantity": 1,
"value": 14.0,
"weight": 18.0,
"currency": "USD",
"hs_tariff_number": "691200",
"code": "MUG-11OZ",
"origin_country": "CN"
}
]
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$customs_info = \Vanlo\CustomsInfo::create(array(
'contents_type' => 'merchandise',
'customs_certify' => true,
'customs_signer' => 'Jane Smith',
'eel_pfc' => 'NOEEI 30.37(a)',
'non_delivery_option' => 'return',
'restriction_type' => 'none',
'customs_items' => array(
array(
'description' => 'Cotton T-shirt',
'quantity' => 2,
'value' => 30.0,
'weight' => 12.0,
'currency' => 'USD',
'hs_tariff_number' => '610910',
'code' => 'TSHIRT-M-BLU',
'origin_country' => 'US'
),
array(
'description' => 'Ceramic mug',
'quantity' => 1,
'value' => 14.0,
'weight' => 18.0,
'currency' => 'USD',
'hs_tariff_number' => '691200',
'code' => 'MUG-11OZ',
'origin_country' => 'CN'
)
)
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
CustomsInfo customsInfo = CustomsInfo.Create(new Dictionary<string, object>() {
{ "contents_type", "merchandise" },
{ "customs_certify", true },
{ "customs_signer", "Jane Smith" },
{ "eel_pfc", "NOEEI 30.37(a)" },
{ "non_delivery_option", "return" },
{ "restriction_type", "none" },
{ "customs_items", new List<Dictionary<string, object>>() {
new Dictionary<string, object>() {
{ "description", "Cotton T-shirt" },
{ "quantity", 2 },
{ "value", 30.0 },
{ "weight", 12.0 },
{ "currency", "USD" },
{ "hs_tariff_number", "610910" },
{ "code", "TSHIRT-M-BLU" },
{ "origin_country", "US" }
},
new Dictionary<string, object>() {
{ "description", "Ceramic mug" },
{ "quantity", 1 },
{ "value", 14.0 },
{ "weight", 18.0 },
{ "currency", "USD" },
{ "hs_tariff_number", "691200" },
{ "code", "MUG-11OZ" },
{ "origin_country", "CN" }
}
} }
});
Creates a customs declaration. Its id can stand in for customs_info on any later shipment.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| eel_ |
string | Electronic Export License or PFC number. For items valued under $2,500 use "NOEEI 30.37(a)" |
| contents_ |
string | "documents", "gift", "merchandise", "returned_goods", "sample", or "other" |
| contents_ |
string | Description of goods, required when contents_type is "other" |
| customs_ |
boolean | Whether the customs form has been signed |
| customs_ |
string | Name of the person signing the customs form |
| restriction_ |
string | "none", "other", "quarantine", or "sanitary_phytosanitary_inspection" |
| restriction_ |
string | Additional comments, required when restriction_type is "other" |
| non_ |
string | "abandon" or "return" (default) |
| customs_ |
CustomsItem[] | Array of CustomsItem objects describing the contents |
Returns
Response for
PARAMETER.REQUIRED:
{
"error": {
"code": "PARAMETER.REQUIRED",
"message": "Missing required parameter: customs_items. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Invalid parameters were passed and the record could not be persisted. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "contents_type",
"message": "is not included in the list"
}
]
}
}
Returns the CustomsInfo.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
PARAMETER.REQUIRED |
422 |
customs_items is missing. |
BAD_ |
400 | A value cannot be saved, such as an unknown contents_type. error.errors names each field. |
Nested Objects
Objects a CustomsInfo carries. Each one also expands in place wherever a table names it.
CustomsItem Object
A CustomsItem:
{
"description": "Cotton T-shirt",
"quantity": 2,
"value": 30.0,
"weight": 12.0,
"currency": "USD",
"hs_tariff_number": "610910",
"code": "TSHIRT-M-BLU",
"origin_country": "US"
}
| Parameter | Type | Specification |
|---|---|---|
| description | string | Human-readable description of the item. Required |
| hs_ |
string | Harmonized System tariff code for the item, 6 to 15 letters and digits. Separators such as dots are ignored. A UPS international shipment requires it on every item |
| origin_ |
string | Two-letter ISO 3166 country code of the item's origin. Defaults to "US" |
| quantity | integer | Number of items. Required |
| value | float | Total value of the items, in currency. Required |
| weight | float | Total weight of the items in ounces. Required |
| currency | string | Three-letter currency code of value. Defaults to "USD" |
| code | string | Your SKU or product code for the item |
Batches
Batch Object
A purchased Batch with its combined label and scan form:
{
"id": "batch_...",
"object": "Batch",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../batch_labels.pdf",
"num_shipments": 2,
"state": "label_generated",
"scan_form": {
"id": "sf_...",
"object": "ScanForm",
"tracking_codes": [
"9405500106024190341287",
"9405500106024190341294"
],
"address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"message": null,
"batch_id": "batch_...",
"form": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp...",
"reference": null,
"status": "ready",
"form_url": "https://www.vanlo.com/rails/active_storage/blobs/proxy/.../scan_form.pdf",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z"
},
"shipments": [
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341287"
},
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341294"
}
],
"status": {
"created": 0,
"queued_for_purchase": 0,
"creation_failed": 0,
"postage_purchased": 2,
"postage_purchase_failed": 0
},
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z"
}
A group of shipments bought, labelled and scanned together. Each step runs in the background and sends a webhook Event when it finishes.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "batch_" |
| object | string | "Batch" |
| state | string | Current state of the batch: "creating", "created", "purchasing", "purchased", "purchase_failed", "label_generating", or "label_generated" |
| status | BatchStatus | Counts of shipments in each processing state |
| num_ |
integer | Total number of shipments in the batch |
| scan_ |
ScanForm | The associated ScanForm object, if generated |
| shipments | BatchShipment[] | Array of BatchShipment objects with per-shipment status |
| label_ |
string | URL of the combined label file, once generated |
| created_ |
datetime | When the batch was created |
| updated_ |
datetime | When the batch was last updated |
Create a Batch
POST/api/v1/batches
curl -X POST https://www.vanlo.com/api/v1/batches \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"batch": {
"shipments": [
{
"id": "shp_..."
},
{
"id": "shp_...",
"carrier": "USPS",
"service": "GroundAdvantage"
}
]
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
batch = Vanlo::Batch.create(
shipments: [
{
id: 'shp_...'
},
{
id: 'shp_...',
carrier: 'USPS',
service: 'GroundAdvantage'
}
]
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
batch = vanlo.Batch.create(
shipments=[
{
"id": "shp_..."
},
{
"id": "shp_...",
"carrier": "USPS",
"service": "GroundAdvantage"
}
]
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$batch = \Vanlo\Batch::create(array(
'shipments' => array(
array(
'id' => 'shp_...'
),
array(
'id' => 'shp_...',
'carrier' => 'USPS',
'service' => 'GroundAdvantage'
)
)
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Batch batch = Batch.Create(new Dictionary<string, object>() {
{ "shipments", new List<Dictionary<string, object>>() {
new Dictionary<string, object>() {
{ "id", "shp_..." }
},
new Dictionary<string, object>() {
{ "id", "shp_..." },
{ "carrier", "USPS" },
{ "service", "GroundAdvantage" }
}
} }
});
Creates a batch from shipments you already created, sent by id. A webhook Event is sent once its state is created.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| shipments | object[] | 1 to 100 shipments, each as { "id": "shp_..." }. An entry may add carrier and service to change the rate it is bought at |
Returns
Response for
PARAMETER.REQUIRED:
{
"error": {
"code": "PARAMETER.REQUIRED",
"message": "Missing required parameter: shipments. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "id",
"message": "is missing"
}
]
}
}
Response for
UNPROCESSABLE_ENTITY:
{
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "One or more shipments is required to perform this action. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Batch in state created, or purchased when every shipment already has a label.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
PARAMETER.REQUIRED |
422 |
shipments is missing. |
BAD_ |
400 | A shipment entry has no id, or there are more than 100. error.errors names each field. |
UNPROCESSABLE_ |
422 | None of the ids is a shipment of yours, or the batch could not be created. error.message says why. |
Buy a Batch
POST/api/v1/batches/:id/buy
curl -X POST https://www.vanlo.com/api/v1/batches/batch_.../buy \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
batch = Vanlo::Batch.retrieve('batch_...')
batch.buy
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
batch = vanlo.Batch.retrieve('batch_...')
batch.buy()
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$batch = \Vanlo\Batch::retrieve('batch_...');
$batch->buy();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Batch batch = Batch.Retrieve("batch_...");
batch.Buy();
Buys a label for every shipment in a batch, in the background. The batch must be in the created state, and a webhook Event is sent when every shipment has been processed.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the batch to purchase |
Returns
Response for
UNPROCESSABLE_ENTITY:
{
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "This batch is either already purchased or currently being purchased. If purchasing fails please try again at a later time. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Batch in the purchasing state.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
UNPROCESSABLE_ |
422 | The batch is already purchased or being purchased, or one of its shipments failed to be created. |
NOT_ |
404 | No batch of yours has this id. |
Create Batch Labels
POST/api/v1/batches/:id/label
curl -X POST https://www.vanlo.com/api/v1/batches/batch_.../label \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"file_format": "zpl"
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
batch = Vanlo::Batch.retrieve('batch_...')
batch.label(file_format: 'zpl')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
batch = vanlo.Batch.retrieve('batch_...')
batch.label(file_format = 'zpl')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$batch = \Vanlo\Batch::retrieve('batch_...');
$batch->label(array('file_format' => 'zpl'));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Batch batch = Batch.Retrieve("batch_...");
batch.GenerateLabel("zpl");
Combines the labels of every shipment in a bought batch into one file, in the background. A webhook Event is sent when label_url is ready.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| file_ |
string | Combined file format: "pdf", "zpl", or "zip" |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "One or more of the shipments don't have postage associated to them. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Batch; label_url is filled in once the file is ready.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A shipment in the batch has no label yet, or file_format is missing or not one of the listed values. |
NOT_ |
404 | No batch of yours has this id. |
Create a Batch ScanForm
POST/api/v1/batches/:id/scan_form
curl -X POST https://www.vanlo.com/api/v1/batches/batch_.../scan_form \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
batch = Vanlo::Batch.retrieve('batch_...')
batch.create_scan_form
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
batch = vanlo.Batch.retrieve('batch_...')
batch.create_scan_form()
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$batch = \Vanlo\Batch::retrieve('batch_...');
$batch->create_scan_form();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Batch batch = Batch.Retrieve("batch_...");
batch.GenerateScanForm();
Creates a ScanForm for every shipment in a bought batch.
Parameters
This call takes no parameters.
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "One or more of the shipments don't have postage associated to them. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
LOCKED:
{
"error": {
"code": "LOCKED",
"message": "Another resource is creating at the moment. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Batch with its scan_form.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A shipment in the batch has no label yet, or a shipment cannot go on a scan form, such as one already on another. error.details lists the scan-form ids involved. |
LOCKED |
429 | A scan form for this batch is already being created. |
NOT_ |
404 | No batch of yours has this id. |
Retrieve a Batch
GET/api/v1/batches/:id
curl https://www.vanlo.com/api/v1/batches/batch_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Batch.retrieve('batch_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Batch.retrieve('batch_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$batch = \Vanlo\Batch::retrieve('batch_...');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Batch batch = Batch.Retrieve("batch_...");
Retrieves a batch by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the batch |
Returns
Response:
{
"id": "batch_...",
"object": "Batch",
"label_url": null,
"num_shipments": 2,
"state": "purchased",
"scan_form": null,
"shipments": [
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341287"
},
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341294"
}
],
"status": {
"created": 0,
"queued_for_purchase": 0,
"creation_failed": 0,
"postage_purchased": 2,
"postage_purchase_failed": 0
},
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z"
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Batch.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No batch of yours has this id. |
Nested Objects
Objects a Batch carries. Each one also expands in place wherever a table names it.
BatchStatus Object
A BatchStatus:
{
"created": 0,
"queued_for_purchase": 0,
"creation_failed": 0,
"postage_purchased": 2,
"postage_purchase_failed": 0
}
| Parameter | Type | Specification |
|---|---|---|
| created | integer | Number of shipments that have been created but not yet queued |
| queued_ |
integer | Number of shipments queued for postage purchase |
| creation_ |
integer | Number of shipments that failed to be created |
| postage_ |
integer | Number of shipments with postage successfully purchased |
| postage_ |
integer | Number of shipments where postage purchase failed |
BatchShipment Object
A BatchShipment:
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341287"
}
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the shipment, begins with "shp_" |
| batch_ |
string | Status of the shipment within the batch: "created", "queued_for_purchase", "postage_purchased", or "postage_purchase_failed" |
| batch_ |
string | Error message if the shipment failed during batch processing |
| tracking_ |
string | Tracking code for the shipment, if purchased |
ScanForms
ScanForm Object
A ScanForm:
{
"id": "sf_...",
"object": "ScanForm",
"tracking_codes": [
"9405500106024190341287",
"9405500106024190341294"
],
"address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"message": null,
"batch_id": null,
"form": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp...",
"reference": "order-1042",
"status": "ready",
"form_url": "https://www.vanlo.com/rails/active_storage/blobs/proxy/.../scan_form.pdf",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z"
}
A carrier manifest that lets the carrier scan many packages with one barcode at pickup.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "sf_" |
| object | string | "ScanForm" |
| tracking_ |
string[] | Array of tracking codes included in the scan form |
| address | Address | The Address that the scan form applies to |
| status | string | Current status of the scan form: "pending", "ready", or "failed" |
| message | string | Error message if the scan form failed to generate |
| warnings | object | Shipments left off a ready scan form: each shipment id maps to a list of the reasons. Present only when there are some |
| form_ |
string | URL of the scan form PDF document |
| form | string | Base64-encoded scan form document, if available |
| batch_ |
string | Identifier of the associated Batch, begins with "batch_" |
| reference | string | Arbitrary reference string for the scan form |
| created_ |
datetime | When the scan form was created |
| updated_ |
datetime | When the scan form was last updated |
Create a ScanForm
POST/api/v1/scan_forms
curl -X POST https://www.vanlo.com/api/v1/scan_forms \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"shipments": [
{
"id": "shp_..."
},
{
"id": "shp_..."
}
],
"carrier": "USPS"
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
scan_form = Vanlo::ScanForm.create(
shipments: [
{
id: 'shp_...'
},
{
id: 'shp_...'
}
],
carrier: 'USPS'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
scan_form = vanlo.ScanForm.create(
shipments=[
{
"id": "shp_..."
},
{
"id": "shp_..."
}
],
carrier="USPS"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$scan_form = \Vanlo\ScanForm::create(array(
'shipments' => array(
array(
'id' => 'shp_...'
),
array(
'id' => 'shp_...'
)
),
'carrier' => 'USPS'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
ScanForm scanForm = ScanForm.Create(new Dictionary<string, object>() {
{ "shipments", new List<Dictionary<string, object>>() {
new Dictionary<string, object>() {
{ "id", "shp_..." }
},
new Dictionary<string, object>() {
{ "id", "shp_..." }
}
} },
{ "carrier", "USPS" }
});
Creates a scan form for one or more purchased shipments, named by id or by reference. To scan a whole batch, use Create a Batch ScanForm.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| shipments | object[] | The shipments to include, each as { "id": "shp_..." }
|
| reference | string | Instead of shipments, include today's shipments with this reference, or * for all of today's shipments. Shipments already on a scan form are left out |
| up_ |
datetime | With reference, only include shipments created before this time. Defaults to now |
| carrier | string |
USPS, the default. Scan forms are not available for other carriers |
Returns
Response for
PARAMETER.REQUIRED:
{
"error": {
"code": "PARAMETER.REQUIRED",
"message": "Missing required parameter: shipments. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "All shipments on a Scan Form must ship from the same warehouse address. Please select shipments from a single location. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "ScanForm",
"message": "All shipments on a Scan Form must ship from the same warehouse address. Please select shipments from a single location."
}
],
"details": {
"from_address_ids": [
"adr_...",
"adr_..."
]
}
}
}
Response for
LOCKED:
{
"error": {
"code": "LOCKED",
"message": "Another resource is creating at the moment. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the ScanForm.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
PARAMETER.REQUIRED |
422 | Neither shipments nor reference is sent. |
BAD_ |
400 | No shipment is eligible, the shipments cannot share a scan form, such as ones from different origin addresses, or the carrier has no scan forms. error.details holds any ids involved. |
LOCKED |
429 | A scan form is already being created for these shipments. |
Create a ScanForm for All Eligible Shipments
POST/api/v1/scan_forms/all
curl -X POST https://www.vanlo.com/api/v1/scan_forms/all \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"reference": "*",
"up_to_time": "2026-10-20T17:00:00-04:00",
"carrier": "USPS"
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
scan_form = Vanlo::ScanForm.create_all(
reference: '*',
up_to_time: '2026-10-20T17:00:00-04:00',
carrier: 'USPS'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
scan_form = vanlo.ScanForm.create_all(
reference="*",
up_to_time="2026-10-20T17:00:00-04:00",
carrier="USPS"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$scan_form = \Vanlo\ScanForm::create_all(array(
'reference' => '*',
'up_to_time' => '2026-10-20T17:00:00-04:00',
'carrier' => 'USPS'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
ScanForm scanForm = ScanForm.CreateAll(new Dictionary<string, object>() {
{ "reference", "*" },
{ "up_to_time", "2026-10-20T17:00:00-04:00" },
{ "carrier", "USPS" }
});
The same call as Create a ScanForm at another path. Send reference as * to include every shipment created today that is not yet on a scan form.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| reference | string | A shipment reference to include today's shipments with it, or * for all of them |
| up_ |
datetime | Only include shipments created before this time. Defaults to now |
| carrier | string |
USPS, the default. Scan forms are not available for other carriers |
| shipments | object[] | Shipments by id, as on Create a ScanForm |
Returns
Response for
PARAMETER.REQUIRED:
{
"error": {
"code": "PARAMETER.REQUIRED",
"message": "Missing required parameter: shipments. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "All shipments on a Scan Form must ship from the same warehouse address. Please select shipments from a single location. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "ScanForm",
"message": "All shipments on a Scan Form must ship from the same warehouse address. Please select shipments from a single location."
}
],
"details": {
"from_address_ids": [
"adr_...",
"adr_..."
]
}
}
}
Response for
LOCKED:
{
"error": {
"code": "LOCKED",
"message": "Another resource is creating at the moment. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the ScanForm.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
PARAMETER.REQUIRED |
422 | Neither shipments nor reference is sent. |
BAD_ |
400 | No shipment is eligible, the shipments cannot share a scan form, such as ones from different origin addresses, or the carrier has no scan forms. error.details holds any ids involved. |
LOCKED |
429 | A scan form is already being created for these shipments. |
List ScanForms
GET/api/v1/scan_forms
curl -G https://www.vanlo.com/api/v1/scan_forms \
-H 'Authorization: Bearer VANLO_API_KEY' \
-d 'page_size=2' \
-d 'reference=order-1042'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::ScanForm.all(
page_size: 2,
reference: 'order-1042'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.ScanForm.all(
page_size=2,
reference="order-1042"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$scan_forms = \Vanlo\ScanForm::all(array(
'page_size' => 2,
'reference' => 'order-1042'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
ScanFormList scanFormList = ScanForm.List(new Dictionary<string, object>() {
{ "page_size", 2 },
{ "reference", "order-1042" }
});
Lists your scan forms a page at a time. Pass before_id or after_id to say where the next page begins.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| before_ |
string | Return scan forms created before this id |
| after_ |
string | Return scan forms created after this id |
| start_ |
datetime | Only return scan forms created after this timestamp |
| end_ |
datetime | Only return scan forms created before this timestamp |
| page_ |
integer | Number of scan forms to return per page (default 20, max 100) |
| reference | string | Only return scan forms with this reference |
Returns
Response:
{
"scan_forms": [
{
"id": "sf_...",
"object": "ScanForm",
"tracking_codes": [
"9405500106024190341287"
],
"address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"message": null,
"warnings": {
"shp_...": [
"This shipment is already in_transit and cannot be added to a Scan Form."
]
},
"batch_id": null,
"form": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp...",
"reference": "order-1042",
"status": "ready",
"form_url": "https://www.vanlo.com/rails/active_storage/blobs/proxy/.../scan_form.pdf",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z"
},
{
"id": "sf_...",
"object": "ScanForm",
"tracking_codes": [
"9405500106024190327715"
],
"address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"message": null,
"batch_id": null,
"form": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp...",
"reference": "order-1042",
"status": "ready",
"form_url": "https://www.vanlo.com/rails/active_storage/blobs/proxy/.../scan_form.pdf",
"created_at": "2026-10-19T21:10:05Z",
"updated_at": "2026-10-19T21:10:05Z"
}
],
"has_more": true
}
Returns an object with scan_forms, an array of ScanForm, and has_more, which says whether another page exists.
On failure it returns one of the common errors; this call has none of its own.
Retrieve a ScanForm
GET/api/v1/scan_forms/:id
curl https://www.vanlo.com/api/v1/scan_forms/sf_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::ScanForm.retrieve('sf_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.ScanForm.retrieve('sf_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$scan_form = \Vanlo\ScanForm::retrieve('sf_...')
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
ScanForm otherScanForm = ScanForm.Retrieve("sf_...");
Retrieves a scan form by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the scan form |
Returns
Response:
{
"id": "sf_...",
"object": "ScanForm",
"tracking_codes": [
"9405500106024190341287",
"9405500106024190341294"
],
"address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"message": null,
"batch_id": null,
"form": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp...",
"reference": "order-1042",
"status": "ready",
"form_url": "https://www.vanlo.com/rails/active_storage/blobs/proxy/.../scan_form.pdf",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z"
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the ScanForm.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No scan form of yours has this id. |
Orders
Order Object
A purchased Order:
{
"id": "order_...",
"object": "Order",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"shipments": [
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042-1",
"usps_zone": "08",
"custom_id": "order-1042-1",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "PDF",
"label_size": "4X6"
}
},
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042-2",
"usps_zone": "08",
"custom_id": "order-1042-2",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 12.0,
"width": 10.0,
"height": 6.0,
"predefined_package": null,
"weight": 48.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "11.62",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08030",
"quoted_service": "GroundAdvantage",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "14.71",
"discount": "3.09",
"discount_date": "2026-09-29",
"total_freight": "11.62",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08030": 14.71
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "13.85",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08030",
"quoted_service": "Priority",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "18.40",
"discount": "4.55",
"discount_date": "2026-09-29",
"total_freight": "13.85",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08030": 18.4
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "56.10",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08030",
"quoted_service": "Express",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "60.15",
"discount": "4.05",
"discount_date": "2026-09-29",
"total_freight": "56.10",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08030": 60.15
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "13.85",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08030",
"quoted_service": "Priority",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "18.40",
"discount": "4.55",
"discount_date": "2026-09-29",
"total_freight": "13.85",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08030": 18.4
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341294",
"public_url": "https://tracking.parcelshop.com/9405500106024190341294"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341294",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "PDF",
"label_size": "4X6"
}
}
],
"rates": [
{
"object": "Rate",
"carrier": "USPS",
"service": "GroundAdvantage",
"rate": "21.46",
"currency": "USD"
},
{
"object": "Rate",
"carrier": "USPS",
"service": "Priority",
"rate": "25.05",
"currency": "USD"
},
{
"object": "Rate",
"carrier": "USPS",
"service": "Express",
"rate": "104.85",
"currency": "USD"
}
],
"carrier": "USPS",
"service": "Priority",
"messages": []
}
An Order groups shipments that share an origin and a destination, so they can be rated and bought together. Its rates hold only the carrier and service combinations every shipment can use, with the amounts summed.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "order_" |
| object | string | "Order" |
| to_ |
Address | The destination address shared by all shipments |
| from_ |
Address | The origin address shared by all shipments |
| shipments | Shipment[] | Array of Shipment objects in the order |
| rates | object[] | One { object: "Rate", carrier, service, rate, currency } entry for each carrier and service every shipment can use, with rate summed across the shipments. Buy the order with its carrier and service. |
| carrier | string | The carrier of the order's first carrier account, USPS by default. Set when the order is created |
| service | string | The service used to purchase the order, or null if not yet purchased |
| messages | object[] | Always empty, kept for compatibility |
| created_ |
datetime | When the order was created |
| updated_ |
datetime | When the order was last updated |
Create an Order
POST/api/v1/orders
curl -X POST https://www.vanlo.com/api/v1/orders \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"order": {
"to_address": {
"name": "John Doe",
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true
},
"from_address": {
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example"
},
"carrier_accounts": [
"ca_..."
],
"shipments": [
{
"parcel": {
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
},
"reference": "order-1042-1",
"custom_id": "order-1042-1",
"options": {
"label_format": "PDF",
"delivery_confirmation": "SIGNATURE"
}
},
{
"parcel": {
"length": 12.0,
"width": 10.0,
"height": 6.0,
"weight": 48.0
},
"reference": "order-1042-2",
"custom_id": "order-1042-2",
"options": {
"label_format": "PDF",
"delivery_confirmation": "SIGNATURE"
}
}
]
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
order = Vanlo::Order.create(
to_address: {
name: 'John Doe',
street1: '148 W 51st St',
street2: 'Apt 4B',
city: 'New York',
state: 'NY',
zip: '10019',
country: 'US',
phone: '2125550199',
email: 'john.doe@example.com',
residential: true
},
from_address: {
name: 'Jane Smith',
company: 'Acme Goods',
street1: '417 Montgomery St',
street2: 'Floor 5',
city: 'San Francisco',
state: 'CA',
zip: '94104',
country: 'US',
phone: '4155550100',
email: 'shipping@acme.example'
},
carrier_accounts: ['ca_...'],
shipments: [
{
parcel: {
length: 10.0,
width: 8.0,
height: 4.0,
weight: 32.0
},
reference: 'order-1042-1',
custom_id: 'order-1042-1',
options: {
label_format: 'PDF',
delivery_confirmation: 'SIGNATURE'
}
},
{
parcel: {
length: 12.0,
width: 10.0,
height: 6.0,
weight: 48.0
},
reference: 'order-1042-2',
custom_id: 'order-1042-2',
options: {
label_format: 'PDF',
delivery_confirmation: 'SIGNATURE'
}
}
]
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
order = vanlo.Order.create(
to_address={
"name": "John Doe",
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": True
},
from_address={
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example"
},
carrier_accounts=["ca_..."],
shipments=[
{
"parcel": {
"length": 10.0,
"width": 8.0,
"height": 4.0,
"weight": 32.0
},
"reference": "order-1042-1",
"custom_id": "order-1042-1",
"options": {
"label_format": "PDF",
"delivery_confirmation": "SIGNATURE"
}
},
{
"parcel": {
"length": 12.0,
"width": 10.0,
"height": 6.0,
"weight": 48.0
},
"reference": "order-1042-2",
"custom_id": "order-1042-2",
"options": {
"label_format": "PDF",
"delivery_confirmation": "SIGNATURE"
}
}
]
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$order = \Vanlo\Order::create(array(
'to_address' => array(
'name' => 'John Doe',
'street1' => '148 W 51st St',
'street2' => 'Apt 4B',
'city' => 'New York',
'state' => 'NY',
'zip' => '10019',
'country' => 'US',
'phone' => '2125550199',
'email' => 'john.doe@example.com',
'residential' => true
),
'from_address' => array(
'name' => 'Jane Smith',
'company' => 'Acme Goods',
'street1' => '417 Montgomery St',
'street2' => 'Floor 5',
'city' => 'San Francisco',
'state' => 'CA',
'zip' => '94104',
'country' => 'US',
'phone' => '4155550100',
'email' => 'shipping@acme.example'
),
'carrier_accounts' => array('ca_...'),
'shipments' => array(
array(
'parcel' => array(
'length' => 10.0,
'width' => 8.0,
'height' => 4.0,
'weight' => 32.0
),
'reference' => 'order-1042-1',
'custom_id' => 'order-1042-1',
'options' => array(
'label_format' => 'PDF',
'delivery_confirmation' => 'SIGNATURE'
)
),
array(
'parcel' => array(
'length' => 12.0,
'width' => 10.0,
'height' => 6.0,
'weight' => 48.0
),
'reference' => 'order-1042-2',
'custom_id' => 'order-1042-2',
'options' => array(
'label_format' => 'PDF',
'delivery_confirmation' => 'SIGNATURE'
)
)
)
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Order order = Order.Create(new Dictionary<string, object>() {
{ "to_address", new Dictionary<string, object>() {
{ "name", "John Doe" },
{ "street1", "148 W 51st St" },
{ "street2", "Apt 4B" },
{ "city", "New York" },
{ "state", "NY" },
{ "zip", "10019" },
{ "country", "US" },
{ "phone", "2125550199" },
{ "email", "john.doe@example.com" },
{ "residential", true }
} },
{ "from_address", new Dictionary<string, object>() {
{ "name", "Jane Smith" },
{ "company", "Acme Goods" },
{ "street1", "417 Montgomery St" },
{ "street2", "Floor 5" },
{ "city", "San Francisco" },
{ "state", "CA" },
{ "zip", "94104" },
{ "country", "US" },
{ "phone", "4155550100" },
{ "email", "shipping@acme.example" }
} },
{ "carrier_accounts", new List<string>() { "ca_..." } },
{ "shipments", new List<Dictionary<string, object>>() {
new Dictionary<string, object>() {
{ "parcel", new Dictionary<string, object>() {
{ "length", 10.0 },
{ "width", 8.0 },
{ "height", 4.0 },
{ "weight", 32.0 }
} },
{ "reference", "order-1042-1" },
{ "custom_id", "order-1042-1" },
{ "options", new Dictionary<string, object>() {
{ "label_format", "PDF" },
{ "delivery_confirmation", "SIGNATURE" }
} }
},
new Dictionary<string, object>() {
{ "parcel", new Dictionary<string, object>() {
{ "length", 12.0 },
{ "width", 10.0 },
{ "height", 6.0 },
{ "weight", 48.0 }
} },
{ "reference", "order-1042-2" },
{ "custom_id", "order-1042-2" },
{ "options", new Dictionary<string, object>() {
{ "label_format", "PDF" },
{ "delivery_confirmation", "SIGNATURE" }
} }
}
} }
});
Creates an order and rates each of its shipments. Send service to buy every shipment in the same request.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| to_ |
Address | Destination address shared by all shipments in the order |
| from_ |
Address | Origin address shared by all shipments in the order |
| shipmentsrequired | object[] | 1 to 100 shipments, each with the fields below |
| carrier_ |
string[] | Carrier account ids to get rates from. Default: USPS |
| service | string | If provided, triggers create-and-buy: all shipments are purchased immediately with this service |
Each entry of shipments:
| Parameter | Type | Specification |
|---|---|---|
| parcelrequired | Parcel | Package dimensions and weight |
| customs_ |
CustomsInfo | Customs information for international shipments |
| carrier_ |
string[] | Override the order-level carrier_accounts for this shipment |
| options | Options | Shipment options. On an international Order that may ship with FedEx or UPS send options.duty_payment on every shipment to say who pays duties and taxes. |
| reference | string | Arbitrary reference string for this shipment |
| custom_ |
string | Your key for this shipment, as on Create a Shipment. Unlike there, a custom_id whose shipment already belongs to an Order is a conflict even while it can still be bought, so replaying an Order request does not update it. |
| return_ |
Address | Return address if different from the order's from_address |
| buyer_ |
Address | Buyer address if different from the order's to_address |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Each shipment custom_id must be unique within an order. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "shipments[0]",
"message": "custom_id must be unique within an order"
},
{
"field": "shipments[1]",
"message": "custom_id must be unique within an order"
}
]
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "Address not found by id for to_address field. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
INVALID_OPTIONS:
{
"error": {
"code": "INVALID_OPTIONS",
"message": "Invalid options. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "duty_payment",
"message": "type must be one of: SENDER, THIRD_PARTY, RECEIVER, BUYER"
}
]
}
}
Response for
CONFLICT:
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042-1",
"usps_zone": "08",
"custom_id": "order-1042-1",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "PDF",
"label_size": "4X6"
},
"error": {
"code": "CONFLICT",
"message": "A shipment with this custom_id already exists and cannot be updated. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "shipments[0]",
"message": "custom_id already belongs to an active shipment"
}
]
}
}
Response for
PAYMENT_REQUIRED:
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient funds. Please check your billing settings at http://www.vanlo.com/balance. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Balance",
"message": "Your balance is too low to purchase this label. Please add funds on the Balance page before buying."
}
]
}
}
Response for
CARRIER_REJECTED_ADDRESS:
{
"error": {
"code": "CARRIER_REJECTED_ADDRESS",
"message": "The carrier rejected the destination address. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Backend",
"message": "USPS rejected this shipment: bad zip code"
}
]
}
}
Response for
EXTERNAL_SERVICE_ERROR:
{
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "Unexpected response from our service provider has been received while processing your request. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "shp_...:Backend",
"message": "OnTrac could not create this label. Please contact support if it does not clear."
}
]
}
}
Response for
TOO_MANY_REQUESTS:
{
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many label purchases in flight for this account. Please retry shortly. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [],
"details": {
"retry_after": 2
}
}
}
Returns the Order with its combined rates, and with every label bought when service is sent.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 | A required field is missing or has the wrong shape, or two shipments share a custom_id. error.errors names each field. |
NOT_ |
404 | An address, parcel or customs info sent by id is not one of yours. |
INVALID_ |
422 | A shipment's options value is not allowed, such as a malformed duty_payment. |
CONFLICT |
409 | A custom_id belongs to a shipment already in an Order, or one that can no longer be updated. That shipment is returned beside error. |
PAYMENT_ |
402 | With service, your balance does not cover the labels. |
CARRIER_ |
422 | Every carrier refused the destination address. error.errors carries the reason. |
EXTERNAL_ |
424 | A carrier rejected or failed one of the shipments. error.errors names the shipment and its reason; the most severe failure decides the status. |
TOO_ |
429 | Too many label purchases are running for your account at once. The Retry-After header gives the wait in seconds. |
Buy an Order
POST/api/v1/orders/:id/buy
curl -X POST https://www.vanlo.com/api/v1/orders/order_.../buy \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"carrier": "USPS",
"service": "Priority"
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
order = Vanlo::Order.retrieve('order_...')
order.buy(carrier: 'USPS', service: 'Priority')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
order = vanlo.Order.retrieve('order_...')
order.buy(carrier='USPS', service='Priority')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$order = \Vanlo\Order::retrieve('order_...');
$order->buy(array(
'carrier' => 'USPS',
'service' => 'Priority'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Order order = Order.Retrieve("order_...");
order.Buy("USPS", "Priority");
Buys every shipment in the order with one carrier and service from the order's rates. An order is bought whole or not at all: when one shipment fails, the labels already bought for the order are refunded.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| carrierrequired | string | The carrier to purchase with (e.g. "USPS") |
| servicerequired | string | The service to purchase with (e.g. "Priority") |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "One or more shipments already have postage. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
PAYMENT_REQUIRED:
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient funds. Please check your billing settings at http://www.vanlo.com/balance. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "Balance",
"message": "Your balance is too low to purchase this label. Please add funds on the Balance page before buying."
}
]
}
}
Response for
EXTERNAL_SERVICE_ERROR:
{
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "Unexpected response from our service provider has been received while processing your request. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "shp_...:Backend",
"message": "OnTrac could not create this label. Please contact support if it does not clear."
}
]
}
}
Response for
LOCKED:
{
"error": {
"code": "LOCKED",
"message": "Another resource is creating at the moment. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
TOO_MANY_REQUESTS:
{
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many label purchases in flight for this account. Please retry shortly. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [],
"details": {
"retry_after": 2
}
}
}
Returns the Order with carrier and service set, and a label on every shipment.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 |
carrier or service is missing or matches no rate, a shipment already has a label, or the order is past its 72-hour purchase window. |
NOT_ |
404 | No order of yours has this id. |
PAYMENT_ |
402 | Your balance does not cover the labels. |
EXTERNAL_ |
424 | A carrier rejected or failed one of the shipments. error.errors names the shipment and its reason; the most severe failure decides the status. |
LOCKED |
429 | This order is already being bought. |
TOO_ |
429 | Too many label purchases are running for your account at once. The Retry-After header gives the wait in seconds. |
Retrying a purchase after a timeout is covered in the Retries and Timeouts Guide.
Retrieve an Order
GET/api/v1/orders/:id
curl https://www.vanlo.com/api/v1/orders/order_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Order.retrieve('order_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Order.retrieve('order_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$order = \Vanlo\Order::retrieve('order_...');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Order order = Order.Retrieve("order_...");
Retrieves an order by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the order |
Returns
Response:
{
"id": "order_...",
"object": "Order",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"shipments": [
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042-1",
"usps_zone": "08",
"custom_id": "order-1042-1",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 10.0,
"width": 8.0,
"height": 4.0,
"predefined_package": null,
"weight": 32.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "9.84",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08020",
"quoted_service": "GroundAdvantage",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "12.47",
"discount": "2.63",
"discount_date": "2026-09-29",
"total_freight": "9.84",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08020": 12.47
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "48.75",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08020",
"quoted_service": "Express",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "52.30",
"discount": "3.55",
"discount_date": "2026-09-29",
"total_freight": "48.75",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08020": 52.3
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "11.20",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08020",
"quoted_service": "Priority",
"billing_weight": "32.0 OZ",
"non_cubic_weight": "32.0 OZ",
"volume": 320.0,
"usps_cubic": false,
"commercial_freight": "14.95",
"discount": "3.75",
"discount_date": "2026-09-29",
"total_freight": "11.20",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08020": 14.95
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341287",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "PDF",
"label_size": "4X6"
}
},
{
"id": "shp_...",
"object": "Shipment",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z",
"reference": "order-1042-2",
"usps_zone": "08",
"custom_id": "order-1042-2",
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"return_address": null,
"buyer_address": null,
"parcel": {
"id": "prcl_...",
"object": "Parcel",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"length": 12.0,
"width": 10.0,
"height": 6.0,
"predefined_package": null,
"weight": 48.0
},
"customs_info": null,
"rates": [
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "GroundAdvantage",
"delivery_date": "2026-10-26",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 6,
"rate": "11.62",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DUXX0XXXXC08030",
"quoted_service": "GroundAdvantage",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "14.71",
"discount": "3.09",
"discount_date": "2026-09-29",
"total_freight": "11.62",
"total_surcharges": "0.00",
"services": {
"DUXX0XXXXC08030": 14.71
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "13.85",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08030",
"quoted_service": "Priority",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "18.40",
"discount": "4.55",
"discount_date": "2026-09-29",
"total_freight": "13.85",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08030": 18.4
},
"rdc": "04"
},
"usps_cubic": false
},
{
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Express",
"delivery_date": "2026-10-22",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 2,
"rate": "56.10",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DEXX0XXXXC08030",
"quoted_service": "Express",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "60.15",
"discount": "4.05",
"discount_date": "2026-09-29",
"total_freight": "56.10",
"total_surcharges": "0.00",
"services": {
"DEXX0XXXXC08030": 60.15
},
"rdc": "04"
},
"usps_cubic": false
}
],
"selected_rate": {
"id": "rate_...",
"object": "Rate",
"carrier_account_id": "ca_...",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"service": "Priority",
"delivery_date": "2026-10-23",
"delivery_datetime": null,
"delivery_date_guaranteed": false,
"delivery_days": 3,
"rate": "13.85",
"carrier": "USPS",
"rate_detail": {
"zone": "08",
"sku": "DPXX0XXXXC08030",
"quoted_service": "Priority",
"billing_weight": "48.0 OZ",
"non_cubic_weight": "48.0 OZ",
"volume": 720.0,
"usps_cubic": false,
"commercial_freight": "18.40",
"discount": "4.55",
"discount_date": "2026-09-29",
"total_freight": "13.85",
"total_surcharges": "0.00",
"services": {
"DPXX0XXXXC08030": 18.4
},
"rdc": "04"
},
"usps_cubic": false
},
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341294",
"public_url": "https://tracking.parcelshop.com/9405500106024190341294"
},
"postage_label": {
"object": "PostageLabel",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"id": "pl_...",
"integrated_form": null,
"label_date": "2026-10-20",
"label_epl2_url": null,
"label_pdf_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_resolution": null,
"label_size": null,
"label_type": null,
"label_file_type": "application/pdf",
"label_url": "https://www.vanlo.com/rails/active_storage/blobs/redirect/.../label.pdf",
"label_zpl_url": null
},
"refund_status": null,
"tracking_code": "9405500106024190341294",
"status": null,
"insurance": null,
"is_return": null,
"options": {
"delivery_confirmation": "SIGNATURE",
"label_format": "PDF",
"label_size": "4X6"
}
}
],
"rates": [
{
"object": "Rate",
"carrier": "USPS",
"service": "GroundAdvantage",
"rate": "21.46",
"currency": "USD"
},
{
"object": "Rate",
"carrier": "USPS",
"service": "Priority",
"rate": "25.05",
"currency": "USD"
},
{
"object": "Rate",
"carrier": "USPS",
"service": "Express",
"rate": "104.85",
"currency": "USD"
}
],
"carrier": "USPS",
"service": "Priority",
"messages": []
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Order.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No order of yours has this id. |
Reports
Report Object
A finished shipment Report:
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-10-20T15:30:02Z",
"updated_at": "2026-10-20T15:31:47Z",
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"status": "ready",
"url": "https://s3.us-west-2.amazonaws.com/vanlo.com/...?response-content-disposition=attachment%3B%20filename%3D%22shipments-2026-09-20-2026-10-19.csv.zip%22&response-content-type=application%2Fzip&X-Amz-Expires=3600&X-Amz-Signature=...",
"url_expires_at": "2026-10-20T16:42:10.884Z"
}
A CSV export of one kind of record over a date range, generated in the background. url stays null until status is ready.
| Type | Object Name | ID Prefix |
|---|---|---|
| shipment | ShipmentReport | shprep_ |
| payment_log | PaymentLogReport | plrep_ |
| shipment_invoice | ShipmentInvoiceReport | shpinvrep_ |
| refund | RefundReport | refrep_ |
| tracking | TrackingReport | trkrep_ |
| invoice_item | InvoiceItemReport | report_ |
| balance_snapshot | BalanceSnapshotReport | report_ |
| fedex_detail | FedExDetailReport | fdxrep_ |
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with a type-specific prefix (e.g., "shprep_" for shipment reports) |
| object | string | The type-specific object name (e.g., "ShipmentReport") |
| created_ |
datetime | When the report was created |
| updated_ |
datetime | When the report was last updated |
| start_ |
date | The start date of the report's date range |
| end_ |
date | The end date of the report's date range |
| status | string | Current status: "new", "generating", "ready", or "error" |
| url | string | URL to download the report CSV (zipped). Expires after 1 hour. Null while generating |
| url_ |
datetime | When the download URL will expire. Null while generating |
Create a Report
POST/api/v1/reports/:type
curl -X POST https://www.vanlo.com/api/v1/reports/shipment \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"send_email": true,
"send_email_address": "reports@acme.example"
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
report = Vanlo::Report.create(
type: 'shipment',
start_date: '2026-09-20',
end_date: '2026-10-19',
send_email: true,
send_email_address: 'reports@acme.example'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
report = vanlo.Report.create(
type="shipment",
start_date="2026-09-20",
end_date="2026-10-19",
send_email=True,
send_email_address="reports@acme.example"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$report = \Vanlo\Report::create(array(
'type' => 'shipment',
'start_date' => '2026-09-20',
'end_date' => '2026-10-19',
'send_email' => true,
'send_email_address' => 'reports@acme.example'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Report report = Report.Create(new Dictionary<string, object>() {
{ "type", "shipment" },
{ "start_date", "2026-09-20" },
{ "end_date", "2026-10-19" },
{ "send_email", true },
{ "send_email_address", "reports@acme.example" }
});
Starts a report of one type over a date range of up to 31 days. Poll it until it is ready, or send send_email to be emailed when it is.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| type | string | The type of report to generate. One of: shipment, payment_log, shipment_invoice, refund, tracking, invoice_item, balance_snapshot, fedex_detail |
| start_ |
date | Start date for the report (inclusive). Defaults to 31 days before end_date, or before today when neither is sent |
| end_ |
date | End date for the report (inclusive). Defaults to start_date + 31 days if omitted |
| send_ |
boolean | If true, send an email when the report is ready. Defaults to false |
| send_ |
string | Email address to send the report to. Defaults to the account email if omitted |
Returns
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Invalid parameters were passed and the record could not be persisted. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "end_date",
"message": "The date range covers more than 31 days and Invalid end date given for the report"
}
]
}
}
Returns the Report in status new, with a null url. A report that fails while generating is not an error: its status becomes error.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 |
type is not one of the report types. |
BAD_ |
400 | The date range is invalid or covers more than 31 days. error.errors names the date. |
List Reports
GET/api/v1/reports/:type
curl -G https://www.vanlo.com/api/v1/reports/shipment \
-H 'Authorization: Bearer VANLO_API_KEY' \
-d 'page_size=2' \
-d 'start_datetime=2026-09-01T00:00:00Z'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Report.all(
type: 'shipment',
page_size: 2,
start_datetime: '2026-09-01T00:00:00Z'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Report.all(
type="shipment",
page_size=2,
start_datetime="2026-09-01T00:00:00Z"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$reports = \Vanlo\Report::all(array(
'type' => 'shipment',
'page_size' => 2,
'start_datetime' => '2026-09-01T00:00:00Z'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
ReportList reportList = Report.List(new Dictionary<string, object>() {
{ "type", "shipment" },
{ "page_size", 2 },
{ "start_datetime", "2026-09-01T00:00:00Z" }
});
Lists your reports of one type a page at a time. Pass before_id or after_id to say where the next page begins.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| type | string | The type of report to list. One of: shipment, payment_log, shipment_invoice, refund, tracking, invoice_item, balance_snapshot, fedex_detail |
| before_ |
string | Return reports created before this id |
| after_ |
string | Return reports created after this id |
| start_ |
datetime | Only return reports created after this timestamp |
| end_ |
datetime | Only return reports created before this timestamp |
| page_ |
integer | Number of reports to return per page (default 20, max 100) |
Returns
Response:
{
"reports": [
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-10-20T15:30:02Z",
"updated_at": "2026-10-20T15:31:47Z",
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"status": "ready",
"url": "https://s3.us-west-2.amazonaws.com/vanlo.com/...?response-content-disposition=attachment%3B%20filename%3D%22shipments-2026-09-20-2026-10-19.csv.zip%22&response-content-type=application%2Fzip&X-Amz-Expires=3600&X-Amz-Signature=...",
"url_expires_at": "2026-10-20T16:42:10.884Z"
},
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-09-20T09:00:11Z",
"updated_at": "2026-09-20T09:01:58Z",
"start_date": "2026-08-20",
"end_date": "2026-09-19",
"status": "ready",
"url": "https://s3.us-west-2.amazonaws.com/vanlo.com/...?response-content-disposition=attachment%3B%20filename%3D%22shipments-2026-08-20-2026-09-19.csv.zip%22&response-content-type=application%2Fzip&X-Amz-Expires=3600&X-Amz-Signature=...",
"url_expires_at": "2026-10-20T16:42:10.884Z"
}
],
"has_more": true
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns an object with reports, an array of Report, and has_more, which says whether another page exists.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 |
type is not one of the report types. |
Retrieve a Report
GET/api/v1/reports/:id
curl https://www.vanlo.com/api/v1/reports/shprep_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Report.retrieve('shprep_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Report.retrieve('shprep_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$report = \Vanlo\Report::retrieve('shprep_...');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Report report = Report.Retrieve("shprep_...");
Retrieves a report by its id. GET /api/v1/reports/:type/:id works too.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the report |
Returns
Response:
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-10-20T15:30:02Z",
"updated_at": "2026-10-20T15:31:47Z",
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"status": "ready",
"url": "https://s3.us-west-2.amazonaws.com/vanlo.com/...?response-content-disposition=attachment%3B%20filename%3D%22shipments-2026-09-20-2026-10-19.csv.zip%22&response-content-type=application%2Fzip&X-Amz-Expires=3600&X-Amz-Signature=...",
"url_expires_at": "2026-10-20T16:42:10.884Z"
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Report.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No report of yours has this id. |
Carrier Accounts
Carrier Account Object
A Carrier Account you added:
{
"id":"ca_...",
"object":"CarrierAccount",
"type":"PassportGlobalAccount",
"readable":"Passport",
"description":"My Passport",
"credentials":{},
"created_at":"2026-08-09T12:00:00Z",
"updated_at":"2026-08-09T12:00:00Z"
}
The credentials of an account you hold with a carrier, so Vanlo rates and buys on your own pricing and the carrier bills you. Accounts Vanlo provides are listed too, with credentials of null, and cannot be changed with your key.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "ca_" |
| object | string | "CarrierAccount" |
| type | string | The account type, e.g. "FedExAccount" or "PassportGlobalAccount" |
| readable | string | The carrier's display name, e.g. "FedEx" or "Passport" |
| description | string | Your own label for the account, or null |
| credentials | object | Always an empty object for accounts you added, and null for accounts managed by Vanlo. Credentials are write-only and are never returned |
| created_ |
datetime | When the account was added |
| updated_ |
datetime | When the account was last changed |
Supported Carrier Account Types
The type you send on create selects the carrier and the credentials fields read; other fields are ignored.
| Type | Carrier | Credentials |
|---|---|---|
| FedExAccount | FedEx | mode (test or prod), client_id, client_secret, account_number |
| UPSAccount | UPS | client_id, client_secret, account_number, mode (test or prod) |
| UniUniAccount | UniUni | mode (test or prod), client_id, client_secret, customer_no |
| DoorDashAccount | DoorDash | developer_id, key_id, signing_secret, pickup_external_business_id (optional) |
| OnTracAccount | OnTrac | mode (test or prod), wsid, wskey, customer_branch |
| VehoAccount | Veho | api_key, mode (sandbox or prod) |
| PassportGlobalAccount | Passport | api_key, mode (stg or prod), company_name |
| DhlEcsAccount | DHL eCommerce | client_id, client_secret, distribution_center, pickup_id |
| AmazonShippingAccount | Amazon Shipping | None — authorized at the carrier, see below |
FedexAccount and UpsAccount are accepted as spellings of FedExAccount and UPSAccount on create; the response always carries the type as listed here.
A Passport account you added before Vanlo integrated Passport directly keeps the PassportGlobalAccount type but was registered under the earlier credential set, so an update on it takes api_key, company_name, email, name and phone instead of the fields above. Both kinds carry the same type in the response; an api_key rotation works on either.
Create a Carrier Account
POST/api/v1/carrier_accounts
curl -X POST https://www.vanlo.com/api/v1/carrier_accounts \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"carrier_account": {
"type": "DhlEcsAccount",
"description": "My DHL eCommerce",
"credentials": {
"client_id": "DHL_CLIENT_ID",
"client_secret": "DHL_CLIENT_SECRET",
"distribution_center": "USORD1",
"pickup_id": "DHL_PICKUP_ID"
}
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::CarrierAccount.create(
type: 'DhlEcsAccount',
description: 'My DHL eCommerce',
credentials: {
client_id: 'DHL_CLIENT_ID',
client_secret: 'DHL_CLIENT_SECRET',
distribution_center: 'USORD1',
pickup_id: 'DHL_PICKUP_ID'
}
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.CarrierAccount.create(
type='DhlEcsAccount',
description='My DHL eCommerce',
credentials={
'client_id': 'DHL_CLIENT_ID',
'client_secret': 'DHL_CLIENT_SECRET',
'distribution_center': 'USORD1',
'pickup_id': 'DHL_PICKUP_ID'
}
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$carrier_account = \Vanlo\CarrierAccount::create(array(
'type' => 'DhlEcsAccount',
'description' => 'My DHL eCommerce',
'credentials' => array(
'client_id' => 'DHL_CLIENT_ID',
'client_secret' => 'DHL_CLIENT_SECRET',
'distribution_center' => 'USORD1',
'pickup_id' => 'DHL_PICKUP_ID'
)
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
CarrierAccount carrierAccount = CarrierAccount.Create(
new Dictionary<string, object>() {
{ "type", "DhlEcsAccount" },
{ "description", "My DHL eCommerce" },
{ "credentials", new Dictionary<string, object>() {
{ "client_id", "DHL_CLIENT_ID" },
{ "client_secret", "DHL_CLIENT_SECRET" },
{ "distribution_center", "USORD1" },
{ "pickup_id", "DHL_PICKUP_ID" }
}}
}
);
Adds an account with the credentials the carrier issued you. FedEx, UniUni, DoorDash, OnTrac, Veho and Passport credentials are verified with the carrier first; UPS credentials are saved as sent, and DHL eCommerce and Amazon Shipping only have their shape checked.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| type | string | Required. One of the account types |
| credentials | object | The credential fields for that type |
| description | string | Optional. Your own label for the account |
Returns
Response for an Amazon Shipping account:
{
"id":"ca_...",
"object":"CarrierAccount",
"type":"AmazonShippingAccount",
"readable":"AmazonShipping",
"description":null,
"credentials":{},
"created_at":"2026-08-09T12:00:00Z",
"updated_at":"2026-08-09T12:00:00Z",
"oauth_url":"https://ship.amazon.com/authorize?..."
}
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "type",
"message": "is missing"
}
]
}
}
Response for
PARAMETER.REQUIRED:
{
"error": {
"code": "PARAMETER.REQUIRED",
"message": "Missing required parameter: carrier_account. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
VALIDATION_ERROR:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "We couldn't register these credentials with the carrier. Please double-check the credential fields and try again. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Carrier Account, ready to pass in carrier_accounts. An Amazon Shipping account also carries an oauth_url the account holder opens to authorize Vanlo, and cannot rate or buy until then.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 |
type is missing, blank or not supported, or credentials is not an object. error.errors names the field. |
PARAMETER.REQUIRED |
422 | The carrier_account object is missing. |
VALIDATION_ |
422 | The carrier rejected the credentials, a credential field for the type is blank, or the carrier is in a limited pilot not enabled on your account. |
List Carrier Accounts
GET/api/v1/carrier_accounts
curl https://www.vanlo.com/api/v1/carrier_accounts \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::CarrierAccount.all
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
carrier_accounts = vanlo.CarrierAccount.all()
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$carrier_accounts = \Vanlo\CarrierAccount::all();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
List<CarrierAccount> carrierAccounts = CarrierAccount.List();
Lists every carrier account available to you, the ones you added and the ones Vanlo manages, in one unpaginated array.
Parameters
This call takes no parameters.
Returns
Response:
[
{
"id":"ca_...",
"object":"CarrierAccount",
"type":"PassportGlobalAccount",
"readable":"Passport",
"description":"My Passport",
"credentials":{},
"created_at":"2026-08-09T12:00:00Z",
"updated_at":"2026-08-09T12:00:00Z"
},
{
"id":"ca_...",
"object":"CarrierAccount",
"type":"USPSAccount",
"readable":"USPS",
"description":null,
"credentials":null,
"created_at":"2026-01-04T09:30:00Z",
"updated_at":"2026-01-04T09:30:00Z"
}
]
Returns an array of Carrier Account.
On failure it returns one of the common errors; this call has none of its own.
Retrieve a Carrier Account
GET/api/v1/carrier_accounts/:id
curl https://www.vanlo.com/api/v1/carrier_accounts/ca_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::CarrierAccount.retrieve('ca_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.CarrierAccount.retrieve('ca_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$carrier_account = \Vanlo\CarrierAccount::retrieve("ca_...");
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
CarrierAccount carrierAccount = CarrierAccount.Retrieve("ca_...");
Retrieves a carrier account by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the carrier account |
Returns
Response:
{
"id":"ca_...",
"object":"CarrierAccount",
"type":"PassportGlobalAccount",
"readable":"Passport",
"description":"My Passport",
"credentials":{},
"created_at":"2026-08-09T12:00:00Z",
"updated_at":"2026-08-09T12:00:00Z"
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Carrier Account.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No carrier account on your account has this id. |
Update a Carrier Account
PATCH/api/v1/carrier_accounts/:id
curl -X PATCH https://www.vanlo.com/api/v1/carrier_accounts/ca_... \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"carrier_account": {
"description": "Passport (rotated)",
"credentials": {
"api_key": "NEW_PASSPORT_API_KEY"
}
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
carrier_account = Vanlo::CarrierAccount.retrieve('ca_...')
carrier_account.update(
description: 'Passport (rotated)',
credentials: { api_key: 'NEW_PASSPORT_API_KEY' }
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
carrier_account = vanlo.CarrierAccount.retrieve('ca_...')
carrier_account.update(
description='Passport (rotated)',
credentials={'api_key': 'NEW_PASSPORT_API_KEY'}
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$carrier_account = \Vanlo\CarrierAccount::retrieve("ca_...");
$carrier_account->update(array(
'description' => 'Passport (rotated)',
'credentials' => array('api_key' => 'NEW_PASSPORT_API_KEY')
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
CarrierAccount carrierAccount = CarrierAccount.Retrieve("ca_...");
carrierAccount.Update(
new Dictionary<string, object>() {
{ "description", "Passport (rotated)" },
{ "credentials", new Dictionary<string, object>() {
{ "api_key", "NEW_PASSPORT_API_KEY" }
}}
}
);
Rotates the credentials of an account you added, renames it, or both. Send only what changes: the credential fields you send replace the stored ones one by one.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the carrier account |
| credentials | object | Replacement credential fields for the account's type |
| description | string | A new label for the account |
Returns
Response for
VALIDATION_ERROR:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "We couldn't register these credentials with the carrier. Please double-check the credential fields and try again. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
UNPROCESSABLE_ENTITY:
{
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "This carrier account has purchased shipments, so its credentials can no longer be changed. Add a new carrier account with the new credentials instead. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
PARAMETER.INVALID_TYPE:
{
"error": {
"code": "PARAMETER.INVALID_TYPE",
"message": "Expected 'credentials' to be an object. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
FORBIDDEN:
{
"error": {
"code": "FORBIDDEN",
"message": "This carrier account is managed by Vanlo and cannot be modified. You can only manage carrier accounts you added yourself. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Carrier Account. Credentials of a FedEx, UPS, UniUni, DoorDash, OnTrac, Veho or native Passport account are locked once a label is bought on it; DHL eCommerce, Amazon Shipping and older Passport credentials rotate at the carrier and stay changeable.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
VALIDATION_ |
422 | The carrier rejected the new credentials, or a credential field is blank. The stored credentials are unchanged. |
UNPROCESSABLE_ |
422 | The credentials can no longer be changed: a label was bought on the account, or Vanlo support set it up. |
PARAMETER.INVALID_ |
422 |
credentials is not an object. |
FORBIDDEN |
403 | The account is managed by Vanlo. |
NOT_ |
404 | No carrier account on your account has this id. |
Delete a Carrier Account
DELETE/api/v1/carrier_accounts/:id
curl -X DELETE https://www.vanlo.com/api/v1/carrier_accounts/ca_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
carrier_account = Vanlo::CarrierAccount.retrieve('ca_...')
carrier_account.delete
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
carrier_account = vanlo.CarrierAccount.retrieve('ca_...')
carrier_account.delete()
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$carrier_account = \Vanlo\CarrierAccount::retrieve("ca_...");
$carrier_account->delete();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
CarrierAccount carrierAccount = CarrierAccount.Retrieve("ca_...");
carrierAccount.Destroy();
Removes an account you added, so it is no longer used for rating and buying. Labels already bought on it are not affected.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the carrier account |
Returns
Response for
FORBIDDEN:
{
"error": {
"code": "FORBIDDEN",
"message": "This carrier account is managed by Vanlo and cannot be modified. You can only manage carrier accounts you added yourself. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns an empty object.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
FORBIDDEN |
403 | The account is managed by Vanlo. |
NOT_ |
404 | No carrier account on your account has this id. |
Trackers
Tracker Object
A Tracker:
{
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [
{
"object": "TrackingDetail",
"status": "pre_transit",
"message": "Shipping Label Created, USPS Awaiting Item",
"datetime": "2026-10-20 15:06:42",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Accepted at USPS Origin Facility",
"datetime": "2026-10-20 23:41:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Arrived at USPS Regional Origin Facility",
"datetime": "2026-10-21 03:12:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "In Transit to Next Facility",
"datetime": "2026-10-21 19:05:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
}
],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-21T19:20:13Z",
"status": "in_transit",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
}
The tracking history of one package, updated as the carrier scans it. A Tracker is created with every purchased label, or on its own from a tracking code.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "trk_" |
| object | string | "Tracker" |
| shipment_ |
string | The id of the Shipment object associated with the Tracker (if any) |
| tracking_ |
TrackingDetails[] | Array of the associated TrackingDetail objects |
| carrier | string | The name of the carrier handling the shipment |
| status | string | The current status of the package, possible values are "unknown", "pre_transit", "in_transit", "out_for_delivery", "delivered", "available_for_pickup", "return_to_sender", "failure", "cancelled" or "error" |
| tracking_ |
string | The tracking code provided by the carrier |
| public_ |
string | URL to a publicly-accessible html page that shows tracking details for this tracker |
| created_ |
datetime | When the tracker was created |
| updated_ |
datetime | When the tracker was last updated |
Test Tracking Codes
In test mode these codes return a fixed status and send a webhook Event to your test URL, with canned details shaped like a real carrier's. A label bought in test mode is tracked as one of them, picked at random.
| tracking_code | status |
|---|---|
| EZ1000000001 | pre_transit |
| EZ2000000002 | in_transit |
| EZ3000000003 | out_for_delivery |
| EZ4000000004 | delivered |
| EZ5000000005 | return_to_sender |
| EZ6000000006 | failure |
| EZ7000000007 | unknown |
Create a Tracker
POST/api/v1/trackers
curl -X POST https://www.vanlo.com/api/v1/trackers \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"tracker": {
"tracking_code": "EZ2000000002"
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Tracker.create(
tracking_code: 'EZ2000000002'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Tracker.create(tracking_code='EZ2000000002')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$tracker = \Vanlo\Tracker::create(array(
'tracking_code' => 'EZ2000000002',
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Tracker tracker = Tracker.Create(
new Dictionary<string, object>() { { "tracking_code", "EZ2000000002" } }
);
Starts tracking a package by its tracking code, for a label bought outside Vanlo. The carrier is detected from the code.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| tracking_ |
string | The tracking code to track |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "tracking_code",
"message": "is missing"
}
]
}
}
Response for
UNPROCESSABLE_ENTITY:
{
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "Unsupported carrier: CanadaPost. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Tracker.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 |
tracking_code is missing. error.errors names the field. |
UNPROCESSABLE_ |
422 | The tracking code could not be tracked, such as one from a carrier Vanlo does not support. error.message carries the reason. |
List Trackers
GET/api/v1/trackers
curl -G https://www.vanlo.com/api/v1/trackers \
-H 'Authorization: Bearer VANLO_API_KEY' \
-d 'page_size=2' \
-d 'start_datetime=2026-10-01T00:00:00Z'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Tracker.all(
page_size: 2,
start_datetime: '2026-10-01T00:00:00Z'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Tracker.all(
page_size=2,
start_datetime="2026-10-01T00:00:00Z"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$trackers = \Vanlo\Tracker::all(array(
'page_size' => 2,
'start_datetime' => '2026-10-01T00:00:00Z'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
TrackerList trackerList = Tracker.List(new Dictionary<string, object>() {
{ "page_size", 2 },
{ "start_datetime", "2026-10-01T00:00:00Z" }
});
Lists your trackers a page at a time. Pass before_id or after_id to say where the next page begins.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| before_ |
string | Return trackers created before this id |
| after_ |
string | Return trackers created after this id |
| start_ |
datetime | Only return trackers created after this timestamp |
| end_ |
datetime | Only return trackers created before this timestamp |
| page_ |
integer | Number of trackers to return per page (default 20, max 100) |
Returns
Response:
{
"trackers": [
{
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [
{
"object": "TrackingDetail",
"status": "pre_transit",
"message": "Shipping Label Created, USPS Awaiting Item",
"datetime": "2026-10-20 15:06:42",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Accepted at USPS Origin Facility",
"datetime": "2026-10-20 23:41:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Arrived at USPS Regional Origin Facility",
"datetime": "2026-10-21 03:12:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "In Transit to Next Facility",
"datetime": "2026-10-21 19:05:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
}
],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-21T19:20:13Z",
"status": "in_transit",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
{
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [
{
"object": "TrackingDetail",
"status": "pre_transit",
"message": "Shipping Label Created, USPS Awaiting Item",
"datetime": "2026-10-17 14:22:10",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Accepted at USPS Origin Facility",
"datetime": "2026-10-17 22:03:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "out_for_delivery",
"message": "Out for Delivery",
"datetime": "2026-10-20 12:47:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "delivered",
"message": "Delivered, In/At Mailbox",
"datetime": "2026-10-20 18:31:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
}
],
"created_at": "2026-10-17T14:22:08Z",
"updated_at": "2026-10-20T18:45:51Z",
"status": "delivered",
"carrier": "USPS",
"tracking_code": "9405500106024190327715",
"public_url": "https://tracking.parcelshop.com/9405500106024190327715"
}
],
"has_more": true
}
Returns an object with trackers, an array of Tracker, and has_more, which says whether another page exists.
On failure it returns one of the common errors; this call has none of its own.
Retrieve a Tracker
GET/api/v1/trackers/:id
curl https://www.vanlo.com/api/v1/trackers/trk_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Tracker.retrieve('trk_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Tracker.retrieve('trk_...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$tracker = \Vanlo\Tracker::retrieve('trk_...');
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Tracker tracker = Tracker.Retrieve("trk_...");
Retrieves a tracker by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the tracker |
Returns
Response:
{
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [
{
"object": "TrackingDetail",
"status": "pre_transit",
"message": "Shipping Label Created, USPS Awaiting Item",
"datetime": "2026-10-20 15:06:42",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Accepted at USPS Origin Facility",
"datetime": "2026-10-20 23:41:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Arrived at USPS Regional Origin Facility",
"datetime": "2026-10-21 03:12:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
},
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "In Transit to Next Facility",
"datetime": "2026-10-21 19:05:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
}
],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-21T19:20:13Z",
"status": "in_transit",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
}
Returns the Tracker, or null when no tracker of yours has this id.
On failure it returns one of the common errors; this call has none of its own.
Nested Objects
Objects a Tracker carries. Each one also expands in place wherever a table names it.
CarrierDetail Object
A CarrierDetail:
{
"object": "CarrierDetail",
"service": "Priority",
"container_type": null,
"origin_location": "SAN FRANCISCO CA, 94104",
"alternate_identifier": null,
"destination_location": "NEW YORK NY, 10019",
"est_delivery_date_local": "2026-10-23",
"est_delivery_time_local": null,
"guaranteed_delivery_date": null,
"initial_delivery_attempt": null,
"origin_tracking_location": {
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
},
"destination_tracking_location": {
"city": "NEW YORK",
"state": "NY",
"country": "US",
"zip": "10019"
}
}
Sent in the carrier_detail of a Tracker Event, when the carrier supplies it. These endpoints do not return it.
| Parameter | Type | Specification |
|---|---|---|
| object | string | "CarrierDetail" |
| service | string | The service level the associated shipment was shipped with (if available) |
| container_ |
string | The type of container the associated shipment was shipped in (if available) |
| origin_ |
string | The location from which the package originated, stringified for presentation (if available) |
| alternate_ |
string | The alternate identifier for this package as provided by the carrier (if available) |
| destination_ |
string | The location to which the package is being sent, stringified for presentation (if available) |
| est_ |
string | The estimated delivery date as provided by the carrier, in the local time zone (if available) |
| est_ |
string | The estimated delivery time as provided by the carrier, in the local time zone (if available) |
| guaranteed_ |
string | The date and time the carrier guarantees the package to be delivered by (if available) |
| initial_ |
string | The date and time of the first attempt by the carrier to deliver the package (if available) |
| origin_ |
TrackingLocation | The location from which the package originated |
| destination_ |
TrackingLocation | The location to which the package is being sent |
TrackingDetails Object
A TrackingDetail:
{
"object": "TrackingDetail",
"status": "in_transit",
"message": "Accepted at USPS Origin Facility",
"datetime": "2026-10-20 23:41:00",
"source": null,
"pod_urls": null,
"updated_at": null,
"created_at": null
}
| Parameter | Type | Specification |
|---|---|---|
| object | string | "TrackingDetail" |
| status | string | status of the package at the time of the scan event, possible values are "unknown", "pre_transit", "in_transit", "out_for_delivery", "delivered", "available_for_pickup", "return_to_sender", "failure", "cancelled" or "error" |
| message | string | Description of the scan event |
| source | string | The carrier that reported the scan, or null |
| datetime | string | When the scan occurred, as "YYYY-MM-DD HH:MM:SS" in the time the carrier reported, without a zone |
| tracking_ |
TrackingLocation | The location associated with the scan event. Sent only in Tracker Events, not by these endpoints |
| pod_ |
string[] | Proof-of-delivery image URLs, if available |
| created_ |
datetime | Always null |
| updated_ |
datetime | Always null |
TrackingLocation Object
A TrackingLocation:
{
"zip": "94128",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US"
}
| Parameter | Type | Specification |
|---|---|---|
| zip | string | The postal code where the scan event occurred (if available) |
| city | string | The city where the scan event occurred (if available) |
| state | string | The state where the scan event occurred (if available) |
| country | string | The country where the scan event occurred (if available) |
Partner Events
The Partner Events endpoint reports USPS shipment milestones - such as a label being created, a package departing a facility, or an order being received - back to the USPS. You submit an event for one or more of your tracking codes, and Vanlo reports it to the USPS on your behalf.
Reporting is asynchronous. A successful request returns 202 Accepted: Vanlo has accepted
the event for reporting, not confirmed that the USPS has already recorded it.
Create a Partner Event
POST/api/v1/partner_events
curl -X POST https://www.vanlo.com/api/v1/partner_events \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"partner_event": {
"tracking_numbers": ["9400111899223333444459"],
"event_code": "80",
"event_zip5": "94103",
"event_date_time": "2026-07-06T14:30:00Z"
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::PartnerEvent.create(
tracking_numbers: ['9400111899223333444459'],
event_code: '80',
event_zip5: '94103',
event_date_time: '2026-07-06T14:30:00Z'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.PartnerEvent.create(
tracking_numbers=['9400111899223333444459'],
event_code='80',
event_zip5='94103',
event_date_time='2026-07-06T14:30:00Z'
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$partner_event = \Vanlo\PartnerEvent::create(array(
'tracking_numbers' => array('9400111899223333444459'),
'event_code' => '80',
'event_zip5' => '94103',
'event_date_time' => '2026-07-06T14:30:00Z'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
var parameters = new Dictionary<string, object>() {
{ "tracking_numbers", new List<string>() { "9400111899223333444459" } },
{ "event_code", "80" },
{ "event_zip5", "94103" },
{ "event_date_time", "2026-07-06T14:30:00Z" }
};
PartnerEvent partnerEvent = PartnerEvent.Create(parameters);
Submits an event for one or more of your tracking codes. Each tracking code you pass is resolved to one of your shipments and reported to the USPS.
Only USPS shipments purchased through Vanlo can be reported. Tracking codes that are not eligible - such as an unrecognized code, another carrier's shipment, or a USPS label not bought through Vanlo - are skipped rather than causing the whole request to fail. If none of the supplied tracking codes match a shipment on your account, the request returns an error (see below). Duplicate and blank tracking codes are ignored.
Most events default their scan location and time to the shipment's label data. Physical
handling events (codes 80-87) happen at the partner rather than at label creation, so
they require you to supply the scan ZIP (event_zip5) and timestamp (event_date_time).
Parameters
| Parameter | Type | Specification |
|---|---|---|
| tracking_ |
string[] | Required. One or more tracking codes to report the event for. Must contain at least one value. Duplicates and blanks are ignored |
| event_ |
string | The event being reported (default: "GX"). See Event Codes below |
| event_ |
string | 5-digit ZIP where the event occurred. Required for physical handling events (80-87). For other events it defaults to the shipment's origin (from-address) ZIP |
| event_ |
string | Timestamp the event occurred, in ISO 8601 (e.g. "2026-07-03T12:00:00Z"). Must be a valid timestamp. Required for physical handling events (80-87). For other events it defaults to the shipment's label timestamp |
Event Codes
| Code | Description |
|---|---|
| GX | Label Created (default) |
| AL | Acceptance / label event |
| 80 | Picked up by shipping partner |
| 81 | Arrived shipping partner facility |
| 82 | Departed shipping partner facility |
| 83 | Tendered to Postal Service |
| 84 | Arrived agent facility |
| 85 | Departed agent facility |
| 86 | Delivered by Agent to Merchant |
| 87 | Final Disposition by Agent |
| 89 | Pre-Shipment Notification, Order Received by Merchant |
Codes 84-87 are for use with Parcel Returns Service only.
Codes 80-87 are physical handling scans, so they require event_zip5 and
event_date_time. Supplying any other event code returns an UNPROCESSABLE_ENTITY error
listing the supported codes.
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "event_zip5",
"message": "is required for physical handling events (80-87)"
}
]
}
}
Response for
UNPROCESSABLE_ENTITY:
{
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "No shipments found for: 9400111899223333444459. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns HTTP 202 Accepted with an empty body. The event is reported to the USPS shortly
after the response, and retried automatically if the USPS is unavailable - an accepted event
never needs to be re-submitted.
Because ineligible tracking codes are skipped, a 202 Accepted confirms that your request was
accepted, not that every tracking code you sent was reported.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 |
tracking_numbers is empty, event_date_time is not a valid timestamp, or a physical handling event (80-87) is missing event_zip5 or event_date_time. Field-level details are in error.errors
|
UNPROCESSABLE_ |
422 | The event_code is not supported, or none of the supplied tracking codes matched a shipment on your account |
Webhooks
Webhook Object
A Webhook:
{
"id": "hook_...",
"object": "Webhook",
"url": "https://example.com/vanlo-webhook",
"webhook_secret": "whsec_8f2c41d7",
"disabled_at": null
}
A URL that receives an Event by HTTP POST whenever one of your objects changes. Event Types lists what each event carries.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "hook_" |
| object | string | "Webhook" |
| url | string | The URL that webhook notifications are sent to |
| webhook_ |
string | The secret Vanlo signs each delivery with, in the X-Hmac-Signature header, or null |
| disabled_ |
datetime | The time the webhook was disabled, or null if enabled |
Create a Webhook
POST/api/v1/webhooks
curl -X POST https://www.vanlo.com/api/v1/webhooks \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"webhook": {
"url": "https://example.com/vanlo-webhook",
"webhook_secret": "whsec_8f2c41d7"
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
webhook = Vanlo::Webhook.create(
url: 'https://example.com/vanlo-webhook',
webhook_secret: 'whsec_8f2c41d7'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
webhook = vanlo.Webhook.create(
url="https://example.com/vanlo-webhook",
webhook_secret="whsec_8f2c41d7"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$webhook = \Vanlo\Webhook::create(array(
'url' => 'https://example.com/vanlo-webhook',
'webhook_secret' => 'whsec_8f2c41d7'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Webhook webhook = Webhook.Create(new Dictionary<string, object>() {
{ "url", "https://example.com/vanlo-webhook" },
{ "webhook_secret", "whsec_8f2c41d7" }
});
Registers a URL to receive events. Registering a URL you already have re-enables it instead of adding another.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| urlrequired | string | The URL to receive webhook notifications |
| webhook_ |
string | A secret Vanlo signs each delivery with, in the X-Hmac-Signature header |
Returns
Response for
BAD_REQUEST:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{
"field": "url",
"message": "is missing"
}
]
}
}
Returns the Webhook.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
BAD_ |
400 |
url is missing or not a valid URL, or your account already has the most webhooks it may hold. error.errors names the field. |
List Webhooks
GET/api/v1/webhooks
curl https://www.vanlo.com/api/v1/webhooks \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Webhook.all
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
webhooks = vanlo.Webhook.all()
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$webhooks = \Vanlo\Webhook::all();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
List<Webhook> webhooks = Webhook.List();
Lists every webhook on your account, in one unpaginated array.
Parameters
This call takes no parameters.
Returns
Response:
[
{
"id": "hook_...",
"object": "Webhook",
"url": "https://example.com/vanlo-webhook",
"webhook_secret": "whsec_8f2c41d7",
"disabled_at": null
}
]
Returns an array of Webhook.
On failure it returns one of the common errors; this call has none of its own.
Retrieve a Webhook
GET/api/v1/webhooks/:id
curl https://www.vanlo.com/api/v1/webhooks/hook_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Webhook.retrieve('hook_...')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Webhook.retrieve('hook...')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$webhook = \Vanlo\Webhook::retrieve("hook_...");
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Webhook webhook = Webhook.Retrieve("hook_...");
Retrieves a webhook by its id.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the webhook |
Returns
Response:
{
"id": "hook_...",
"object": "Webhook",
"url": "https://example.com/vanlo-webhook",
"webhook_secret": "whsec_8f2c41d7",
"disabled_at": null
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Webhook.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No webhook of yours has this id. |
Update a Webhook
PATCH/api/v1/webhooks/:id
curl -X PATCH https://www.vanlo.com/api/v1/webhooks/hook_... \
-H 'Authorization: Bearer VANLO_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"webhook": {
"webhook_secret": "whsec_3b9e07a1"
}
}'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
webhook = Vanlo::Webhook.retrieve('hook_...')
webhook.update(webhook_secret: 'whsec_3b9e07a1')
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
webhook = vanlo.Webhook.retrieve('hook_...')
webhook.update(webhook_secret='whsec_3b9e07a1')
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$webhook = \Vanlo\Webhook::retrieve('hook_...');
$webhook->update(array('webhook_secret' => 'whsec_3b9e07a1'));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Webhook webhook = Webhook.Retrieve("hook_...");
webhook.Update(new Dictionary<string, object>() {
{ "webhook_secret", "whsec_3b9e07a1" }
});
Re-enables a disabled webhook, and replaces its webhook_secret when one is sent. PUT works too.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the webhook |
| webhook_ |
string | A new secret to sign deliveries with, or null to stop signing them. Without it the stored secret is kept |
Returns
Response for
PARAMETER.REQUIRED:
{
"error": {
"code": "PARAMETER.REQUIRED",
"message": "Missing required parameter: webhook. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns the Webhook, enabled.
On failure it returns an Error instead. These are the errors specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
PARAMETER.REQUIRED |
422 | The webhook object is missing or empty. |
NOT_ |
404 | No webhook of yours has this id. |
Delete a Webhook
DELETE/api/v1/webhooks/:id
curl -X DELETE https://www.vanlo.com/api/v1/webhooks/hook_... \
-H 'Authorization: Bearer VANLO_API_KEY'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
webhook = Vanlo::Webhook.retrieve('hook_...')
webhook.delete
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
webhook = vanlo.Webhook.retrieve('hook_...')
webhook.delete()
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$webhook->delete();
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
Webhook webhook = Webhook.Retrieve("hook_...");
webhook.Destroy();
Deletes a webhook, so it receives no further events.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the webhook |
Returns
Response for
NOT_FOUND:
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": []
}
}
Returns an empty object.
On failure it returns an Error instead. This is the error specific to this call, on top of the common errors.
| Code | Status | Trigger |
|---|---|---|
NOT_ |
404 | No webhook of yours has this id. |
Events
Event Object
An Event delivered to a webhook:
{
"id": "evt_...",
"object": "Event",
"description": "tracker.updated",
"pending_urls": [
"https://example.com/vanlo-webhook"
],
"completed_urls": [],
"failed_urls": [],
"result": {
"id": "trk_...",
"object": "Tracker",
"tracking_code": "9405500106024190341287",
"status": "in_transit",
"status_detail": "in_transit",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-21T19:20:13Z",
"signed_by": null,
"weight": 32.0,
"est_delivery_date": "2026-10-23T00:00:00Z",
"pod_urls": null,
"shipment_id": "shp_...",
"carrier": "USPS",
"tracking_details": [
{
"object": "TrackingDetail",
"message": "Shipping Label Created, USPS Awaiting Item",
"description": "",
"status": "pre_transit",
"status_detail": "label_created",
"datetime": "2026-10-20T15:06:42Z",
"source": "USPS",
"carrier_code": "GX",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
}
},
{
"object": "TrackingDetail",
"message": "Accepted at USPS Origin Facility",
"description": "",
"status": "in_transit",
"status_detail": "arrived_at_facility",
"datetime": "2026-10-20T23:41:00Z",
"source": "USPS",
"carrier_code": "OA",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94188"
}
},
{
"object": "TrackingDetail",
"message": "Arrived at USPS Regional Origin Facility",
"description": "",
"status": "in_transit",
"status_detail": "arrived_at_facility",
"datetime": "2026-10-21T03:12:00Z",
"source": "USPS",
"carrier_code": "10",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94128"
}
},
{
"object": "TrackingDetail",
"message": "In Transit to Next Facility",
"description": "",
"status": "in_transit",
"status_detail": "in_transit",
"datetime": "2026-10-21T19:05:00Z",
"source": "USPS",
"carrier_code": "NT",
"tracking_location": {
"object": "TrackingLocation",
"city": null,
"state": null,
"country": "US",
"zip": null
}
}
],
"carrier_detail": {
"object": "CarrierDetail",
"service": "Priority",
"container_type": null,
"est_delivery_date_local": "2026-10-23",
"est_delivery_time_local": null,
"origin_location": "SAN FRANCISCO CA, 94104",
"origin_tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
},
"destination_location": "NEW YORK NY, 10019",
"destination_tracking_location": {
"object": "TrackingLocation",
"city": "NEW YORK",
"state": "NY",
"country": "US",
"zip": "10019"
},
"guaranteed_delivery_date": null,
"alternate_identifier": null,
"initial_delivery_attempt": null
},
"is_return": false,
"finalized": false,
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"created_at": "2026-10-21T19:20:14Z",
"updated_at": "2026-10-21T19:20:14Z"
}
An Event records something that happened on your account, such as a tracker status change, and is what your webhooks receive.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier, begins with "evt_" |
| object | string | "Event" |
| description | string | Event type descriptor, e.g. "tracker.updated" or "batch.updated" |
| pending_ |
string[] | Array of webhook URLs that have not yet received this event |
| completed_ |
string[] | Array of webhook URLs that have successfully received this event |
| failed_ |
string[] | Array of webhook URLs that failed to receive this event |
| result | object | The payload, which depends on the event type. Event Types lists each one |
| created_ |
datetime | When the event was created |
| updated_ |
datetime | When the event was last updated |
List Events
GET/api/v1/events
curl -G https://www.vanlo.com/api/v1/events \
-H 'Authorization: Bearer VANLO_API_KEY' \
-d 'page_size=5' \
-d 'start_datetime=2026-10-21T00:00:00Z'
require 'vanlo'
Vanlo.api_key = 'VANLO_API_KEY'
Vanlo::Event.all(
page_size: 5,
start_datetime: '2026-10-21T00:00:00Z'
)
import vanlo
vanlo.api_key = 'VANLO_API_KEY'
vanlo.Event.all(
page_size=5,
start_datetime="2026-10-21T00:00:00Z"
)
require_once('/path/to/lib/vanlo.php');
\Vanlo\Vanlo::setApiKey('VANLO_API_KEY');
$events = \Vanlo\Event::all(array(
'page_size' => 5,
'start_datetime' => '2026-10-21T00:00:00Z'
));
using Vanlo;
ClientManager.SetCurrent("VANLO_API_KEY");
EventList eventList = Event.List(new Dictionary<string, object>() {
{ "page_size", 5 },
{ "start_datetime", "2026-10-21T00:00:00Z" }
});
Lists the events sent to your webhooks, a page at a time, to debug a delivery or replay a missed one. Pass before_id or after_id to say where the next page begins.
Parameters
| Parameter | Type | Specification |
|---|---|---|
| before_ |
string | Return events created before this id |
| after_ |
string | Return events created after this id |
| start_ |
datetime | Only return events created after this timestamp |
| end_ |
datetime | Only return events created before this timestamp |
| page_ |
integer | Number of events to return per page (default 20, max 100) |
Returns
Response:
{
"events": [
{
"id": "evt_...",
"object": "Event",
"description": "tracker.updated",
"pending_urls": [],
"completed_urls": [
"https://example.com/vanlo-webhook"
],
"failed_urls": [],
"result": {
"id": "trk_...",
"object": "Tracker",
"tracking_code": "9405500106024190341287",
"status": "in_transit",
"status_detail": "in_transit",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-21T19:20:13Z",
"signed_by": null,
"weight": 32.0,
"est_delivery_date": "2026-10-23T00:00:00Z",
"pod_urls": null,
"shipment_id": "shp_...",
"carrier": "USPS",
"tracking_details": [
{
"object": "TrackingDetail",
"message": "Shipping Label Created, USPS Awaiting Item",
"description": "",
"status": "pre_transit",
"status_detail": "label_created",
"datetime": "2026-10-20T15:06:42Z",
"source": "USPS",
"carrier_code": "GX",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
}
},
{
"object": "TrackingDetail",
"message": "Accepted at USPS Origin Facility",
"description": "",
"status": "in_transit",
"status_detail": "arrived_at_facility",
"datetime": "2026-10-20T23:41:00Z",
"source": "USPS",
"carrier_code": "OA",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94188"
}
},
{
"object": "TrackingDetail",
"message": "Arrived at USPS Regional Origin Facility",
"description": "",
"status": "in_transit",
"status_detail": "arrived_at_facility",
"datetime": "2026-10-21T03:12:00Z",
"source": "USPS",
"carrier_code": "10",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94128"
}
},
{
"object": "TrackingDetail",
"message": "In Transit to Next Facility",
"description": "",
"status": "in_transit",
"status_detail": "in_transit",
"datetime": "2026-10-21T19:05:00Z",
"source": "USPS",
"carrier_code": "NT",
"tracking_location": {
"object": "TrackingLocation",
"city": null,
"state": null,
"country": "US",
"zip": null
}
}
],
"carrier_detail": {
"object": "CarrierDetail",
"service": "Priority",
"container_type": null,
"est_delivery_date_local": "2026-10-23",
"est_delivery_time_local": null,
"origin_location": "SAN FRANCISCO CA, 94104",
"origin_tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
},
"destination_location": "NEW YORK NY, 10019",
"destination_tracking_location": {
"object": "TrackingLocation",
"city": "NEW YORK",
"state": "NY",
"country": "US",
"zip": "10019"
},
"guaranteed_delivery_date": null,
"alternate_identifier": null,
"initial_delivery_attempt": null
},
"is_return": false,
"finalized": false,
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"created_at": "2026-10-21T19:20:14Z",
"updated_at": "2026-10-21T19:20:15Z"
}
],
"has_more": true
}
Returns an object with events, an array of Event, and has_more, which says whether another page exists. Each result is the payload delivered to your webhooks.
On failure it returns one of the common errors; this call has none of its own.
Event Types
Each event type returns a specific set of data in the result field of the webhook event. The events below are the v1 events Vanlo sends, grouped by the object they describe.
Delivery, retry, and authentication are the same for every event - see the Webhooks Guide for those details. The sections below document only the result payload of each event.
Batch Events
batch.created
Example
resultpayload:
{
"id": "batch_...",
"object": "Batch",
"label_url": null,
"num_shipments": 2,
"state": "created",
"scan_form": null,
"shipments": [
{
"id": "shp_...",
"batch_status": "created",
"batch_message": null,
"tracking_code": null
},
{
"id": "shp_...",
"batch_status": "created",
"batch_message": null,
"tracking_code": null
}
],
"status": {
"created": 2,
"queued_for_purchase": 0,
"creation_failed": 0,
"postage_purchased": 0,
"postage_purchase_failed": 0
},
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:04:12Z"
}
Sent when a new batch is created. The result is a Batch object.
batch.updated
Example
resultpayload:
{
"id": "batch_...",
"object": "Batch",
"label_url": null,
"num_shipments": 2,
"state": "purchased",
"scan_form": null,
"shipments": [
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341287"
},
{
"id": "shp_...",
"batch_status": "postage_purchased",
"batch_message": null,
"tracking_code": "9405500106024190341294"
}
],
"status": {
"created": 0,
"queued_for_purchase": 0,
"creation_failed": 0,
"postage_purchased": 2,
"postage_purchase_failed": 0
},
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-20T15:06:40Z"
}
Sent when a batch purchase finishes, with state purchased or purchase_failed, and when its combined label is generated. The result is the same Batch object as batch.created.
Tracker Events
tracker.updated
Example
resultpayload:
{
"id": "trk_...",
"object": "Tracker",
"tracking_code": "9405500106024190341287",
"status": "in_transit",
"status_detail": "in_transit",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-21T19:20:13Z",
"signed_by": null,
"weight": 32.0,
"est_delivery_date": "2026-10-23T00:00:00Z",
"pod_urls": null,
"shipment_id": "shp_...",
"carrier": "USPS",
"tracking_details": [
{
"object": "TrackingDetail",
"message": "Shipping Label Created, USPS Awaiting Item",
"description": "",
"status": "pre_transit",
"status_detail": "label_created",
"datetime": "2026-10-20T15:06:42Z",
"source": "USPS",
"carrier_code": "GX",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
}
},
{
"object": "TrackingDetail",
"message": "Accepted at USPS Origin Facility",
"description": "",
"status": "in_transit",
"status_detail": "arrived_at_facility",
"datetime": "2026-10-20T23:41:00Z",
"source": "USPS",
"carrier_code": "OA",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94188"
}
},
{
"object": "TrackingDetail",
"message": "Arrived at USPS Regional Origin Facility",
"description": "",
"status": "in_transit",
"status_detail": "arrived_at_facility",
"datetime": "2026-10-21T03:12:00Z",
"source": "USPS",
"carrier_code": "10",
"tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94128"
}
},
{
"object": "TrackingDetail",
"message": "In Transit to Next Facility",
"description": "",
"status": "in_transit",
"status_detail": "in_transit",
"datetime": "2026-10-21T19:05:00Z",
"source": "USPS",
"carrier_code": "NT",
"tracking_location": {
"object": "TrackingLocation",
"city": null,
"state": null,
"country": "US",
"zip": null
}
}
],
"carrier_detail": {
"object": "CarrierDetail",
"service": "Priority",
"container_type": null,
"est_delivery_date_local": "2026-10-23",
"est_delivery_time_local": null,
"origin_location": "SAN FRANCISCO CA, 94104",
"origin_tracking_location": {
"object": "TrackingLocation",
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94104"
},
"destination_location": "NEW YORK NY, 10019",
"destination_tracking_location": {
"object": "TrackingLocation",
"city": "NEW YORK",
"state": "NY",
"country": "US",
"zip": "10019"
},
"guaranteed_delivery_date": null,
"alternate_identifier": null,
"initial_delivery_attempt": null
},
"is_return": false,
"finalized": false,
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
}
Sent whenever a tracker receives new tracking information from the carrier. The result is a Tracker object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the tracker, begins with "trk_" |
| object | string | "Tracker" |
| status | string | Current tracking status: "unknown", "pre_transit", "in_transit", "out_for_delivery", "available_for_pickup", "delivered", "return_to_sender", "failure", "cancelled", or "error" |
| carrier | string | Name of the carrier handling the shipment |
| tracking_ |
string | The tracking code provided by the carrier |
| shipment_ |
string | Identifier of the associated shipment, if any |
| status_ |
string | The carrier's finer-grained status, such as "arrived_at_facility", when it gives one |
| tracking_ |
TrackingDetails[] | Every scan so far. Each also carries description, status_detail, carrier_code and its TrackingLocation in tracking_location
|
| carrier_ |
CarrierDetail | Associated CarrierDetail object, when the carrier supplies one |
| pod_ |
string[] | Proof-of-delivery image URLs, if any |
| is_ |
boolean | Whether the package is being returned to the sender, when the carrier says |
| finalized | boolean | Whether the tracker has reached its last status, when the carrier says |
| public_ |
string | URL to a publicly-accessible tracking page |
| est_ |
datetime | Estimated delivery date, if available |
| signed_ |
string | Name of the person who signed for the package, if available |
| weight | float | Weight of the package, if available |
| created_ |
datetime | When the tracker was created |
| updated_ |
datetime | When the tracker was last updated |
tracker.detail.created
Example
resultpayload:
{
"message": "In Transit to Next Facility",
"status": "in_transit",
"datetime": "2026-10-21 19:05:00",
"location": {
"city": "SAN FRANCISCO",
"state": "CA",
"country": "US",
"zip": "94128"
},
"created_at": "2026-10-21 19:20:13",
"tracker_id": "trk_...",
"tracking_code": "9405500106024190341287"
}
Sent for each new tracking detail (carrier scan) added to a tracker. The result is a single tracking detail, with the parent tracker's tracker_id and tracking_code attached.
| Parameter | Type | Specification |
|---|---|---|
| status | string | Tracking status reported by this scan |
| message | string | Human-readable description of the scan |
| datetime | string | When the scan occurred, as "YYYY-MM-DD HH:MM:SS" in the time the carrier reported, without a zone |
| location | object | Scan location: city, state, country, zip
|
| pod_ |
string[] | Proof-of-delivery image URLs. Present only when there are some |
| created_ |
string | When Vanlo recorded the scan, in UTC as "YYYY-MM-DD HH:MM:SS" |
| tracker_ |
string | Identifier of the parent tracker, begins with "trk_" |
| tracking_ |
string | The tracking code of the parent tracker |
Refund Events
refund.successful
Example
resultpayload:
{
"id": "rfnd_...",
"object": "Refund",
"status": "refunded",
"shipment_id": "shp_...",
"created_at": "2026-10-20T15:04:12Z",
"updated_at": "2026-10-21T16:02:44Z",
"carrier": "USPS",
"tracking_code": "9405500106024190341287"
}
Sent when a refund request for a shipment is approved by the carrier. The result is a Refund object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the refund, begins with "rfnd_" |
| object | string | "Refund" |
| status | string | "refunded" |
| shipment_ |
string | Identifier of the refunded shipment, begins with "shp_" |
| carrier | string | Name of the carrier that issued the refund |
| tracking_ |
string | The tracking code of the refunded shipment |
| created_ |
datetime | When the refund was created |
| updated_ |
datetime | When the refund was last updated |
Insurance Events
insurance.purchased
Example
resultpayload:
{
"id": "ins_...",
"object": "Insurance",
"reference": "vanlo_shp_...",
"amount": "150.00000",
"provider": "shipsurance",
"provider_id": "7720394",
"status": "purchased",
"messages": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"shipment_id": "shp_...",
"tracking_code": "9405500106024190341287",
"tracker": {
"id": "trk_...",
"object": "Tracker",
"shipment_id": "shp_...",
"tracking_details": [],
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z",
"status": "unknown",
"carrier": "USPS",
"tracking_code": "9405500106024190341287",
"public_url": "https://tracking.parcelshop.com/9405500106024190341287"
},
"from_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"to_address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "John Doe",
"company": null,
"street1": "148 W 51st St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10019",
"country": "US",
"phone": "2125550199",
"email": "john.doe@example.com",
"residential": true,
"verifications": null
},
"fee": {
"amount": "1.50000"
}
}
Sent when insurance is successfully purchased for a shipment. The result is an Insurance object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the insurance, begins with "ins_" |
| object | string | "Insurance" |
| reference | string | The policy reference: vanlo_ and the shipment id |
| amount | string | Insured value of the shipment |
| provider | string | Name of the insurance provider |
| provider_ |
string | The provider's identifier for the policy |
| status | string | Current status of the insurance |
| messages | string[] | Provider messages, if any |
| shipment_ |
string | Identifier of the insured shipment, begins with "shp_" |
| tracking_ |
string | The tracking code of the insured shipment |
| tracker | Tracker | Associated Tracker object, if available |
| from_ |
Address | Origin address, if available |
| to_ |
Address | Destination address, if available |
| fee | object | Insurance fee: amount
|
| created_ |
datetime | When the insurance was created |
| updated_ |
datetime | When the insurance was last updated |
Payment Events
payment.created
Example
resultpayload:
{
"id": "paylog_...",
"object": "PaymentLog",
"amount": "25.00",
"balance": "150.00",
"status": "pending",
"source_type": "bank_account",
"target_type": "vanlo_stripe",
"charge_type": "recharge",
"created_at": "2026-10-20T14:02:51Z"
}
Sent when a payment (account recharge) is initiated. The result is a PaymentLog object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the payment log, begins with "paylog_" |
| object | string | "PaymentLog" |
| amount | string | Charged amount |
| balance | string | Account balance after the payment, if available |
| status | string | Payment status: "pending", "completed", or "failed" |
| source_ |
string | Funding source: "bank_account" or "credit_card" |
| target_ |
string | "vanlo_stripe" |
| charge_ |
string | "recharge" |
| created_ |
datetime | When the payment was created |
payment.completed
Example
resultpayload:
{
"id": "paylog_...",
"object": "PaymentLog",
"amount": "25.00",
"balance": "175.00",
"status": "completed",
"source_type": "bank_account",
"target_type": "vanlo_stripe",
"charge_type": "recharge",
"created_at": "2026-10-20T14:02:51Z"
}
Sent when a payment clears. The result is the same PaymentLog object as payment.created, with status set to completed.
payment.failed
Example
resultpayload:
{
"id": "paylog_...",
"object": "PaymentLog",
"amount": "25.00",
"balance": "150.00",
"status": "failed",
"source_type": "bank_account",
"target_type": "vanlo_stripe",
"charge_type": "recharge",
"created_at": "2026-10-20T14:02:51Z"
}
Sent when a payment fails. The result is the same PaymentLog object as payment.created, with status set to failed.
Report Events
report.new
Example
resultpayload:
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-10-20T15:30:02Z",
"updated_at": "2026-10-20T15:30:02Z",
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"status": "new",
"url": null,
"url_expires_at": null
}
Sent when a report is requested and starts generating. The result is a Report object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the report, with a prefix for its type, such as "shprep_" |
| object | string | The report type, e.g. "ShipmentReport" or "PaymentLogReport" |
| status | string | "new", "available", or "failed". These are the API's new and generating, ready, and error
|
| start_ |
date | First day covered by the report |
| end_ |
date | Last day covered by the report |
| url | string | Download URL, present once the report is available |
| url_ |
datetime | When the download URL expires, present once available |
| created_ |
datetime | When the report was created |
| updated_ |
datetime | When the report was last updated |
report.available
Example
resultpayload:
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-10-20T15:30:02Z",
"updated_at": "2026-10-20T15:31:47Z",
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"status": "available",
"url": "https://s3.us-west-2.amazonaws.com/vanlo.com/...?response-content-disposition=attachment%3B%20filename%3D%22shipments-2026-09-20-2026-10-19.csv.zip%22&response-content-type=application%2Fzip&X-Amz-Expires=3600&X-Amz-Signature=...",
"url_expires_at": "2026-10-20T16:42:10.884Z"
}
Sent when a report has finished generating and is ready to download. The result is the same Report object as report.new, with status set to available and the url populated.
report.failed
Example
resultpayload:
{
"id": "shprep_...",
"object": "ShipmentReport",
"created_at": "2026-10-20T15:30:02Z",
"updated_at": "2026-10-20T15:31:47Z",
"start_date": "2026-09-20",
"end_date": "2026-10-19",
"status": "failed",
"url": null,
"url_expires_at": null
}
Sent when a report fails to generate. The result is the same Report object as report.new, with status set to failed.
Shipment Events
shipment.invoice.created
Example
resultpayload:
{
"id": "ppshp_...",
"object": "ShipmentInvoice",
"status": "processed",
"shipment_id": "shp_...",
"label_date": "2026-10-20",
"tracking_code": "9405500106024190341287",
"quoted_amount": "11.20",
"quoted_currency": "USD",
"initially_paid_amount": "11.20",
"initially_paid_currency": "USD",
"initially_paid_payment_log": "paylog_...",
"adjustment_reason": "weight_correction",
"adjustment_amount": "4.35",
"invoice_date": "2026-11-03T09:12:40Z",
"invoice_type": "adjustment",
"invoice_amount": "4.35",
"invoice_currency": "USD",
"invoice_payment_log": "paylog_...",
"total_cost": "15.55",
"carrier_account": "ca_...",
"carrier": "USPS",
"claimed_details": {
"parcel": {
"weight": 32.0
},
"zone": 8
},
"captured_details": {
"parcel": {
"weight": 56.0
},
"zone": 8
}
}
Sent when a carrier issues a post-purchase adjustment (a corrected charge) for a shipment. The result is a ShipmentInvoice object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the invoice, begins with "ppshp_" |
| object | string | "ShipmentInvoice" |
| status | string | "processed" |
| shipment_ |
string | Identifier of the adjusted shipment, begins with "shp_" |
| tracking_ |
string | The tracking code of the adjusted shipment |
| label_ |
date | Date the label was created |
| quoted_ |
string | Amount originally quoted for the shipment |
| quoted_ |
string | "USD" |
| initially_ |
string | Amount initially paid for the shipment |
| initially_ |
string | "USD" |
| initially_ |
string | Payment log identifier for the initial charge |
| adjustment_ |
string | Reason for the adjustment, e.g. "weight_correction" |
| adjustment_ |
string | Amount of the adjustment |
| invoice_ |
datetime | When the adjustment was recorded |
| invoice_ |
string | "adjustment" |
| invoice_ |
string | Amount of the invoice |
| invoice_ |
string | "USD" |
| invoice_ |
string | Payment log identifier for the adjustment charge |
| total_ |
string | Total cost after the adjustment |
| carrier_ |
string | Identifier of the carrier account used |
| carrier | string | Name of the carrier |
| claimed_ |
object | What the label was bought with, such as { "parcel": { "weight": 32.0 }, "zone": 8 }
|
| captured_ |
object | What the carrier measured, in the same shape as claimed_details
|
Scan Form Events
scan_form.updated
Example
resultpayload:
{
"id": "sf_...",
"object": "ScanForm",
"tracking_codes": [
"9405500106024190341287",
"9405500106024190341294"
],
"address": {
"id": "adr_...",
"object": "Address",
"created_at": "2026-10-20T15:04:11Z",
"updated_at": "2026-10-20T15:04:11Z",
"name": "Jane Smith",
"company": "Acme Goods",
"street1": "417 Montgomery St",
"street2": "Floor 5",
"city": "San Francisco",
"state": "CA",
"zip": "94104",
"country": "US",
"phone": "4155550100",
"email": "shipping@acme.example",
"residential": null,
"verifications": null
},
"message": null,
"batch_id": null,
"form": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp...",
"reference": "order-1042",
"status": "ready",
"form_url": "https://www.vanlo.com/rails/active_storage/blobs/proxy/.../scan_form.pdf",
"created_at": "2026-10-20T15:06:40Z",
"updated_at": "2026-10-20T15:06:40Z"
}
Sent when a scan form is created or its status changes. The result is a ScanForm object.
| Parameter | Type | Specification |
|---|---|---|
| id | string | Unique identifier of the scan form, begins with "sf_" |
| object | string | "ScanForm" |
| status | string | Current status of the scan form |
| tracking_ |
string[] | Tracking codes included on the form |
| address | Address | Origin address, if available |
| message | string | Error message, if the form failed |
| warnings | object | Shipments left off a ready scan form: each shipment id maps to a list of the reasons. Present only when there are some |
| batch_ |
string | Identifier of the associated batch, if any, begins with "batch_" |
| reference | string | Your reference for the scan form, if provided |
| form_ |
string | URL of the generated scan form document |
| created_ |
datetime | When the scan form was created |
| updated_ |
datetime | When the scan form was last updated |
Errors
The Vanlo API answers every failed request with a standard HTTP status and an error body. The
status gives the class of problem; error.code says exactly what went wrong.
Error Object
A Create a Shipment request without
to_address:
{
"error": {
"code": "BAD_REQUEST",
"message": "Bad request, please check params and retry. Request ID: 6f1c2e4a-9b3d-4e8f-a1c2-5d7e8f9a0b1c",
"errors": [
{ "field": "to_address", "message": "is missing" }
]
}
}
Every error response holds a single error object.
| Parameter | Type | Specification |
|---|---|---|
| code | string | Stable, machine-readable code such as BAD_REQUEST. Handle errors by this value. |
| message | string | Human-readable description, ending with the request ID for support. The wording can change, so never match on it. |
| errors | object[] | One { field, message } entry for each field that was missing or invalid. |
| details | object | Extra hints, present only where the endpoint sets them, such as the scan-form ids returned on a scan-form scoping error. |
A few errors also return the affected resource, with its fields at the top level of the body
next to error. A 409 CONFLICT on a shipment custom_id does this, as shown under
Create a Shipment.
Client errors
A 4xx status means the request is the problem, and the same request fails the same way again,
so fix it before retrying. Any endpoint can return these errors. One specific to a single call,
such as PAYMENT_REQUIRED when buying a label, is listed under that call's Returns.
CARRIER_SERVICE_UNAVAILABLE, LOCKED and TOO_MANY_REQUESTS clear on their own. Retry them
with backoff, waiting the Retry-After header or error.details.retry_after when the response
carries one.
| Code | Status | When it happens |
|---|---|---|
| BAD_ |
400 | The request is malformed and cannot be parsed or routed. |
| UNAUTHORIZED | 401 | The API key is missing or invalid. |
| FORBIDDEN | 403 | The key lacks permission for this resource. |
| IP_ |
403 | The request comes from an IP address that is not on the key's allowlist. |
| NOT_ |
404 | The id or path does not exist. |
| NOT_ |
406 | The Accept header asks for a representation the API cannot return. |
| CONFLICT | 409 | The same entity is created or updated twice at once, or a custom_id shipment can no longer change: its label is bought or being bought, its 72-hour window has passed, or, on Create an Order, it already belongs to one. |
| UNPROCESSABLE_ |
422 | The request is understood but semantically invalid. |
| PARAMETER.FORBIDDEN | 422 | The request sends a field it may not set. |
| INVALID_ |
422 | One or more parameters are invalid; error.errors lists them. |
| PARAMETER.REQUIRED | 422 | A required field is missing; error.errors names it. |
| PARAMETER.INVALID_ |
422 | A field has the wrong type. |
| CARRIER_ |
424 | The carrier cannot be used right now: it failed the purchase, or Vanlo paused calls to it after repeated timeouts and will resume on its own. |
| LOCKED | 429 | Another operation holds the lock, such as a burst of scan-form requests. On a purchase, Vanlo is still confirming an earlier purchase of that shipment with the carrier. |
| TOO_ |
429 | More label purchases are in flight for your account than Vanlo will carry. Other endpoints use this code for their own limits, listed under their Returns. |
Server errors
A 5xx status is not caused by the request and is usually safe to retry with backoff. If
INTERNAL_SERVER_ERROR persists, contact support@vanlo.com.
| Code | Status | When it happens |
|---|---|---|
| INTERNAL_ |
500 | An unexpected error on Vanlo's side. |
| MAINTENANCE | 503 | Scheduled maintenance. |
| CARRIER_ |
503 | The carrier answered a label purchase with success, but Vanlo could not read the reply, so the label may exist. |
| TIMEOUT_ |
504 | The request used up its 60-second budget, counted from its arrival, possibly before a carrier was called. On a purchase, a label may still be produced afterwards. |
| CARRIER_ |
504 | The carrier gave no usable answer: it passed the 30-second limit, did not reply, or returned a gateway error. On a refund, an unreadable success reply also returns this. |