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/api

API Endpoints

Create Shipping Label

POSThttps://kiloships.com/api/shipping-labels/domestic

Create a new domestic shipping label

Get Domestic Price

POSThttps://kiloships.com/api/shipping-labels/domestic/price

Get a free price quote for a domestic package — no label is created and no balance is consumed

List Shipping Labels

GEThttps://kiloships.com/api/shipping-labels

Retrieve shipping labels for your organization with filters and pagination

Cancel Shipping Label

DELETEhttps://kiloships.com/api/shipping-labels/domestic/{trackingNumber}

Cancel a domestic shipping label using its tracking number

Create GDE Label

POSThttps://kiloships.com/api/shipping-labels/gde

Create a Global Direct Entry (GDE) label — USPS Ground Advantage or Priority Mail

Cancel GDE Label

DELETEhttps://kiloships.com/api/shipping-labels/gde/{trackingNumber}

Cancel a GDE label and request a refund

Register Tracking Numbers

POSThttps://kiloships.com/api/tracking/register

Register tracking numbers for continuous monitoring (one-time charge per number)

Track Package

GEThttps://kiloships.com/api/tracking/{trackingNumber}

Get the stored tracking snapshot for a registered number (registration required, no per-request fee)

City/State Lookup

GEThttps://kiloships.com/api/addresses/city-state?zipCode={zipCode}

Get city and state information for a ZIP code

ZIP Code Lookup

POSThttps://kiloships.com/api/addresses/zipcode

Get ZIP code information for an address

Address Standardization

POSThttps://kiloships.com/api/addresses/address

Get standardized address information

Get Organization Balance

GEThttps://kiloships.com/api/organizations/balance

Get 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

POSThttps://kiloships.com/api/shipping-labels/domestic

Authentication

Requires an API key to be included in the request headers:

Authorization: Bearer YOUR_API_KEY

Request 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 name
  • street1 (string) - Primary street address
  • street2 (string, optional) - Secondary address line
  • city (string) - City name
  • state (string) - Two-letter state code
  • zip (string) - 5-digit or 9-digit ZIP code
  • country (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 name
  • street1 (string) - Primary street address
  • street2 (string, optional) - Secondary address line
  • city (string) - City name
  • state (string) - Two-letter state code
  • zip (string) - 5-digit or 9-digit ZIP code
  • country (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 weight
  • massUnit (string) - Weight unit ("oz" or "lb")
  • length (string) - Package length
  • width (string) - Package width
  • height (string) - Package height
  • distanceUnit (string) - Dimension unit ("in" or "cm")

Service Level

servicelevelToken (required) - One of:

  • usps_ground_advantage - USPS Ground Advantage
  • usps_priority - USPS Priority Mail
  • usps_priority_express - USPS Priority Mail Express
  • usps_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 contents
  • customsContentType - 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 item
    • itemQuantity - Number of items
    • itemTotalValue - Total value of the items
    • weightUOM - Unit of measure for weight (oz or lb)
    • itemTotalWeight - Total weight of the items
    • HSTariffNumber - Optional Harmonized System tariff number
    • countryofOrigin - Country where the item was manufactured
    • itemCategory - Optional category of the item
    • itemSubcategory - 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
customs-form-example.json
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 details
  • parcel - Object containing package details
  • status - Current label status
  • labelUrl - URL to download the shipping label PDF
  • trackingNumber - Carrier tracking number
  • uniqueReferenceId - The client-supplied reference ID, if provided

Example Response

create-label-response.json
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

POSThttps://kiloships.com/api/shipping-labels/domestic/price

Authentication

Requires an API key to be included in the request headers, or an authenticated session:

Authorization: Bearer YOUR_API_KEY

Request 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 weight
  • massUnit - "oz" or "lb". The server converts to pounds before pricing.
  • length, width, height (string or number) - Package dimensions
  • distanceUnit - "in" or "cm". The server converts to inches before pricing.

Service Level

servicelevelToken (required) - One of:

  • usps_ground_advantage
  • usps_priority
  • usps_priority_express
  • usps_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 entry
  • rates[0].fees[] - USPS fee line items (raw, unmodified)
  • rates[0].mailClass, productName, productDefinition - Descriptive USPS passthrough fields
  • rates[0].warnings - Optional USPS advisory notices, present only when USPS returns them

Example Response

get-domestic-price-response.json
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 successfully
  • 400 - Invalid request body, unsupported/unrecognized service level token, or USPS rejected the package as unpriceable
  • 401 - Missing or invalid authentication
  • 403 - Authenticated account has no associated organization
  • 502 - USPS pricing upstream unavailable or timed out
  • 500 - 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

GEThttps://kiloships.com/api/shipping-labels

Authentication

Use an API key in the Authorization header, or call the endpoint from an authenticated user session.

Authorization: Bearer YOUR_API_KEY

Query Parameters

ParameterTypeRequiredDescription
pageintegerNoPage number to return. Default is 1.
pageSizeintegerNoNumber of labels to return per page. Default is 10 and maximum is 1000.
statusstringNoFilter by label status such as completed, pending, or cancelled.
labelTypestringNoFilter by label type, for example DOMESTIC.
searchstringNoSearch across tracking number, recipient name, and address fields.
sortBystringNoSort field. Allowed values: createdAt, postage, chargeAmount, trackingNumber, status, labelType.
sortOrderstringNoSort direction. Use asc or desc. Default is desc.
fromDateISO datetimeNoReturn labels created on or after this timestamp.
toDateISO datetimeNoReturn 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

list-shipping-labels-response.json
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

DELETEhttps://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

ParameterTypeRequiredDescription
trackingNumberstringYesThe 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

curl
1curl -X DELETE \ 2 "https://kiloships.com/api/shipping-labels/domestic/9405511298370938473298" \ 3 -H "Authorization: Bearer YOUR_API_KEY"

Example Response

response.json
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 canceled
  • DISPUTED - 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

GEThttps://kiloships.com/api/shipping-labels/reference/{uniqueReferenceId}

Authentication

Requires an API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Path Parameter

ParameterTypeRequiredDescription
uniqueReferenceIdstringYesThe reference ID you provided when creating the label.

Example Request

get-label-by-reference-request.sh
1curl -X GET 'https://kiloships.com/api/shipping-labels/reference/ORDER-12345' \ 2 -H 'Authorization: Bearer YOUR_API_KEY'

Example Response

get-label-by-reference-response.json
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

StatusDescription
404No active label found for the given reference ID within your organization.
401Missing 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

POSThttps://kiloships.com/api/shipping-labels/gde

Your 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_KEY

Request Body

Service Level

servicelevelToken (required) - One of:

  • usps_ground_advantage - USPS Ground Advantage
  • usps_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 code
  • country (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 weight
  • massUnit (string) - Weight unit ("oz" or "lb")
  • length (string) - Package length
  • width (string) - Package width
  • height (string) - Package height
  • distanceUnit (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 (provider is always "usps")
  • parcel - Package weight, normalized to ounces
  • status - Current label status (completed on success)
  • labelUrl - URL to download the shipping label PDF
  • trackingNumber - Carrier tracking number
  • metadata - Echoed back from the request
  • uniqueReferenceId - The client-supplied reference ID, if provided

Example Response

create-gde-label-response.json
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

StatusDescription
400Request validation failed (missing/invalid field). The message names the specific field.
401Missing or invalid API key / session.
402Insufficient organization balance.
403GDE labels are not enabled for your organization. Contact an administrator.
409An active label with this uniqueReferenceId already exists.
503The GDE label service is temporarily unavailable. Retry after the interval in the Retry-After header.
422 / 502The 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

DELETEhttps://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

ParameterTypeRequiredDescription
trackingNumberstringYesThe tracking number of the label to cancel

Authentication

Requires an API key in the Authorization header, or an authenticated session.

Example Request

curl
1curl -X DELETE \ 2 "https://kiloships.com/api/shipping-labels/gde/9234690327908700943823" \ 3 -H "Authorization: Bearer YOUR_API_KEY"

Example Response

response.json
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 cancelled
  • disputed - The refund is still processing on the carrier's side

Error Responses

StatusDescription
404No GDE label found for this tracking number within your organization.
409The 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

POSThttps://kiloships.com/api/scan-form

Create a USPS SCAN form for multiple tracking numbers

Authentication

Requires an API key to be included in the request headers:

Authorization: Bearer YOUR_API_KEY

Request Body

Required Fields:

  • mailingDate - Format: YYYY-MM-DD
  • entryFacilityZIPCode - 5-digit or 9-digit ZIP code
  • destinationEntryFacilityType - One of:
    • "NONE"
    • "DESTINATION_NETWORK_DISTRIBUTION_CENTER"
    • "DESTINATION_SECTIONAL_CENTER_FACILITY"
    • "DESTINATION_DELIVERY_UNIT"
    • "DESTINATION_SERVICE_HUB"
  • fromAddress - Sender's address object
  • shipment.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

scan-form-request.json
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 identifier
  • imageType - Type of image (PDF, TIFF, etc.)
  • labelType - Type of label
  • mailingDate - Confirmed mailing date
  • scanFormImage - URL to download the form
  • manifestNumber - Optional manifest number
  • shipment - Object containing confirmed tracking numbers
  • fromAddress - Confirmed sender address

Example Success Response

scan-form-response.json
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

POSThttps://kiloships.com/api/tracking/register

Batch 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.

register-request.sh
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"] }'
register-response.json
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

GEThttps://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.

snapshot-response.json
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).

statusCategoryMeaning
REGISTEREDNumber registered; first update not yet available
PICKEDUSPS accepted / picked up the package
IN_TRANSITPackage is moving through the USPS network
DELIVEREDPackage delivered (final status)
NOT_AVAILABLEUSPS 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 secret is 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.

tracking-updated-payload.json
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]
HeaderValue
KiloShips-Eventtracking.updated (real) or tracking.test (Test button)
KiloShips-Signaturet={unix_seconds},v1={hmac_hex}
X-Webhook-IDUnique delivery ID — dedupe retried deliveries on it
User-Agentkiloships-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:

verify-webhook.js
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 2xx quickly (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:

insufficient-balance-response.json
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

GEThttps://kiloships.com/api/addresses/city-state?zipCode={zipCode}

Parameters

zipCode (required) - 5-digit ZIP code

Response

  • city - City name
  • state - Two-letter state code
  • ZIPCode - 5-digit ZIP code

Example Request

city-state-lookup.sh
1curl -X GET "https://kiloships.com/api/addresses/city-state?zipCode=10001" \ 2 -H "Authorization: Bearer YOUR_API_KEY"

Example Response

city-state-response.json
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

POSThttps://kiloships.com/api/addresses/zipcode

Request Body

  • streetAddress (required) - Primary street address
  • city (required) - City name
  • 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 WY
  • secondaryAddress (optional) - Apartment, suite, etc.
  • firm (optional) - Company or organization name
  • urbanization (optional) - Urbanization code (Puerto Rico only)

Response

  • address - Object containing:
    • streetAddress - Standardized street address
    • city - City name
    • state - Two-letter state code
    • ZIPCode - 5-digit ZIP code
    • ZIPPlus4 - ZIP+4 code (if available)
    • secondaryAddress - Standardized secondary address

Example Request

zipcode-lookup-request.json
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

zipcode-lookup-response.json
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

POSThttps://kiloships.com/api/addresses/address

Request Body

  • streetAddress (required) - Primary street address
  • city (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 WY
  • secondaryAddress (optional) - Apartment, suite, etc.
  • firm (optional) - Company or organization name
  • urbanization (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 address
    • streetAddressAbbreviation - Abbreviated street address
    • secondaryAddress - Standardized secondary address
    • city - Standardized city name
    • cityAbbreviation - Abbreviated city name
    • state - Two-letter state code
    • ZIPCode - 5-digit ZIP code
    • ZIPPlus4 - ZIP+4 code
  • additionalInfo - Object containing:
    • deliveryPoint - Delivery point code
    • carrierRoute - Carrier route code
    • DPVConfirmation - Delivery point validation status
    • DPVCMRA - Commercial mail receiving agency status
    • business - Business address indicator
    • centralDeliveryPoint - Central delivery point indicator
    • vacant - Vacant address indicator
  • corrections - Array of correction codes and descriptions
  • matches - Array of match codes and descriptions
  • warnings - Array of warning messages

Example Request

address-standardization-request.json
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

address-standardization-response.json
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

GEThttps://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 code
destinationZIPCode(required) - Destination ZIP code
mailingDate(required) - Mailing date in YYYY-MM-DD format

Response

get-zone-response.json
1{ 2 "zone": 5 3}

Example Request

get-zone-request.sh
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

GEThttps://kiloships.com/api/organizations/balance

Authentication

Requires an API key to be included in the request headers:

Authorization: Bearer YOUR_API_KEY

Example Request

get-balance-request.sh
1curl -X GET "https://kiloships.com/api/organizations/balance" \ 2 -H "Authorization: Bearer YOUR_API_KEY"

Example Response

get-balance-response.json
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 successful
  • message - A general error message
  • code - HTTP status code
  • error - Detailed error object:
    • code - Error code
    • message - Error message
    • errors - Array of specific error details:
      • title - Error type
      • detail - Detailed error message
      • source - Object indicating the error source

Common Error Codes

  • 400 - Bad Request - Invalid input parameters or validation errors
  • 401 - Unauthorized - Invalid or missing API key
  • 402 - Payment Required - Insufficient balance
  • 404 - Not Found - Resource not found
  • 429 - Too Many Requests - Rate limit exceeded
  • 500 - Internal Server Error - Server-side error

Example Error Response

error-response.json
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 digits
  • fromAddress.ZIPCode - ZIP code must be exactly 5 digits
  • servicelevelToken - Must be a valid service level
  • weight - Must be a positive number
  • dimensions - Length, width, and height must be positive numbers