## CreateSalesOrder Quickstart Guide

This guide walks you through creating your first sales order using the Wineshipping API. We recommend following this four-step workflow: discover inventory, test the payload, integrate with your software, then monitor the shipment.

### Workflow Overview

```mermaid
graph LR
    A["Step 1: Discover Inventory<br/>GetSellable API"] --> B["Step 2: Test Payload<br/>Console/Postman"]
    B --> C["Step 3: Integrate<br/>Your Software"]
    C --> D["Monitor Shipment<br/>GetDetails/Webhooks"]
```

## Step 1: Discover Available Inventory with GetSellable

Before creating an order, use the [GetSellable](/api/v3.1/openapi/inventory/getsellable) endpoint to find available items and quantities.

### GetSellable Request Example

```json
{
  "Authentication": {
    "UserKey": "YOUR_USER_KEY",
    "Password": "YOUR_PASSWORD",
    "CustomerNo": "YOUR_CUSTOMER_NUMBER"
  },
  "Warehouses": ["APC01"]
}
```

### GetSellable Response Example

```json
{
  "TotalRecordCount": 145,
  "SalesChannel": "DTC",
  "Items": [
    {
      "ItemNo": "1466-SE",
      "ItemDescription": "2016 CAB SAUV RESERVE NAPA VALLEY",
      "ItemUnit": "bottle",
      "SellableQuantity": 1250
    },
    {
      "ItemNo": "A37B693E",
      "ItemDescription": "Pinot Noir 2020",
      "ItemUnit": "bottle",
      "SellableQuantity": 450
    },
    {
      "ItemNo": "5C7D8E9F",
      "ItemDescription": "Chardonnay 2019 - Case",
      "ItemUnit": "case",
      "SellableQuantity": 12
    }
  ]
}
```

**Key Takeaways:**

- Note the `ItemNo` for each product you want to include in your order
- Verify `SellableQuantity` is sufficient for your order
- Pay attention to `ItemUnit` (bottle, case, etc.) to match your order quantities


## Step 2: Test Your Payload in Console/Postman

Before integrating with your application, test your order payload using Redocly Console, Postman, or curl.

### Quick Start Payload (Minimal Example)

Use this as your starting point:

```json
{
  "Authentication": {
    "UserKey": "YOUR_USER_KEY",
    "Password": "YOUR_PASSWORD",
    "CustomerNo": "YOUR_CUSTOMER_NUMBER"
  },
  "OrderInfo": {
    "OrderNo": "MYORDER-001",
    "OrderDate": "2026-01-15T10:30:00Z",
    "OrderType": "RETAIL"
  },
  "RecipientContactInfo": {
    "FirstName": "John",
    "LastName": "Doe",
    "Address": "123 Main St",
    "City": "Napa",
    "State": "CA",
    "ZipCode": "94558",
    "Country": "US",
    "PhoneNumber": "7071234567",
    "EmailAddress": "customer@example.com"
  },
  "ShipmentInfo": {
    "ShippingCarrier": "FEX",
    "ShippingCarrierService": "GRND",
    "RequestedShipmentDate": "01/20/2026",
    "WineshippingWarehouseLocation": "APC01"
  },
  "ItemsInfo": [
    {
      "ItemNo": "1466-SE",
      "ItemDescription": "2016 CAB SAUV RESERVE NAPA VALLEY",
      "ItemQuantity": 6
    }
  ]
}
```

### Testing in Redocly Console

1. Open the [API Reference](/api/v3.1/openapi)
2. Navigate to **Fulfillment > Create Sales Order**
3. Click the **Try It Out** button
4. Select the "Quick Start" example or paste your payload
5. Replace authentication credentials with your test credentials
6. Click **Execute**


### Testing in Postman

1. Open your Postman workspace
2. Create a new POST request to: `https://api-test.wineshipping.com/v3/api/SalesOrder/CreateSalesOrder`
3. Set **Content-Type** header to `application/json`
4. Paste the payload in the request body
5. Click **Send**


### Testing with cURL

```bash
curl -X POST https://api-test.wineshipping.com/v3/api/SalesOrder/CreateSalesOrder \
  -H "Content-Type: application/json" \
  -d '{
    "Authentication": {
      "UserKey": "YOUR_USER_KEY",
      "Password": "YOUR_PASSWORD",
      "CustomerNo": "YOUR_CUSTOMER_NUMBER"
    },
    "OrderInfo": {
      "OrderNo": "MYORDER-001",
      "OrderDate": "2026-01-15T10:30:00Z",
      "OrderType": "DTC"
    },
    "RecipientContactInfo": {
      "FirstName": "John",
      "LastName": "Doe",
      "Address": "123 Main St",
      "City": "Napa",
      "State": "CA",
      "ZipCode": "94558",
      "Country": "US",
      "PhoneNumber": "7071234567",
      "EmailAddress": "customer@example.com"
    },
    "ShipmentInfo": {
      "ShippingCarrier": "FEX",
      "ShippingCarrierService": "GRND",
      "RequestedShipmentDate": "01/20/2026",
      "WineshippingWarehouseLocation": "APC01"
    },
    "ItemsInfo": [
      {
        "ItemNo": "1466-SE",
        "ItemDescription": "2016 CAB SAUV RESERVE NAPA VALLEY",
        "ItemQuantity": 6
      }
    ]
  }'
```

### Success Response

A successful request returns **HTTP 201** with a transaction reference ID:

```json
"D94BC05C-A1C3-4CBB-8DA1-E59C73AD2CAE"
```

**Store this ID!** Use it to track the order and troubleshoot any issues.

### Common Test Errors & Fixes

| Error | Cause | Solution |
|  --- | --- | --- |
| `401 Unauthorized` | Invalid credentials | Verify `UserKey`, `Password`, and `CustomerNo` |
| `400 Bad Request` | Missing/invalid required fields | Check all required fields are populated and formatted correctly |
| `429 Too Many Requests` | Rate limit exceeded | Wait before retrying; use webhooks instead of polling `GetDetails` for tracking updates |
| Order rejected | `ItemNo` unavailable or address invalid | Use `GetSellable` to verify items; validate address format |


## Step 3: Integrate with Your Software

Once your payload is verified in the console, integrate the request into your application using your preferred HTTP client library.

### Python Example

```python
import requests
import json
from datetime import datetime

def create_sales_order(item_no, quantity):
    url = "https://api-test.wineshipping.com/v3/api/SalesOrder/CreateSalesOrder"
    
    payload = {
        "Authentication": {
            "UserKey": "YOUR_USER_KEY",
            "Password": "YOUR_PASSWORD",
            "CustomerNo": "YOUR_CUSTOMER_NUMBER"
        },
        "OrderInfo": {
            "OrderNo": f"ORDER-{datetime.now().timestamp()}",
            "OrderDate": datetime.utcnow().isoformat() + "Z",
            "OrderType": "DTC",
            "WineshippingWarehouseLocation": "APC01"
        },
        "RecipientContactInfo": {
            "FirstName": "John",
            "LastName": "Doe",
            "Address": "123 Main St",
            "City": "Napa",
            "State": "CA",
            "ZipCode": "94558",
            "Country": "US",
            "PhoneNumber": "7071234567",
            "EmailAddress": "customer@example.com"
        },
        "ShipmentInfo": {
            "ShippingCarrier": "FEX",
            "ShippingCarrierService": "GRND",
            "RequestedShipmentDate": "01/20/2026"
        },
        "ItemsInfo": [
            {
                "ItemNo": item_no,
                "ItemQuantity": quantity
            }
        ]
    }
    
    headers = {"Content-Type": "application/json"}
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 201:
        transaction_id = response.json()
        print(f"Order created successfully. Transaction ID: {transaction_id}")
        return transaction_id
    else:
        print(f"Error: {response.status_code} - {response.text}")
        return None

# Usage
create_sales_order("1466-SE", 6)
```

### JavaScript/TypeScript Example

```typescript
async function createSalesOrder(itemNo: string, quantity: number): Promise<string | null> {
  const url = "https://api-test.wineshipping.com/v3/api/SalesOrder/CreateSalesOrder";
  
  const payload = {
    Authentication: {
      UserKey: "YOUR_USER_KEY",
      Password: "YOUR_PASSWORD",
      CustomerNo: "YOUR_CUSTOMER_NUMBER"
    },
    OrderInfo: {
      OrderNo: `ORDER-${Date.now()}`,
      OrderDate: new Date().toISOString(),
      OrderType: "DTC",
      WineshippingWarehouseLocation: "APC01"
    },
    RecipientContactInfo: {
      FirstName: "John",
      LastName: "Doe",
      Address: "123 Main St",
      City: "Napa",
      State: "CA",
      ZipCode: "94558",
      Country: "US",
      PhoneNumber: "7071234567",
      EmailAddress: "customer@example.com"
    },
    ShipmentInfo: {
      ShippingCarrier: "FEX",
      ShippingCarrierService: "GRND",
      RequestedShipmentDate: "01/20/2026"
    },
    ItemsInfo: [
      {
        ItemNo: itemNo,
        ItemQuantity: quantity
      }
    ]
  };
  
  try {
    const response = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload)
    });
    
    if (response.status === 201) {
      const transactionId = await response.json();
      console.log(`Order created successfully. Transaction ID: ${transactionId}`);
      return transactionId;
    } else {
      console.error(`Error: ${response.status} - ${response.statusText}`);
      return null;
    }
  } catch (error) {
    console.error("Request failed:", error);
    return null;
  }
}

// Usage
createSalesOrder("1466-SE", 6);
```

### C#/.NET Example

```csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class WineshippingOrderService
{
    private readonly HttpClient _httpClient;
    private const string ApiUrl = "https://api-test.wineshipping.com/v3/api/SalesOrder/CreateSalesOrder";
    
    public WineshippingOrderService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
    
    public async Task<string> CreateSalesOrderAsync(string itemNo, int quantity)
    {
        var payload = new
        {
            Authentication = new
            {
                UserKey = "YOUR_USER_KEY",
                Password = "YOUR_PASSWORD",
                CustomerNo = "YOUR_CUSTOMER_NUMBER"
            },
            OrderInfo = new
            {
                OrderNo = $"ORDER-{DateTime.UtcNow.Ticks}",
                OrderDate = DateTime.UtcNow.ToString("o"),
                OrderType = "DTC",
                WineshippingWarehouseLocation = "APC01"
            },
            RecipientContactInfo = new
            {
                FirstName = "John",
                LastName = "Doe",
                Address = "123 Main St",
                City = "Napa",
                State = "CA",
                ZipCode = "94558",
                Country = "US",
                PhoneNumber = "7071234567",
                EmailAddress = "customer@example.com"
            },
            ShipmentInfo = new
            {
                ShippingCarrier = "FEX",
                ShippingCarrierService = "GRND",
                RequestedShipmentDate = "01/20/2026"
            },
            ItemsInfo = new[]
            {
                new
                {
                    ItemNo = itemNo,
                    ItemQuantity = quantity
                }
            }
        };
        
        var json = JsonSerializer.Serialize(payload);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        
        var response = await _httpClient.PostAsync(ApiUrl, content);
        
        if (response.StatusCode == System.Net.HttpStatusCode.Created)
        {
            var responseContent = await response.Content.ReadAsStringAsync();
            var transactionId = JsonSerializer.Deserialize<string>(responseContent);
            Console.WriteLine($"Order created successfully. Transaction ID: {transactionId}");
            return transactionId;
        }
        else
        {
            var errorContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Error: {response.StatusCode} - {errorContent}");
            return null;
        }
    }
}

public static class Program
{
    public static async Task Main()
    {
        using var httpClient = new HttpClient();
        var service = new WineshippingOrderService(httpClient);
        await service.CreateSalesOrderAsync("1466-SE", 6);
    }
}
```

## Step 4: Monitor Your Shipment

After creating an order, track its status using webhooks (recommended) or the GetDetails API.

### Webhook Events (Recommended)

For the best experience and to avoid rate limiting, use event-driven tracking via webhooks instead of polling.

[Set up webhooks](/docs/eventdriventracking) to receive real-time updates on:

- Order fulfillment status
- Package tracking events
- Carrier updates
- Delivery estimates


### GetDetails API (For Ad-Hoc Queries)

```bash
curl -X POST https://api-test.wineshipping.com/v3/api/Tracking/GetDetails \
  -H "Content-Type: application/json" \
  -d '{
    "AuthenticationDetails": {
      "UserKey": "YOUR_USER_KEY",
      "Password": "YOUR_PASSWORD",
      "CustomerNo": "YOUR_CUSTOMER_NUMBER"
    },
    "OrderNo": "MYORDER-001"
  }'
```

## Next Steps

- **Explore more examples**: Check out the [full CreateSalesOrder examples](/api/v3.1/openapi/fulfillment/createsalesorder) for advanced scenarios (international orders, multiple items, etc.)
- **Set up webhooks**: Configure [Event-Driven Tracking](/docs/eventdriventracking) for real-time updates
- **Handle errors**: Review common error codes in [Codes & Descriptions](/docs/codes-descriptions)
- **Manage orders**: Learn how to [update](/api/v3.1/openapi/fulfillment/updatesalesorder) or [cancel](/api/v3.1/openapi/fulfillment/cancelsalesorder) orders
- **Inventory management**: Use [GetInventoryStatus](/api/v3.1/openapi/inventory/getinventorystatus) for detailed inventory information


## Support

For issues or questions:

- **Email**: [api@wineshipping.com](mailto:api@wineshipping.com)
- **API Reference**: [Full specification](/api/v3.1/openapi)
- **Infrastructure**: Learn about [environments and rate limits](/docs/infrastructure)