Interactive Examples
Learn by doing with step-by-step code examples in multiple languages
Beginner
5 min
Buy Your First Label
Quote, draft, purchase — the three calls that put a real label in your hands
Intermediate
10 min
Track a Shipment
Read a shipment's state, and register a webhook so you are not paying requests to poll
Advanced
15 min
Buy Labels in Bulk
Up to 25 labels in one request — and one rate-limit charge instead of 75
Buy Your First Label
Quote, draft, purchase — the three calls that put a real label in your hands
Beginner
5 min
node >= 18 — fetch is built in, no SDK neededconst API = 'https://atoship.com/api/v1';
const KEY = process.env.ATOSHIP_API_KEY;
async function call(path, body) {
const res = await fetch(API + path, {
method: 'POST',
headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body ?? {})
});
const data = await res.json();
// Every error carries error.code (UPPER_SNAKE_CASE). Branch on that —
// never on the message text, which is free to change.
if (!res.ok) throw new Error(`${data.error?.code}: ${data.error?.message}`);
return data;
}
const shipment = {
from_address: {
name: 'Warehouse', street1: '417 Montgomery St',
city: 'San Francisco', state: 'CA', zip: '94104', country: 'US'
},
to_address: {
name: 'Ada Lovelace', street1: '1355 Market St',
city: 'San Francisco', state: 'CA', zip: '94103', country: 'US'
},
parcel: {
length: 10, width: 8, height: 6,
weight: 32, weight_unit: 'oz', dimension_unit: 'in'
}
};
async function buyLabel() {
// 1. Quote. Rating is free — it spends nothing and commits to nothing.
const { data: rates } = await call('/rates', shipment);
if (!rates.length) throw new Error('No rates for this shipment');
const cheapest = rates.reduce((a, b) => (a.rate <= b.rate ? a : b));
console.log(`${cheapest.carrier} ${cheapest.service} $${cheapest.rate}`);
// 2. Create the label as a DRAFT. Still nothing charged.
const draft = await call('/labels', { ...shipment, rate_id: cheapest.id });
console.log(draft.id, draft.status); // 'draft', label_url still null
// 3. Purchase. THIS is the call that spends money.
const label = await call(`/labels/${draft.id}/purchase`);
console.log(label.status, label.tracking_number, label.label_url);
return label;
}
buyLabel().catch((err) => console.error(err.message));Pro Tips:
- Rating is free. Quote as often as you need — only the purchase call spends money.
- Reuse the rate_id from the quote. Buying without one lets the server pick a service, which is rarely the one you priced.
- A label is created as a draft first, so a bad address fails before anything is charged.
Next Steps
Ready to implement these examples in your application?