API Documentation
Getting Started
Kiloships provides a simple and powerful API for creating and managing shipping labels. Our documentation will help you get up and running quickly.
Base URL
All API requests should be made to:
https://kiloships.com/apiAPI Endpoints
Create Shipping Label
https://kiloships.com/api/shipping-labels/domesticCreate a new domestic shipping label
Get Domestic Price
https://kiloships.com/api/shipping-labels/domestic/priceGet a free price quote for a domestic package — no label is created and no balance is consumed
List Shipping Labels
https://kiloships.com/api/shipping-labelsRetrieve shipping labels for your organization with filters and pagination
Cancel Shipping Label
https://kiloships.com/api/shipping-labels/domestic/{trackingNumber}Cancel a domestic shipping label using its tracking number
Create GDE Label
https://kiloships.com/api/shipping-labels/gdeCreate a Global Direct Entry (GDE) label — USPS Ground Advantage or Priority Mail
Cancel GDE Label
https://kiloships.com/api/shipping-labels/gde/{trackingNumber}Cancel a GDE label and request a refund
Register Tracking Numbers
https://kiloships.com/api/tracking/registerRegister tracking numbers for continuous monitoring (one-time charge per number)
Track Package
https://kiloships.com/api/tracking/{trackingNumber}Get the stored tracking snapshot for a registered number (registration required, no per-request fee)
City/State Lookup
https://kiloships.com/api/addresses/city-state?zipCode={zipCode}Get city and state information for a ZIP code
ZIP Code Lookup
https://kiloships.com/api/addresses/zipcodeGet ZIP code information for an address
Address Standardization
https://kiloships.com/api/addresses/addressGet standardized address information
Get Organization Balance
https://kiloships.com/api/organizations/balanceGet the current balance of your organization
Create Domestic Label
Create a domestic shipping label for USPS services. This endpoint handles label generation, tracking number assignment, and automatic rate calculations.
Endpoint
https://kiloships.com/api/shipping-labels/domesticAuthentication
Requires an API key to be included in the request headers:
Authorization: Bearer YOUR_API_KEYRequest Body
Shipment Object
uniqueReferenceId (optional) - A client-supplied reference ID (max 255 characters). Must be unique within your organization. Returns HTTP 409 if a duplicate active label already has this ID.
async (optional) - Boolean flag for asynchronous label creation (default: false)
addressTo (required) - Destination address object containing:
name(string) - Recipient's full namestreet1(string) - Primary street addressstreet2(string, optional) - Secondary address linecity(string) - City namestate(string) - Two-letter state codezip(string) - 5-digit or 9-digit ZIP codecountry(string) - Two-letter country code (default: "US")ignoreBadAddress(boolean, optional) - When set to true, bypasses address validation and allows label creation even with unverified addresses. When false or omitted, address validation is enforced (default: false)
addressFrom Object
Sender's address with the same fields as addressTo, including:
name(string) - Sender's full namestreet1(string) - Primary street addressstreet2(string, optional) - Secondary address linecity(string) - City namestate(string) - Two-letter state codezip(string) - 5-digit or 9-digit ZIP codecountry(string) - Two-letter country code (default: "US")ignoreBadAddress(boolean, optional) - When set to true, bypasses address validation and allows label creation even with unverified addresses. When false or omitted, address validation is enforced (default: false)
Parcels Array
Array containing a single parcel object with:
weight(string) - Package weightmassUnit(string) - Weight unit ("oz" or "lb")length(string) - Package lengthwidth(string) - Package widthheight(string) - Package heightdistanceUnit(string) - Dimension unit ("in" or "cm")
Service Level
servicelevelToken (required) - One of:
usps_ground_advantage- USPS Ground Advantageusps_priority- USPS Priority Mailusps_priority_express- USPS Priority Mail Expressusps_media_mail- USPS Media Mail
Metadata
metadata (optional) - Array of strings for custom messages or references
Customs Form
The customsForm object is optional and is used for international shipments that require customs documentation.
Fields
contentComments- Optional comments about the shipment contentscustomsContentType- Type of contents being shipped:- MERCHANDISE
- SAMPLE
- GIFT
- DOCUMENTS
- RETURNED_GOODS
- OTHER
contents- Array of items in the shipment, each containing:itemDescription- Description of the itemitemQuantity- Number of itemsitemTotalValue- Total value of the itemsweightUOM- Unit of measure for weight (oz or lb)itemTotalWeight- Total weight of the itemsHSTariffNumber- Optional Harmonized System tariff numbercountryofOrigin- Country where the item was manufactureditemCategory- Optional category of the itemitemSubcategory- Optional subcategory of the item
Special Requirements for Military and Diplomatic Addresses
Additional information is required when shipping to or from:
- MPOs (Military Post Offices)
- APOs (Army Post Offices)
- FPOs (Fleet Post Offices)
- DPOs (Diplomatic Post Offices)
- U.S. Possessions, Territories, and Freely Associated States (PTFAS)
For these addresses, you must include:
- Complete unit information in the address
- Valid military or diplomatic ZIP code
- Proper military or diplomatic state code (AA, AE, AP)
- Detailed item descriptions in the customs form
- Accurate country of origin for all items
Example Customs Form
1{
2 "contentComments": "Sample shipment for testing",
3 "customsContentType": "MERCHANDISE",
4 "contents": [
5 {
6 "itemDescription": "Cotton T-Shirt",
7 "itemQuantity": 2,
8 "itemTotalValue": 29.99,
9 "weightUOM": "oz",
10 "itemTotalWeight": 8,
11 "HSTariffNumber": "6109.10.0000",
12 "countryofOrigin": "US",
13 "itemCategory": "Clothing",
14 "itemSubcategory": "T-Shirts"
15 }
16 ]
17}Example Request
1curl -X POST https://kiloships.com/api/shipping-labels/domestic \
2 -H "Authorization: Bearer YOUR_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "shipment": {
6 "async": false,
7 "parcels": [{
8 "width": "0.25",
9 "height": "6",
10 "length": "9",
11 "weight": "0.5",
12 "massUnit": "lb",
13 "distanceUnit": "in"
14 }],
15 "addressTo": {
16 "zip": "63118",
17 "city": "St. Louis",
18 "name": "asd Doe",
19 "state": "MO",
20 "country": "US",
21 "street1": "1100 Wyoming",
22 "street2": "Suite 150"
23 },
24 "addressFrom": {
25 "zip": "63116",
26 "city": "St. Louis",
27 "name": "John Smith",
28 "state": "MO",
29 "country": "US",
30 "street1": "4120 Bingham"
31 }
32 },
33 "servicelevelToken": "usps_ground_advantage",
34 "uniqueReferenceId": "ORDER-12345",
35 "metadata": [
36 "Message 1",
37 "Message 2",
38 "Message 3"
39 ]
40 }'Response Fields
rate- Object containing pricing and service detailsparcel- Object containing package detailsstatus- Current label statuslabelUrl- URL to download the shipping label PDFtrackingNumber- Carrier tracking numberuniqueReferenceId- The client-supplied reference ID, if provided
Example Response
1{
2 "rate": {
3 "amount": "3.74",
4 "currency": "USD",
5 "objectId": "DUXP0XXXU101080",
6 "provider": "usps",
7 "amountLocal": 3.74,
8 "currencyLocal": "USD",
9 "carrierAccount": "",
10 "servicelevelName": "usps_ground_advantage",
11 "servicelevelToken": "usps_ground_advantage"
12 },
13 "parcel": {
14 "weight": 0.5,
15 "weightUOM": "LB"
16 },
17 "status": "CREATED",
18 "labelUrl": "https://photo.kiloships.com/shipping-labels/domestic/label-1-1743838485434-9200190384072900005162.pdf",
19 "messages": [],
20 "metadata": [
21 "Message 1",
22 "Message 2",
23 "Message 3"
24 ],
25 "objectId": "DUXP0XXXU101080",
26 "objectOwner": "",
27 "objectState": "CREATED",
28 "objectCreated": "2025-04-05T07:34:46.109Z",
29 "objectUpdated": "2025-04-05T07:34:46.109Z",
30 "trackingNumber": "9200190384072900005162",
31 "trackingStatus": "CREATED",
32 "trackingUrlProvider": "USPS",
33 "labelImageUrl": "https://photo.kiloships.com/shipping-labels/domestic/label-1-1743838485434-9200190384072900005162.pdf",
34 "chargeAmount": 3.74,
35 "uniqueReferenceId": "ORDER-12345"
36}Get Domestic Price
Get a price quote for a domestic USPS package. This endpoint is free — it consumes no organization balance and creates no shipping label. totalBasePrice is exactly what POST /shipping-labels/domestic would bill for the same package.
Endpoint
https://kiloships.com/api/shipping-labels/domestic/priceAuthentication
Requires an API key to be included in the request headers, or an authenticated session:
Authorization: Bearer YOUR_API_KEYRequest Body
Shipment Object
parcels (required) - Array with exactly one parcel object. Unlike POST /shipping-labels/domestic, which accepts several parcels and prices the first, this endpoint returns a single price and rejects a request with zero or more than one parcel.
addressTo / addressFrom (required) - Only zip is required and validated. You can pass the same full address object used for label creation; the other fields are accepted and ignored.
Parcel Object
weight(string or number) - Package weightmassUnit-"oz"or"lb". The server converts to pounds before pricing.length,width,height(string or number) - Package dimensionsdistanceUnit-"in"or"cm". The server converts to inches before pricing.
Service Level
servicelevelToken (required) - One of:
usps_ground_advantageusps_priorityusps_priority_expressusps_media_mail
usps_first_class is not supported here — use POST /shipping-labels/indicia-imb instead. Any other unrecognized value is rejected with a 400; there is no silent fallback to Priority Mail.
Mailing Date
mailingDate (optional) - YYYY-MM-DD. Defaults to today. Must be within today through today + 7 days, matching what USPS accepts.
Example Request
1curl -X POST https://kiloships.com/api/shipping-labels/domestic/price \
2 -H "Authorization: Bearer YOUR_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "shipment": {
6 "parcels": [{
7 "weight": "2",
8 "massUnit": "lb",
9 "length": "24",
10 "width": "12",
11 "height": "10",
12 "distanceUnit": "in"
13 }],
14 "addressTo": { "zip": "94105" },
15 "addressFrom": { "zip": "10001" }
16 },
17 "servicelevelToken": "usps_priority"
18 }'Response Fields
totalBasePrice is the amount you pay — the same amount POST /shipping-labels/domestic will bill for this exact package. Bill from this field, not price.
rates[0].price is the postage share of that amount: totalBasePrice − Σ fees. The payload always reconciles: price + Σ fees === totalBasePrice. With no fees, the two are equal.
Despite the USPS-shaped field names, neither price field is USPS list postage — both derive from what this platform actually charges. There is no separate chargeAmount field; totalBasePrice already is the charge.
rates[0].zone is the raw USPS zone string.
rates- Always exactly one entryrates[0].fees[]- USPS fee line items (raw, unmodified)rates[0].mailClass,productName,productDefinition- Descriptive USPS passthrough fieldsrates[0].warnings- Optional USPS advisory notices, present only when USPS returns them
Example Response
1{
2 "totalBasePrice": 80.95,
3 "rates": [
4 {
5 "SKU": "DPXR0XXXXC08210",
6 "description": "Priority Mail Nonstandard Dimensional Rectangular",
7 "price": 76.45,
8 "weight": 2,
9 "fees": [
10 { "name": "Nonstandard Length > 22", "SKU": "D811XXNXXXX0000", "price": 4.50 }
11 ],
12 "startDate": "2026-07-12",
13 "mailClass": "PRIORITY_MAIL",
14 "zone": "08",
15 "warnings": [
16 { "warningCode": "002", "warningDescription": "Dimensional weight is greater than provided weight. Dimensional rate returned." },
17 { "warningCode": "001", "warningDescription": "Contract rate not found for request. Published rate returned." }
18 ]
19 }
20 ]
21}80.95 is what the customer pays. 76.45 + 4.50 = 80.95 — the payload reconciles exactly. Captured from a live sandbox quote; productName / productDefinition and warnings are present only when USPS returns them for the matched rate.
Status Codes
200- Price computed successfully400- Invalid request body, unsupported/unrecognized service level token, or USPS rejected the package as unpriceable401- Missing or invalid authentication403- Authenticated account has no associated organization502- USPS pricing upstream unavailable or timed out500- Unexpected server error
List Shipping Labels
Retrieve shipping labels that belong to your organization. This endpoint supports filtering, sorting, and page-based pagination, and accepts both Bearer API keys and authenticated sessions.
Endpoint
https://kiloships.com/api/shipping-labelsAuthentication
Use an API key in the Authorization header, or call the endpoint from an authenticated user session.
Authorization: Bearer YOUR_API_KEYQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number to return. Default is 1. |
pageSize | integer | No | Number of labels to return per page. Default is 10 and maximum is 1000. |
status | string | No | Filter by label status such as completed, pending, or cancelled. |
labelType | string | No | Filter by label type, for example DOMESTIC. |
search | string | No | Search across tracking number, recipient name, and address fields. |
sortBy | string | No | Sort field. Allowed values: createdAt, postage, chargeAmount, trackingNumber, status, labelType. |
sortOrder | string | No | Sort direction. Use asc or desc. Default is desc. |
fromDate | ISO datetime | No | Return labels created on or after this timestamp. |
toDate | ISO datetime | No | Return labels created on or before this timestamp. |
Example Request
1curl -X GET "https://kiloships.com/api/shipping-labels?page=1&pageSize=100&status=completed&labelType=DOMESTIC&search=st.%20louis&sortBy=createdAt&sortOrder=desc&fromDate=2026-03-01T00:00:00.000Z&toDate=2026-03-15T23:59:59.999Z" \
2 -H "Authorization: Bearer YOUR_API_KEY"Example Response
1{
2 "success": true,
3 "data": [
4 {
5 "trackingNumber": "9405511298370938472938",
6 "status": "completed",
7 "toAddress": {
8 "name": "Jane Doe",
9 "street1": "1100 Wyoming",
10 "city": "St. Louis",
11 "state": "MO",
12 "zip": "63118"
13 },
14 "fromAddress": {
15 "name": "John Smith",
16 "street1": "4120 Bingham",
17 "city": "St. Louis",
18 "state": "MO",
19 "zip": "63116"
20 },
21 "mailClass": "usps_ground_advantage",
22 "zone": 5,
23 "weight": 0.5,
24 "weightUnit": "LB",
25 "length": 9,
26 "width": 6,
27 "height": 0.25,
28 "dimensionsUnit": "IN",
29 "chargeAmount": 4.17,
30 "labelImage": "https://photo.kiloships.com/shipping-labels/domestic/label-29-1743838485434-9405511298370938472938.pdf",
31 "mailingDate": "2026-03-15",
32 "cancelledAt": null,
33 "disputedAt": null,
34 "adjustedAt": null,
35 "cancelledFee": null,
36 "adjustedFee": null,
37 "createdAt": "2026-03-15T09:12:44.000Z",
38 "updatedAt": "2026-03-15T09:12:46.000Z"
39 }
40 ],
41 "meta": {
42 "total": 245,
43 "page": 1,
44 "pageSize": 100,
45 "totalPages": 3,
46 "filteredBy": {
47 "status": "completed",
48 "labelType": "DOMESTIC",
49 "search": "st. louis",
50 "sortBy": "createdAt",
51 "sortOrder": "desc",
52 "fromDate": "2026-03-01T00:00:00.000Z",
53 "toDate": "2026-03-15T23:59:59.999Z"
54 }
55 }
56}Cancel Domestic Label
Endpoint
https://kiloships.com/api/shipping-labels/domestic/{trackingNumber}Cancel a domestic shipping label using its tracking number. This endpoint supports both session-based authentication and API key authentication.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| trackingNumber | string | Yes | The tracking number of the label to cancel |
Authentication
This endpoint supports two authentication methods:
- Session Authentication: Use when making requests from a web browser with an active session
- API Key Authentication: Use when making programmatic requests with an API key
Only one authentication method is required. The endpoint will first check for session authentication, and if that fails, it will check for API key authentication.
Example Request
1curl -X DELETE \
2 "https://kiloships.com/api/shipping-labels/domestic/9405511298370938473298" \
3 -H "Authorization: Bearer YOUR_API_KEY"Example Response
1{
2 "success": true,
3 "data": {
4 "id": 123,
5 "trackingNumber": "9405511298370938473298",
6 "status": "CANCELLED",
7 "cancelledAt": "2024-04-21T12:00:00Z"
8 },
9 "message": "Shipping label successfully canceled"
10}The status field indicates the current state of the label:
CANCELLED- The label has been successfully canceledDISPUTED- A refund request has been initiated for the label
Get Label by Reference ID
Retrieve a shipping label using your own reference ID. Useful when you want to look up a label without storing the internal tracking number on your side.
Endpoint
https://kiloships.com/api/shipping-labels/reference/{uniqueReferenceId}Authentication
Requires an API key in the Authorization header:
Authorization: Bearer YOUR_API_KEYPath Parameter
| Parameter | Type | Required | Description |
|---|---|---|---|
uniqueReferenceId | string | Yes | The reference ID you provided when creating the label. |
Example Request
1curl -X GET 'https://kiloships.com/api/shipping-labels/reference/ORDER-12345' \
2 -H 'Authorization: Bearer YOUR_API_KEY'Example Response
1{
2 "rate": {
3 "amount": "3.74",
4 "currency": "USD",
5 "objectId": "DUXP0XXXU101080",
6 "provider": "usps",
7 "amountLocal": 3.74,
8 "currencyLocal": "USD",
9 "carrierAccount": "",
10 "servicelevelName": "usps_ground_advantage",
11 "servicelevelToken": "usps_ground_advantage"
12 },
13 "parcel": {
14 "weight": 0.5,
15 "weightUOM": "LB"
16 },
17 "status": "CREATED",
18 "labelUrl": "https://photo.kiloships.com/shipping-labels/domestic/label-1-1743838485434-9200190384072900005162.pdf",
19 "messages": [],
20 "metadata": [],
21 "objectId": "DUXP0XXXU101080",
22 "objectOwner": "",
23 "objectState": "CREATED",
24 "objectCreated": "2025-04-05T07:34:46.109Z",
25 "objectUpdated": "2025-04-05T07:34:46.109Z",
26 "trackingNumber": "9200190384072900005162",
27 "trackingStatus": "CREATED",
28 "trackingUrlProvider": "USPS",
29 "labelImageUrl": "https://photo.kiloships.com/shipping-labels/domestic/label-1-1743838485434-9200190384072900005162.pdf",
30 "chargeAmount": 3.74,
31 "uniqueReferenceId": "ORDER-12345"
32}Error Responses
| Status | Description |
|---|---|
404 | No active label found for the given reference ID within your organization. |
401 | Missing or invalid API key. |
Create GDE Label
Create a Global Direct Entry (GDE) shipping label. GDE labels are USPS Ground Advantage and Priority Mail services fulfilled through our carrier partner Gori, priced and returned to you exactly like any other USPS label.
Endpoint
https://kiloships.com/api/shipping-labels/gdeYour organization must have GDE labels enabled by an administrator before this endpoint will accept requests.
Authentication
Requires an API key in the Authorization header, or an authenticated session:
Authorization: Bearer YOUR_API_KEYRequest Body
Service Level
servicelevelToken (required) - One of:
usps_ground_advantage- USPS Ground Advantageusps_priority- USPS Priority Mail
GDE supports only these two service levels — no Priority Mail Express or Media Mail.
shipment.addressTo / shipment.addressFrom
name(string, required)street1(string, required)street2(string, optional)city(string, required)state(string, required)zip(string, required) - 5-digit or 9-digit (ZIP+4) US ZIP codecountry(string, required) - 2-letter ISO country code
GDE ships within the US only. There are no phone or email fields on either address.
shipment.parcels
Array containing exactly one parcel object with:
weight(string) - Package weightmassUnit(string) - Weight unit ("oz" or "lb")length(string) - Package lengthwidth(string) - Package widthheight(string) - Package heightdistanceUnit(string) - Dimension unit ("in" or "cm")
Weight and dimensions are converted to ounces/inches automatically if submitted in pounds/centimeters.
Other fields
uniqueReferenceId(optional) - A client-supplied reference ID, max 30 characters. Must be unique per organization among active labels. Returns HTTP 409 if a duplicate is submitted.mailingDate(optional) -YYYY-MM-DD. Defaults to today if omitted.metadata(optional) - Array of up to 2 strings, each max 30 characters. Unlike domestic labels, GDE does not print metadata on the label image — instead each entry is sent to our carrier partner as a shipment reference field, and is also echoed back in the response.
There is no customsForm field for GDE labels — customs declarations are not supported on this endpoint.
Example Request
1curl -X POST https://kiloships.com/api/shipping-labels/gde \
2 -H "Authorization: Bearer YOUR_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "servicelevelToken": "usps_ground_advantage",
6 "uniqueReferenceId": "ORDER-12345",
7 "metadata": ["Warehouse A", "Fragile"],
8 "shipment": {
9 "parcels": [{
10 "weight": "16",
11 "massUnit": "oz",
12 "length": "10",
13 "width": "8",
14 "height": "6",
15 "distanceUnit": "in"
16 }],
17 "addressTo": {
18 "name": "Jane Doe",
19 "street1": "456 Oak Ave",
20 "city": "Long Beach",
21 "state": "CA",
22 "zip": "90001",
23 "country": "US"
24 },
25 "addressFrom": {
26 "name": "John Smith",
27 "street1": "123 Main St",
28 "city": "New York",
29 "state": "NY",
30 "zip": "10001",
31 "country": "US"
32 }
33 }
34 }'Response Fields
rate- Pricing and service details (provideris always"usps")parcel- Package weight, normalized to ouncesstatus- Current label status (completedon success)labelUrl- URL to download the shipping label PDFtrackingNumber- Carrier tracking numbermetadata- Echoed back from the requestuniqueReferenceId- The client-supplied reference ID, if provided
Example Response
1{
2 "rate": {
3 "amount": "15.01",
4 "amountLocal": 15.01,
5 "currency": "USD",
6 "provider": "usps",
7 "servicelevelName": "USPS Ground Advantage",
8 "servicelevelToken": "usps_ground_advantage"
9 },
10 "parcel": {
11 "weight": 16,
12 "weightUOM": "oz"
13 },
14 "labelUrl": "https://photo.kiloships.com/shipping-labels/gde/label-2-1785212707646-9234690327908700943823.pdf",
15 "trackingNumber": "9234690327908700943823",
16 "status": "completed",
17 "metadata": ["Warehouse A", "Fragile"],
18 "uniqueReferenceId": "ORDER-12345"
19}Error Responses
| Status | Description |
|---|---|
400 | Request validation failed (missing/invalid field). The message names the specific field. |
401 | Missing or invalid API key / session. |
402 | Insufficient organization balance. |
403 | GDE labels are not enabled for your organization. Contact an administrator. |
409 | An active label with this uniqueReferenceId already exists. |
503 | The GDE label service is temporarily unavailable. Retry after the interval in the Retry-After header. |
422 / 502 | The carrier rejected the request (e.g. an undeliverable ZIP code) or returned an error. The message describes the carrier-side issue. |
Cancel GDE Label
Endpoint
https://kiloships.com/api/shipping-labels/gde/{trackingNumber}Cancel a GDE shipping label and request a refund from the carrier. This endpoint works even if GDE labels have since been disabled for your organization — cancelling an existing label is always allowed.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| trackingNumber | string | Yes | The tracking number of the label to cancel |
Authentication
Requires an API key in the Authorization header, or an authenticated session.
Example Request
1curl -X DELETE \
2 "https://kiloships.com/api/shipping-labels/gde/9234690327908700943823" \
3 -H "Authorization: Bearer YOUR_API_KEY"Example Response
1{
2 "success": true,
3 "data": {
4 "id": "500418838",
5 "refund": {
6 "amount": 10.01,
7 "status": "refunded",
8 "created_at": "2026-07-28 04:17:01",
9 "updated_at": "2026-07-28 04:17:01"
10 }
11 },
12 "message": "GDE label successfully cancelled"
13}The label's internal status is updated based on the carrier's refund outcome:
cancelled- The refund completed and the label is fully cancelleddisputed- The refund is still processing on the carrier's side
Error Responses
| Status | Description |
|---|---|
404 | No GDE label found for this tracking number within your organization. |
409 | The label is already cancelled or disputed. |
SCAN Form API
The SCAN Form API allows you to create USPS SCAN (Shipment Confirmation Acceptance Notice) forms for multiple tracking numbers. This form serves as proof of shipment for multiple packages in a single document.
Create SCAN Form
https://kiloships.com/api/scan-formCreate a USPS SCAN form for multiple tracking numbers
Authentication
Requires an API key to be included in the request headers:
Authorization: Bearer YOUR_API_KEYRequest Body
Required Fields:
mailingDate- Format: YYYY-MM-DDentryFacilityZIPCode- 5-digit or 9-digit ZIP codedestinationEntryFacilityType- One of:- "NONE"
- "DESTINATION_NETWORK_DISTRIBUTION_CENTER"
- "DESTINATION_SECTIONAL_CENTER_FACILITY"
- "DESTINATION_DELIVERY_UNIT"
- "DESTINATION_SERVICE_HUB"
fromAddress- Sender's address objectshipment.trackingNumbers- Array of tracking numbers
fromAddress Object:
streetAddress- Primary street address (required)city- City name (required)state- Two-letter state code (required)ZIPCode- 5-digit or 9-digit ZIP code (required)firstName- Recipient's first name (optional)lastName- Recipient's last name (optional)firm- Company name (optional)secondaryAddress- Suite, Apt, etc. (optional)ZIPPlus4- ZIP+4 code (optional)urbanization- Urbanization code for Puerto Rico (optional)ignoreBadAddress- Bypass address validation (optional)
Optional Fields:
overwriteMailingDate- Boolean to overwrite mailing date
Example Request
1{
2 "mailingDate": "2024-02-20",
3 "entryFacilityZIPCode": "12345",
4 "destinationEntryFacilityType": "NONE",
5 "fromAddress": {
6 "streetAddress": "123 Main St",
7 "city": "Anytown",
8 "state": "CA",
9 "ZIPCode": "12345"
10 },
11 "shipment": {
12 "trackingNumbers": [
13 "9400100000000000000000",
14 "9400100000000000000001"
15 ]
16 }
17}Response Fields
form- Form type identifierimageType- Type of image (PDF, TIFF, etc.)labelType- Type of labelmailingDate- Confirmed mailing datescanFormImage- URL to download the formmanifestNumber- Optional manifest numbershipment- Object containing confirmed tracking numbersfromAddress- Confirmed sender address
Example Success Response
1{
2 "form": "5630",
3 "imageType": "PDF",
4 "labelType": "8.5x11LABEL",
5 "mailingDate": "2024-02-20",
6 "overwriteMailingDate": false,
7 "entryFacilityZIPCode": "12345",
8 "destinationEntryFacilityType": "NONE",
9 "shipment": {
10 "trackingNumbers": [
11 "9400100000000000000000",
12 "9400100000000000000001"
13 ]
14 },
15 "manifestNumber": "123456789",
16 "fromAddress": {
17 "streetAddress": "123 Main St",
18 "city": "Anytown",
19 "state": "CA",
20 "ZIPCode": "12345"
21 },
22 "scanFormImage": "https://your-cloudflare-url.com/scan-forms/form.pdf"
23}Important Notes
- All tracking numbers must belong to your organization
- The SCAN form will be generated as a PDF and stored in Cloudflare R2
- The mailing date must be in YYYY-MM-DD format
- ZIP codes must be either 5 digits or 9 digits (with hyphen)
- All required fields are validated before making the request to USPS
Package Tracking
Register tracking numbers once, then read continuously refreshed status snapshots — no per-request tracking fees. Pair with webhooks to get pushed updates the moment a status changes.
Service enablement required
The tracking service is disabled by default. Contact your account administrator or support to enable it for your organization before registering numbers.
1. Register Tracking Numbers
https://kiloships.com/api/tracking/registerBatch up to 100 numbers per request. Strict USPS format validation. Each number is charged once per registration (re-registering the same number is idempotent — never double-charged). Registrations expire 60 days after creation.
1curl -X POST 'https://kiloships.com/api/tracking/register' \
2 -H 'Authorization: Bearer YOUR_API_KEY' \
3 -H 'Content-Type: application/json' \
4 -d '{ "trackingNumbers": ["9400111899223100000001"] }'1{
2 "success": true,
3 "results": [
4 {
5 "trackingNumber": "9400111899223100000001",
6 "status": "registered",
7 "trackingType": "external",
8 "chargeAmount": 0.03
9 }
10 ],
11 "summary": { "registered": 1, "alreadyRegistered": 0, "invalid": 0, "insufficientBalance": 0 }
12}2. Query the Snapshot
https://kiloships.com/api/tracking/{trackingNumber}Returns the latest tracking information for a registered number — no extra charge per request. Tracking data refreshes automatically: shortly after registration, then periodically (typically every 4–8 hours) until the package is delivered. Unregistered numbers return 404 with code NOT_REGISTERED.
1{
2 "success": true,
3 "data": {
4 "trackingNumber": "9400111899223100000001",
5 "trackingType": "external",
6 "status": "Moving Through Network",
7 "statusCategory": "IN_TRANSIT",
8 "events": [
9 {
10 "status": "Departed USPS Regional Facility",
11 "location": "LOS ANGELES CA DISTRIBUTION CENTER",
12 "datetime": "June 10, 2026, 8:12 pm"
13 }
14 ],
15 "expectedDeliveryDate": "Saturday, June 13, 2026",
16 "expectedDeliveryTime": "by 9:00pm",
17 "bannerMessage": null,
18 "pickedAt": "2026-06-09T18:02:11.000Z",
19 "deliveredAt": null
20 }
21}Status Vocabulary
statusCategory is a fixed vocabulary; status is the raw USPS status text as displayed on usps.com (free-form, changes more often).
| statusCategory | Meaning |
|---|---|
REGISTERED | Number registered; first update not yet available |
PICKED | USPS accepted / picked up the package |
IN_TRANSIT | Package is moving through the USPS network |
DELIVERED | Package delivered (final status) |
NOT_AVAILABLE | USPS has no information for this number yet |
Webhooks
Get signed HTTP notifications pushed to your server whenever a registered tracking number's status changes — no need to check for updates yourself.
Subscribe
Create and manage webhook subscriptions in your dashboard under Tools → Webhooks:
- Add your HTTPS callback URL (plain HTTP is not accepted). The signing
secretis shown once on creation — copy and store it immediately; it cannot be retrieved later. - Use the Test button to send a sample signed delivery to your endpoint and confirm connectivity before going live.
- View last-notified time and remove subscriptions you no longer need.
Event Payload
The tracking.updated event fires when the raw USPS status text changes. The body is an array — one entry per changed number in the batch. Each entry has the same shape as the GET /tracking/{trackingNumber} snapshot data object, so one parser handles both.
1[
2 {
3 "trackingNumber": "9400111899223100000001",
4 "trackingType": "external",
5 "status": "Out for Delivery",
6 "statusCategory": "IN_TRANSIT",
7 "events": [
8 {
9 "status": "Out for Delivery",
10 "location": "LOS ANGELES, CA 90001",
11 "datetime": "June 13, 2026, 7:42 am"
12 }
13 ],
14 "expectedDeliveryDate": "Saturday, June 13, 2026",
15 "expectedDeliveryTime": "by 9:00pm",
16 "bannerMessage": null,
17 "pickedAt": "2026-06-09T18:02:11.000Z",
18 "deliveredAt": null
19 }
20]| Header | Value |
|---|---|
KiloShips-Event | tracking.updated (real) or tracking.test (Test button) |
KiloShips-Signature | t={unix_seconds},v1={hmac_hex} |
X-Webhook-ID | Unique delivery ID — dedupe retried deliveries on it |
User-Agent | kiloships-us/1.0 |
Verify the Signature
v1 is HMAC-SHA256 of `${t}.${rawBody}` keyed with your subscription secret. Always compare with a constant-time function:
1const crypto = require('crypto');
2
3function verifyWebhook(req, rawBody, secret) {
4 const header = req.headers['kiloships-signature'] || '';
5 const match = header.match(/^t=(\d+),v1=([0-9a-f]{64})$/);
6 if (!match) return false;
7
8 const [, ts, theirSig] = match;
9 const expected = crypto
10 .createHmac('sha256', secret)
11 .update(`${ts}.${rawBody}`)
12 .digest('hex');
13
14 return crypto.timingSafeEqual(
15 Buffer.from(expected, 'hex'),
16 Buffer.from(theirSig, 'hex')
17 );
18}Delivery Semantics
- Respond with any
2xxquickly (within 10 seconds) — slow responses are treated as failures. - Failed deliveries are retried up to 6 times with increasing backoff (1m, 5m, 15m, 1h, 6h, 24h — a ~31 hour window) before being marked failed permanently.
- Retries reuse the same
X-Webhook-ID— make your handler idempotent by deduplicating on it.
Address APIs
The Address APIs provide utilities for validating and standardizing address information, including city/state lookup, ZIP code lookup, and address standardization. These endpoints help ensure accurate shipping addresses and improve delivery success rates.
Pricing & Billing
The City/State Lookup, ZIP Code Lookup, and Address Standardization endpoints each cost $0.02 per successful lookup (default; may vary by account). The fee is charged only when USPS returns a successful result — failed or invalid lookups are never charged. Each call is billed independently: client retries are billed separately (no idempotency key).
If your account balance is insufficient, the request returns HTTP 402 with a structured body:
1{
2 "error": "insufficient_balance",
3 "currentBalance": 0.01,
4 "chargeAmount": 0.02,
5 "message": "Insufficient balance for address lookup"
6}City/State Lookup
Get city and state information for a given ZIP code. $0.02 per successful lookup.
Endpoint
https://kiloships.com/api/addresses/city-state?zipCode={zipCode}Parameters
zipCode (required) - 5-digit ZIP code
Response
city- City namestate- Two-letter state codeZIPCode- 5-digit ZIP code
Example Request
1curl -X GET "https://kiloships.com/api/addresses/city-state?zipCode=10001" \
2 -H "Authorization: Bearer YOUR_API_KEY"Example Response
1{
2 "city": "New York",
3 "state": "NY",
4 "ZIPCode": "10001"
5}ZIP Code Lookup
Get ZIP code information for a given address. $0.02 per successful lookup.
Endpoint
https://kiloships.com/api/addresses/zipcodeRequest Body
streetAddress(required) - Primary street addresscity(required) - City namestate(required) - Two-letter state code AA AE AL AK AP AS AZ AR CA CO CT DE DC FM FL GA GU HI ID IL IN IA KS KY LA ME MH MD MA MI MN MS MO MP MT NE NV NH NJ NM NY NC ND OH OK OR PW PA PR RI SC SD TN TX UT VT VI VA WA WV WI WYsecondaryAddress(optional) - Apartment, suite, etc.firm(optional) - Company or organization nameurbanization(optional) - Urbanization code (Puerto Rico only)
Response
address- Object containing:streetAddress- Standardized street addresscity- City namestate- Two-letter state codeZIPCode- 5-digit ZIP codeZIPPlus4- ZIP+4 code (if available)secondaryAddress- Standardized secondary address
Example Request
1curl -X POST "https://kiloships.com/api/addresses/zipcode" \
2 -H "Authorization: Bearer YOUR_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "streetAddress": "350 5th Ave",
6 "city": "New York",
7 "state": "NY",
8 "secondaryAddress": "Suite 3000"
9 }'Example Response
1{
2 "address": {
3 "streetAddress": "350 5TH AVE",
4 "secondaryAddress": "STE 3000",
5 "city": "NEW YORK",
6 "state": "NY",
7 "ZIPCode": "10118",
8 "ZIPPlus4": "0110"
9 }
10}Address Standardization
Get standardized address information and validate address components. $0.02 per successful lookup.
Endpoint
https://kiloships.com/api/addresses/addressRequest Body
streetAddress(required) - Primary street addresscity(required*) - City name (*either city or ZIP code required)state(required) - Two-letter state code AA AE AL AK AP AS AZ AR CA CO CT DE DC FM FL GA GU HI ID IL IN IA KS KY LA ME MH MD MA MI MN MS MO MP MT NE NV NH NJ NM NY NC ND OH OK OR PW PA PR RI SC SD TN TX UT VT VI VA WA WV WI WYsecondaryAddress(optional) - Apartment, suite, etc.firm(optional) - Company or organization nameurbanization(optional) - Urbanization code (Puerto Rico only)ZIPCode(optional*) - 5-digit ZIP code (*either city or ZIP code required)
Response
firm- Standardized company name (if provided)address- Object containing:streetAddress- Standardized street addressstreetAddressAbbreviation- Abbreviated street addresssecondaryAddress- Standardized secondary addresscity- Standardized city namecityAbbreviation- Abbreviated city namestate- Two-letter state codeZIPCode- 5-digit ZIP codeZIPPlus4- ZIP+4 code
additionalInfo- Object containing:deliveryPoint- Delivery point codecarrierRoute- Carrier route codeDPVConfirmation- Delivery point validation statusDPVCMRA- Commercial mail receiving agency statusbusiness- Business address indicatorcentralDeliveryPoint- Central delivery point indicatorvacant- Vacant address indicator
corrections- Array of correction codes and descriptionsmatches- Array of match codes and descriptionswarnings- Array of warning messages
Example Request
1curl -X POST "https://kiloships.com/api/addresses/address" \
2 -H "Authorization: Bearer YOUR_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "streetAddress": "350 5th Ave",
6 "city": "New York",
7 "state": "NY",
8 "secondaryAddress": "Suite 3000"
9 }'Example Response
1{
2 "address": {
3 "streetAddress": "350 5TH AVE",
4 "streetAddressAbbreviation": "350 5TH AVE",
5 "secondaryAddress": "STE 3000",
6 "city": "NEW YORK",
7 "cityAbbreviation": "NEW YORK",
8 "state": "NY",
9 "ZIPCode": "10118",
10 "ZIPPlus4": "0110"
11 },
12 "additionalInfo": {
13 "deliveryPoint": "00",
14 "carrierRoute": "C006",
15 "DPVConfirmation": "Y",
16 "DPVCMRA": "N",
17 "business": "Y",
18 "centralDeliveryPoint": "N",
19 "vacant": "N"
20 },
21 "matches": [
22 {
23 "code": "A",
24 "text": "Exact match"
25 }
26 ]
27}Get Zone
https://kiloships.com/api/addresses/zone/number?originZIPCode={originZIPCode}&destinationZIPCode={destinationZIPCode}&mailingDate={mailingDate}Get the shipping zone between two ZIP codes for a specific mailing date
Query Parameters
originZIPCode(required) - Origin ZIP codedestinationZIPCode(required) - Destination ZIP codemailingDate(required) - Mailing date in YYYY-MM-DD formatResponse
1{
2 "zone": 5
3}Example Request
1curl -X GET "https://kiloships.com/api/addresses/zone?originZIPCode=90210&destinationZIPCode=10001&mailingDate=2024-04-15" \
2 -H "Authorization: Bearer YOUR_API_KEY"Organization Balance
Get the current balance of your organization. This endpoint requires authentication and returns the available balance that can be used for shipping labels and other services.
Endpoint
https://kiloships.com/api/organizations/balanceAuthentication
Requires an API key to be included in the request headers:
Authorization: Bearer YOUR_API_KEYExample Request
1curl -X GET "https://kiloships.com/api/organizations/balance" \
2 -H "Authorization: Bearer YOUR_API_KEY"Example Response
1{
2 "currentBalance": 728.8
3}Response Fields
currentBalance- Current available balance in USD
Error Handling
Error Response Format
When an error occurs, the API will return a JSON response with the following structure:
success- Boolean indicating if the request was successfulmessage- A general error messagecode- HTTP status codeerror- Detailed error object:code- Error codemessage- Error messageerrors- Array of specific error details:title- Error typedetail- Detailed error messagesource- Object indicating the error source
Common Error Codes
400- Bad Request - Invalid input parameters or validation errors401- Unauthorized - Invalid or missing API key402- Payment Required - Insufficient balance404- Not Found - Resource not found429- Too Many Requests - Rate limit exceeded500- Internal Server Error - Server-side error
Example Error Response
1{
2 "success": false,
3 "message": "Bad Request",
4 "code": "400",
5 "error": {
6 "code": "400",
7 "message": "Bad Request",
8 "errors": [
9 {
10 "title": "Bad Request",
11 "detail": "five digits are required",
12 "source": {
13 "parameter": "toAddress.ZIPCode"
14 }
15 }
16 ]
17 }
18}Common Validation Errors
toAddress.ZIPCode- ZIP code must be exactly 5 digitsfromAddress.ZIPCode- ZIP code must be exactly 5 digitsservicelevelToken- Must be a valid service levelweight- Must be a positive numberdimensions- Length, width, and height must be positive numbers