API Reference

A RESTful JSON API for shipping labels, rate shopping, tracking, and account management. Authenticate with a JWT or API key and start shipping in minutes.

Authentication

Every request must include a Bearer token in the Authorization header. You can use either a JWT access token (from the login flow) or an API key created in the dashboard.

Authorization: Bearer <jwt_or_api_key>

API keys use the nsk_ prefix and are scoped per-organization. Create one via POST /api-keys.

Base URL

https://ninjaship.com/api/v1

All endpoint paths below are relative to this base.

Rate Limits

  • General: 100 requests / minute (per organization)
  • Auth endpoints: 10 requests / minute (per IP)

Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining) are included in every response.

Response Format

Every response is wrapped in a standard envelope.

Success (2xx)

{
  "success": true,
  "data": { ... }
}

Error (4xx / 5xx)

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request data",
    "details": { ... }
  }
}

Common error codes: VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, INSUFFICIENT_BALANCE, INTERNAL_ERROR

Pagination

List endpoints accept page and limit query parameters and return a pagination envelope.

GET /shipments?page=2&limit=20

{
  "success": true,
  "data": {
    "items": [ ... ],
    "total": 142,
    "page": 2,
    "limit": 20,
    "totalPages": 8
  }
}

Endpoints

Shipments
GET/shipmentsList shipments with pagination. Supports ?page, ?limit, and ?batchId filter.
POST/shipmentsCreate a shipment and fetch carrier rates.
// POST /shipments
{
  "fromAddressId": "uuid",     // or inline "fromAddress": { ... }
  "toAddress": {
    "name": "Jane Doe",
    "street1": "456 Oak Ave",
    "city": "Austin",
    "state": "TX",
    "zip": "78701",
    "country": "US"
  },
  "packageType": "package",    // envelope | package | flat_rate_*
  "weight": { "value": 12, "unit": "oz" },
  "dimensions": { "length": 10, "width": 8, "height": 4, "unit": "in" },
  "labelFormat": "pdf_4x6",   // pdf_4x6 | pdf_8x11 | zpl
  "reference": "ORDER-1234",
  "signatureConfirmation": false
}

// Response 201
{
  "success": true,
  "data": { "shipment": { ... }, "rates": [ ... ] }
}
GET/shipments/:idGet shipment details including from/to addresses.
DELETE/shipments/:idDelete a draft or rated shipment (not purchased).
POST/shipments/:id/buyPurchase a label for a rated shipment. Debits your wallet balance.
// POST /shipments/:id/buy
{
  "rateId": "rate_abc123",
  "labelFormat": "pdf_4x6",
  "insuranceAmountCents": 0
}

// Response
{
  "success": true,
  "data": {
    "shipment": { ... },
    "labelUrl": "https://...",
    "trackingNumber": "9400111...",
    "trackingPageUrl": "https://..."
  }
}
POST/shipments/:id/voidVoid a purchased label and refund your wallet.
Rates
POST/ratesGet shipping rates for a parcel. Uses your organization's default from-address.
// POST /rates
{
  "weight": 16,
  "weightUnit": "oz",
  "length": 12, "width": 8, "height": 4,
  "dimensionUnit": "in",
  "destination": {
    "zip": "90210",
    "state": "CA",
    "country": "US"
  }
}

// Response
{
  "success": true,
  "data": {
    "rates": [
      {
        "label": "USPS Priority Mail",
        "cost": 8.45,
        "carrier": "USPS",
        "service": "Priority",
        "estimatedDays": 2
      }
    ]
  }
}
Addresses
GET/addressesList saved addresses in your address book.
POST/addressesCreate a new address.
// POST /addresses
{
  "name": "Warehouse A",
  "street1": "123 Main St",
  "city": "New York",
  "state": "NY",
  "zip": "10001",
  "country": "US",
  "phone": "555-0100",
  "isDefault": true,
  "tags": ["warehouse", "east-coast"]
}
GET/addresses/:idGet a single address by ID.
PUT/addresses/:idUpdate an address. All fields are optional.
DELETE/addresses/:idDelete an address.
POST/addresses/validateValidate an address via carrier verification.
// POST /addresses/validate
{
  "street1": "123 Main St",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

// Response
{
  "success": true,
  "data": {
    "valid": true,
    "suggestedAddress": { ... },
    "messages": []
  }
}
Tracking
GET/trackingList shipments with tracking status, ordered by last update.
GET/tracking/:shipmentIdGet tracking details and event history for a shipment.
// Response
{
  "success": true,
  "data": {
    "shipment": {
      "id": "uuid",
      "status": "in_transit",
      "carrier": "USPS",
      "trackingNumber": "9400111..."
    },
    "events": [
      {
        "status": "in_transit",
        "message": "Arrived at facility",
        "location": "Memphis, TN",
        "carrierTimestamp": "2026-04-01T14:30:00Z"
      }
    ]
  }
}
POST/tracking/:shipmentId/refreshManually refresh tracking from the carrier. No request body needed.
Orders
GET/ordersList orders with pagination. Supports ?status, ?platform, and ?search filters.
GET /orders?status=unfulfilled&platform=shopify&search=ORD-100

// Response
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "uuid",
        "orderNumber": "ORD-100",
        "platform": "shopify",
        "status": "unfulfilled",
        "recipientName": "Jane Doe",
        "recipientCity": "Austin",
        "recipientState": "TX",
        "itemCount": 3,
        "totalWeightOz": 24
      }
    ],
    "total": 1,
    "page": 1,
    "limit": 20,
    "totalPages": 1
  }
}
Batches
GET/batchesList all batches.
POST/batchesCreate a batch from existing shipments.
// POST /batches
{
  "shipmentIds": ["uuid1", "uuid2", "uuid3"],
  "rateSelectionStrategy": "cheapest"  // cheapest | fastest | manual
}

// Response 201
{
  "success": true,
  "data": { "batch": { "id": "uuid", "status": "pending", ... } }
}
GET/batches/:idGet batch details with shipment list and progress.
// Response includes progress
{
  "success": true,
  "data": {
    "batch": { ... },
    "shipments": [ ... ],
    "progress": {
      "total": 50,
      "completed": 42,
      "errors": 1,
      "percent": 84
    }
  }
}
POST/batches/:id/purchasePurchase labels for all shipments in a batch.
// POST /batches/:id/purchase
{
  "rateSelections": [
    { "shipmentId": "uuid1", "rateId": "rate_abc" },
    { "shipmentId": "uuid2", "rateId": "rate_def" }
  ]
}
Package Presets
GET/package-presetsList saved package presets.
POST/package-presetsCreate a package preset.
// POST /package-presets
{
  "name": "Small Box",
  "length": 8,
  "width": 6,
  "height": 4,
  "weightOz": 16,
  "isDefault": false
}
PUT/package-presets/:idUpdate a preset. All fields are optional.
DELETE/package-presets/:idDelete a preset.
Automation Rules

Automation rules apply actions to shipments that match conditions. Rules run in priority order during batch processing.

GET/automation-rulesList all automation rules.
POST/automation-rulesCreate an automation rule.
// POST /automation-rules
{
  "name": "Priority for heavy packages",
  "priority": 10,
  "conditionGroups": [
    {
      "logic": "and",
      "conditions": [
        { "field": "weight_oz", "operator": "greater_than", "value": 48 },
        { "field": "destination_state", "operator": "in", "value": ["CA","NY"] }
      ]
    }
  ],
  "actions": [
    { "type": "set_carrier_service", "config": { "carrier": "UPS", "service": "Ground" } },
    { "type": "add_signature", "config": {} }
  ],
  "isActive": true
}

Condition fields: weight_oz, zone, destination_country, destination_state, carrier, service, order_value_cents, store_source, package_type, item_name, item_sku, item_count

Action types: set_carrier_service, add_insurance, add_signature, apply_package_preset, tag_shipment, send_email, apply_return_label

PUT/automation-rules/:idUpdate a rule. All fields are optional.
DELETE/automation-rules/:idDelete a rule.
Pickups
GET/pickupsList pickups with pagination. Supports ?shipmentId filter.
POST/pickupsCreate a pickup request and get available rates.
// POST /pickups
{
  "shipmentIds": ["uuid1"],
  "addressId": "uuid",
  "minDatetime": "2026-04-03T09:00:00Z",
  "maxDatetime": "2026-04-03T17:00:00Z",
  "instructions": "Ring bell, packages at side door"
}
POST/pickups/:id/cancelCancel a scheduled pickup.
API Keys
GET/api-keysList API keys. Only the key prefix is returned for security.
POST/api-keysCreate a new API key. The full key is only returned once.
// POST /api-keys
{
  "name": "Production integration",
  "scopes": ["labels:read", "labels:write", "rates:read", "tracking:read"]
}

// Response 201
{
  "success": true,
  "data": {
    "apiKey": { "id": "uuid", "name": "Production integration", "keyPrefix": "nsk_abc1234..." },
    "rawKey": "nsk_abc1234...full_key_here"
  }
}

Available scopes: labels:read, labels:write, rates:read, tracking:read, addresses:read, addresses:write, balance:read, webhooks:manage

DELETE/api-keys/:idRevoke an API key.
Billing
GET/billing/balanceGet wallet balance and auto-recharge settings.
// Response
{
  "success": true,
  "data": {
    "balanceCents": 5000,
    "autoRecharge": {
      "enabled": true,
      "thresholdCents": 1000,
      "amountCents": 5000
    }
  }
}
POST/billing/topupAdd funds to your wallet. Requires a Stripe payment method.
// POST /billing/topup
{
  "amountCents": 5000,
  "paymentMethodId": "pm_..."
}

// Response (immediate success)
{ "success": true, "data": { "status": "succeeded", "balanceCents": 10000 } }

// Response (3D Secure required)
{ "success": true, "data": { "status": "requires_action", "clientSecret": "pi_..._secret_..." } }
GET/billing/payment-methodsList saved payment methods (cards).
DELETE/billing/payment-methods?id=pm_...Detach a payment method.
POST/billing/payment-methods/defaultSet a payment method as the default.
GET/billing/transactionsList wallet transactions with pagination.
Team
GET/teamList team members in your organization.
POST/teamInvite a new team member by email.
// POST /team
{
  "email": "newuser@example.com",
  "role": "member"   // owner | admin | member | viewer
}

// Response 201
{
  "success": true,
  "data": { "member": { "id": "uuid", "email": "newuser@example.com", "role": "member" } }
}
PUT/team/:memberIdUpdate a team member's role. Cannot change your own role.
DELETE/team/:memberIdRemove a team member. Cannot remove yourself.

Ready to integrate? Create a free account and generate an API key.

Get Started Free