@surajrasaili/shipengine
v1.0.1
Published
A TypeScript-first Node.js client for the ShipEngine API with full type safety.
Downloads
4
Maintainers
Readme
ShipEngine SDK for Node.js
A type-safe, production-ready Node.js SDK for the ShipEngine API with a Stripe-like developer experience.
Features
- 🔒 Fully Type-Safe - Built with TypeScript, all requests and responses are strictly typed
- 🎯 Stripe-like DX - Intuitive resource-based API (
shipengine.shipments.create()) - 🔄 Automatic Retries - Exponential backoff for rate limits (429) and server errors (5xx)
- 🔑 Idempotency Support - Prevent duplicate operations with idempotency keys
- ⚡ Modern JavaScript - Uses native
fetch, no external HTTP dependencies - 📝 JSDoc Comments - Full IntelliSense support in VS Code
Installation
npm install @surajrasaili/shipengineQuick Start
import { ShipEngine } from '@surajrasaili/shipengine';
const shipengine = new ShipEngine('your-api-key');
// Validate an address
const validated = await shipengine.addresses.validate([
{
name: 'John Doe',
address_line1: '123 Main St',
city_locality: 'Austin',
state_province: 'TX',
postal_code: '78701',
country_code: 'US',
},
]);
// Get shipping rates
const rates = await shipengine.rates.estimate({
carrier_ids: ['se-123456'],
from_postal_code: '78702',
from_country_code: 'US',
to_postal_code: '78701',
to_country_code: 'US',
weight: { value: 1, unit: 'pound' },
});
// Create a shipping label
const label = await shipengine.labels.create({
shipment: {
carrier_id: 'se-123456',
service_code: 'usps_priority_mail',
ship_to: {
name: 'John Doe',
address_line1: '123 Main St',
city_locality: 'Austin',
state_province: 'TX',
postal_code: '78701',
country_code: 'US',
},
ship_from: {
name: 'Warehouse',
address_line1: '456 Warehouse Ave',
city_locality: 'Austin',
state_province: 'TX',
postal_code: '78702',
country_code: 'US',
},
packages: [{ weight: { value: 1, unit: 'pound' } }],
},
});
console.log(`Label created: ${label.label_id}`);
console.log(`Tracking: ${label.tracking_number}`);Configuration
const shipengine = new ShipEngine('your-api-key', {
baseUrl: 'https://api.shipengine.com', // API base URL (default)
timeout: 30000, // Request timeout in ms (default: 30000)
maxRetries: 3, // Max retry attempts (default: 3)
retryDelay: 500, // Initial retry delay in ms (default: 500)
});Available Resources
| Resource | Description |
|----------|-------------|
| account | Account settings and images |
| addresses | Address validation and parsing |
| batches | Bulk label operations |
| carriers | Carrier management and connections |
| documents | Combined label documents |
| insurance | Shipsurance account management |
| labels | Shipping label creation and management |
| manifests | End-of-day manifests |
| packages | Custom package types |
| pickups | Carrier pickup scheduling |
| rates | Shipping rate calculation |
| servicePoints | PUDO locations |
| shipments | Shipment management |
| tags | Shipment tagging |
| tracking | Package tracking |
| warehouses | Warehouse/origin management |
| webhooks | Event webhooks |
API Reference
Addresses
// Validate addresses
const results = await shipengine.addresses.validate([
{ name: 'John Doe', address_line1: '123 Main St', ... }
]);
// Parse address from text
const parsed = await shipengine.addresses.parse({
text: 'Ship to John Doe at 123 Main St, Austin TX 78701',
});Shipments
// List shipments
const shipments = await shipengine.shipments.list({
page: 1,
page_size: 25,
shipment_status: 'pending',
});
// Create shipments
const created = await shipengine.shipments.create({
shipments: [{ ... }],
});
// Get shipment by ID
const shipment = await shipengine.shipments.get('se-123456');
// Update shipment
await shipengine.shipments.update('se-123456', { ... });
// Cancel shipment
await shipengine.shipments.cancel('se-123456');
// Get shipment rates
const rates = await shipengine.shipments.listRates('se-123456');
// Add/remove tags
await shipengine.shipments.addTag('se-123456', 'priority');
await shipengine.shipments.removeTag('se-123456', 'priority');Labels
// List labels
const labels = await shipengine.labels.list({
label_status: 'completed',
carrier_id: 'se-123456',
});
// Create label
const label = await shipengine.labels.create({
shipment: { ... },
});
// Create label from rate
const label = await shipengine.labels.createFromRate('se-rate-123', {
validate_address: 'validate_and_clean',
});
// Create label from shipment
const label = await shipengine.labels.createFromShipment('se-ship-123', {});
// Create return label
const returnLabel = await shipengine.labels.createReturnLabel('se-label-123', {});
// Void label
const voidResult = await shipengine.labels.void('se-label-123');
// Get tracking for label
const tracking = await shipengine.labels.getTracking('se-label-123');Rates
// Calculate rates
const rates = await shipengine.rates.calculate({
shipment: { ... },
rate_options: { carrier_ids: ['se-123'] },
});
// Estimate rates (simplified)
const estimates = await shipengine.rates.estimate({
carrier_ids: ['se-123'],
from_postal_code: '78702',
to_postal_code: '78701',
from_country_code: 'US',
to_country_code: 'US',
weight: { value: 1, unit: 'pound' },
});
// Bulk rate comparison
const bulk = await shipengine.rates.compareBulk({
shipments: [...],
rate_options: {},
});
// Get rate by ID
const rate = await shipengine.rates.get('se-rate-123');Carriers
// List carriers
const carriers = await shipengine.carriers.list();
// Get carrier by ID
const carrier = await shipengine.carriers.get('se-carrier-123');
// Get carrier services
const services = await shipengine.carriers.listServices('se-carrier-123');
// Get carrier package types
const packages = await shipengine.carriers.listPackageTypes('se-carrier-123');
// Add funds to carrier
const balance = await shipengine.carriers.addFunds('se-carrier-123', {
amount: 100,
currency: 'usd',
});
// Connect a carrier
const connected = await shipengine.carriers.connect('ups', {
nickname: 'My UPS Account',
account_number: '123456',
...
});Tracking
// Get tracking info
const tracking = await shipengine.tracking.get({
carrier_code: 'ups',
tracking_number: '1Z999AA10123456784',
});
// Subscribe to tracking updates
await shipengine.tracking.startTracking({
carrier_code: 'ups',
tracking_number: '1Z999AA10123456784',
});
// Unsubscribe from tracking
await shipengine.tracking.stopTracking({
carrier_code: 'ups',
tracking_number: '1Z999AA10123456784',
});Warehouses
// List warehouses
const warehouses = await shipengine.warehouses.list();
// Create warehouse
const warehouse = await shipengine.warehouses.create({
name: 'East Coast Warehouse',
origin_address: { ... },
});
// Update warehouse
await shipengine.warehouses.update('se-wh-123', { name: 'Updated Name' });
// Delete warehouse
await shipengine.warehouses.delete('se-wh-123');Webhooks
// List webhooks
const webhooks = await shipengine.webhooks.list();
// Create webhook
const webhook = await shipengine.webhooks.create({
url: 'https://example.com/webhook',
event: 'track',
});
// Update webhook
await shipengine.webhooks.update('se-wh-123', {
url: 'https://example.com/new-webhook',
});
// Delete webhook
await shipengine.webhooks.delete('se-wh-123');Idempotency
For POST/PUT requests, you can pass an idempotency key to prevent duplicate operations:
const label = await shipengine.labels.create(
{ shipment: { ... } },
{ idempotencyKey: 'order-12345-label' }
);Error Handling
The SDK provides typed error classes for different error scenarios:
import {
ShipEngineError,
ShipEngineApiError,
ShipEngineAuthenticationError,
ShipEngineInvalidRequestError,
ShipEngineRateLimitError,
} from '@surajrasaili/shipengine';
try {
await shipengine.labels.create({ ... });
} catch (error) {
if (error instanceof ShipEngineAuthenticationError) {
// 401 - Invalid API key
console.error('Authentication failed:', error.message);
} else if (error instanceof ShipEngineInvalidRequestError) {
// 400/422 - Validation error
console.error('Invalid request:', error.message);
console.error('Field:', error.fieldName);
} else if (error instanceof ShipEngineRateLimitError) {
// 429 - Rate limited (auto-retried by default)
console.error('Rate limited, retry after:', error.retryAfter);
} else if (error instanceof ShipEngineApiError) {
// Other API errors
console.error('API error:', error.statusCode, error.message);
console.error('Request ID:', error.requestId);
console.error('Errors:', error.errors);
} else if (error instanceof ShipEngineError) {
// Network/timeout errors
console.error('SDK error:', error.message);
}
}Automatic Retries
The SDK automatically retries requests that fail due to:
- 429 Too Many Requests - Uses
Retry-Afterheader or exponential backoff - 5xx Server Errors - Exponential backoff with jitter
Configure retry behavior:
const shipengine = new ShipEngine('your-api-key', {
maxRetries: 5, // Max retry attempts (default: 3)
retryDelay: 1000, // Initial delay in ms (default: 500)
});Set maxRetries: 0 to disable retries.
TypeScript Support
All types are exported for use in your application:
import type {
components,
operations,
paths,
} from '@surajrasaili/shipengine';
// Use component schemas
type Address = components['schemas']['address'];
type Shipment = components['schemas']['shipment'];
type Label = components['schemas']['label'];
// Use operation types
type CreateShipmentBody = components['schemas']['create_shipments_request_body'];
type CreateShipmentResponse = components['schemas']['create_shipments_response_body'];Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Type check
npm run build
# Regenerate types from OpenAPI spec
npm run generate:typesLicense
ISC
