Skip to Content
BridgesExamplesShipStation

ShipStation Bridge Example

ShipStation is a shipping category bridge that demonstrates API key authentication and shipment syncing.

Manifest

const manifest: BridgeManifest = { name: 'shipstation', displayName: 'ShipStation', description: 'Sync shipments and create orders in ShipStation', version: '1.0.0', category: 'shipping', integrationType: 'api', icon: 'ship', authMethods: { apiKey: true, accessToken: false, oauth2: false }, configFields: [ { name: 'apiKey', label: 'API Key', type: 'password', required: true }, { name: 'apiSecret', label: 'API Secret', type: 'password', required: true }, ], tasks: [ { name: 'grab-shipments', displayName: 'Grab Shipments', description: 'Fetch shipments from ShipStation', category: 'sync', supportsSchedule: true }, { name: 'create-shipment', displayName: 'Create Shipment', description: 'Create an order in ShipStation', category: 'push', supportsSchedule: false }, { name: 'get-rates', displayName: 'Get Rates', description: 'Get shipping rates', category: 'sync', supportsSchedule: false }, ], };

Key Implementation Pattern

ShipStation uses Basic authentication with Base64-encoded credentials:

function createHeaders(credentials: Record<string, string>) { const encoded = btoa(`${credentials.apiKey}:${credentials.apiSecret}`); return { 'Authorization': `Basic ${encoded}`, 'Content-Type': 'application/json', }; }

Rate Limiting

ShipStation enforces strict rate limits (40 requests per minute). Use the rateLimiting config:

rateLimiting: { requestsPerSecond: 0.6, retryAfterHeader: 'X-Rate-Limit-Reset', }

Grab Shipments

async function grabShipments(context: BridgeTaskContext, input: Record<string, unknown>) { const page = (input.page as number) || 1; const response = await fetch( `https://ssapi.shipstation.com/shipments?page=${page}&pageSize=500`, { headers: createHeaders(context.config.credentials) } ); const data = await response.json(); const shipments = data.shipments.map(transformShipStationShipment); return { success: true, data: shipments, metrics: { recordsProcessed: shipments.length }, pagination: { hasMore: data.page < data.pages, nextPage: data.page + 1, total: data.total, }, }; }