Creating Orders

Creating Orders Guide

This guide walks you through creating outbound orders using the Spreetail Channel Integration API.

Overview

Outbound orders represent customer orders that need to be fulfilled and shipped. When you create an order, it is validated, stored, and queued for processing by our fulfillment system.

Endpoint

POST /outbound

Full URL: https://api.spreetaileu.com/api/api/v1/outbound

Authentication

Requires Bearer token authentication. See the Authentication Guide for details.

Order Structure

A complete order includes:

  • Order Information: Reference number, dates, status, currency
  • Order Items: Products/SKUs with quantities and prices
  • Delivery Address: Shipping destination
  • Billing Address: Billing information

Required Fields

FieldTypeDescription
ReferenceNumberstringUnique order reference (per client)
ReceivedDatestring (ISO 8601)When the order was received
DispatchBystring (ISO 8601)Latest dispatch date/time — must include a time zone. Converted to UTC on storage. See below
CurrencystringISO 4217 currency code (EUR, GBP, USD)
PaymentStatusstringPayment status (e.g., "PAID")
ChannelBuyerNamestringCustomer name
warehouse_namestringWarehouse the order ships from (e.g. ramy data testing) — use the exact name supplied by your Account Manager
OrderItemsarrayAt least one item required
DeliveryAddressobjectComplete delivery address
BillingAddressobjectComplete billing address
ℹ️

Note: The Status field is automatically set to "Pending" when creating an order. You do not need to include it in your request, and any value you provide will be ignored.

Date Format

DispatchBy must be an ISO 8601 timestamp that includes a time zone — either Z for UTC, or an explicit offset such as +01:00 or -07:00.

It is converted to UTC before it is stored, so the following are all the same moment and are all stored as 2025-10-30T17:00:00Z:

2025-10-30T17:00:00Z            UTC
2025-10-30T18:00:00+01:00       UK summer time
2025-10-30T10:00:00-07:00       US Pacific

Your dispatch deadline is not moved by this — only how the timestamp is written. Sending UTC (Z) directly is simplest, and is what the examples below use.

⚠️

Always include the time zone. A timestamp with no time zone, such as 2025-10-30T17:00:00, is ambiguous and may be read hours away from the deadline you intended.

Example: Complete Order

{
  "ReferenceNumber": "ORD-2025-001",
  "ReceivedDate": "2025-01-15T10:00:00Z",
  "DispatchBy": "2025-01-16T17:00:00Z",
  "Currency": "EUR",
  // Note: Status is automatically set to "Pending" - do not include
  "PaymentStatus": "PAID",
  "ChannelBuyerName": "John Doe",
  "PostalServiceCost": 5.99,
  "PostalServiceTaxRate": 19,
  "warehouse_name": "ramy data testing",
  "OrderItems": [
    {
      "SKU": "PROD-12345",
      "ItemTitle": "Premium Wireless Headphones",
      "Qty": 2,
      "PricePerUnit": 29.99,
      "TaxRate": 19,
      "OrderLineNumber": "1"
    },
    {
      "SKU": "PROD-67890",
      "ItemTitle": "USB-C Cable",
      "Qty": 1,
      "PricePerUnit": 9.99,
      "TaxRate": 19,
      "OrderLineNumber": "2"
    }
  ],
  "DeliveryAddress": {
    "FullName": "John Doe",
    "Company": "Acme Corp",
    "Address1": "123 Main Street",
    "Address2": "Suite 100",
    "Town": "Berlin",
    "Region": "Berlin",
    "PostCode": "10115",
    "Country": "Germany",
    "CountryCode": "DE",
    "PhoneNumber": "+49 30 12345678",
    "EmailAddress": "[email protected]"
  },
  "BillingAddress": {
    "FullName": "John Doe",
    "Company": "Acme Corp",
    "Address1": "123 Main Street",
    "Address2": "Suite 100",
    "Town": "Berlin",
    "Region": "Berlin",
    "PostCode": "10115",
    "Country": "Germany",
    "CountryCode": "DE",
    "PhoneNumber": "+49 30 12345678",
    "EmailAddress": "[email protected]"
  }
}

Code Examples

Python

import requests
from datetime import datetime, timedelta

def create_order(access_token, order_data):
    """Create an outbound order"""
    url = "https://api.spreetaileu.com/api/api/v1/outbound"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }
    
    response = requests.post(url, headers=headers, json=order_data)
    response.raise_for_status()
    return response.json()

# Example usage
order = {
    "ReferenceNumber": f"ORD-{datetime.now().strftime('%Y%m%d-%H%M%S')}",
    "ReceivedDate": datetime.utcnow().isoformat() + "Z",
    "DispatchBy": (datetime.utcnow() + timedelta(days=1)).isoformat() + "Z",
    "Currency": "EUR",
    # Note: Status is automatically set to "Pending" - do not include
    "PaymentStatus": "PAID",
    "ChannelBuyerName": "John Doe",
    "warehouse_name": "ramy data testing",
    "OrderItems": [{
        "SKU": "PROD-12345",
        "ItemTitle": "Premium Headphones",
        "Qty": 2,
        "PricePerUnit": 29.99,
        "OrderLineNumber": "1"
    }],
    "DeliveryAddress": {
        "FullName": "John Doe",
        "Address1": "123 Main Street",
        "Town": "Berlin",
        "PostCode": "10115",
        "Country": "Germany",
        "CountryCode": "DE"
    },
    "BillingAddress": {
        "FullName": "John Doe",
        "Address1": "123 Main Street",
        "Town": "Berlin",
        "PostCode": "10115",
        "Country": "Germany",
        "CountryCode": "DE"
    }
}

result = create_order(access_token, order)
print(f"Order created: {result}")

JavaScript/Node.js

async function createOrder(accessToken, orderData) {
  const url = 'https://api.spreetaileu.com/api/api/v1/outbound';
  
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(orderData)
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Order creation failed: ${error.error || response.statusText}`);
  }
  
  return await response.json();
}

// Example usage
const order = {
  ReferenceNumber: `ORD-${Date.now()}`,
  ReceivedDate: new Date().toISOString(),
  DispatchBy: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
  Currency: 'EUR',
  // Note: Status is automatically set to "Pending" - do not include
  PaymentStatus: 'PAID',
  ChannelBuyerName: 'John Doe',
  warehouse_name: 'ramy data testing',
  OrderItems: [{
    SKU: 'PROD-12345',
    ItemTitle: 'Premium Headphones',
    Qty: 2,
    PricePerUnit: 29.99,
    OrderLineNumber: '1'
  }],
  DeliveryAddress: {
    FullName: 'John Doe',
    Address1: '123 Main Street',
    Town: 'Berlin',
    PostCode: '10115',
    Country: 'Germany',
    CountryCode: 'DE'
  },
  BillingAddress: {
    FullName: 'John Doe',
    Address1: '123 Main Street',
    Town: 'Berlin',
    PostCode: '10115',
    Country: 'Germany',
    CountryCode: 'DE'
  }
};

createOrder(accessToken, order)
  .then(result => console.log('Order created:', result))
  .catch(error => console.error('Error:', error));

Response

Success Response (201)

{
  "success": true,
  "message": "Order created successfully",
  "data": {
    "ReferenceNumber": "ORD-2025-001",
    "Client": "BrandName",
    "Status": "Pending",
    "OrderId": {
      "UUID": "123e4567-e89b-12d3-a456-426614174000",
      "Number": 1730192400
    }
  }
}

Error Responses

400 Bad Request - Validation error:

{
  "success": false,
  "error": "ReferenceNumber is required"
}

401 Unauthorized - Invalid or expired token:

{
  "success": false,
  "error": "Unauthorized"
}

409 Conflict - Duplicate reference number:

{
  "success": false,
  "error": "Order with ReferenceNumber 'ORD-2025-001' already exists"
}

Important Notes

PricePerUnit Validation

  • PricePerUnit must be greater than 0 (minimum: 0.01)
  • Orders with PricePerUnit: 0 will be rejected by Linnworks and cannot be processed
  • Ensure all order items have valid pricing before submission

Reference Number Uniqueness

  • Reference numbers must be unique per client
  • If you submit the same reference number twice, you'll receive a 409 Conflict error
  • Use a consistent format (e.g., ORD-YYYYMMDD-####)

Currency Codes

Supported ISO 4217 currency codes:

  • EUR - Euro
  • GBP - British Pound
  • USD - US Dollar

Date Formats

All dates must be in ISO 8601 format with UTC timezone:

  • Format: YYYY-MM-DDTHH:mm:ssZ
  • Example: 2025-01-15T10:00:00Z

Address Requirements

Both DeliveryAddress and BillingAddress require:

  • FullName
  • Address1
  • Town
  • PostCode
  • Country or CountryCode

Order Items

  • At least one item is required
  • Each item must have: SKU, ItemTitle, Qty, PricePerUnit, OrderLineNumber
  • Quantities must be positive integers
  • PricePerUnit must be greater than 0 - Orders with zero price will be rejected by Linnworks and cannot be processed
  • OrderLineNumber is required (e.g., '1', '2') and cannot be empty - Required for order processing compatibility with Linnworks

Best Practices

  1. Generate Unique Reference Numbers: Use timestamps or UUIDs to ensure uniqueness
  2. Validate Before Sending: Validate all required fields and formats before API calls
  3. Handle Errors Gracefully: Implement retry logic for transient errors
  4. Store Order IDs: Save the returned order_id for future reference
  5. Monitor Order Status: Use /order/{order_id} to check order status after creation

Next Steps

After creating an order:

  1. Check Order Status: Use GET /order/{order_id} to verify the order was processed
  2. Handle Errors: Implement error handling for validation failures
  3. Track Shipments: Monitor order status for dispatch and tracking updates

Related Endpoints

  • GET /order/{order_id} - Retrieve order details
  • GET /order?channel_ref={value} - Look up orders by the Channel_Ref note value you supplied at creation (returns an array, since one channel reference can match several orders)
  • GET /order?ship_from=MSF - List your Amazon Seller Flex (MSF) orders, which are not visible via GET /order/{order_id}
  • POST /order/{order_id}/cancel - Cancel an order
  • GET /inventory - Check inventory before creating orders

Did this page help you?