# Shipment Numbers & Uniqueness

The `shipment_number` is a user-friendly, human-readable identifier for shipments. Understanding how it works and its relationship to `external_shipment_id` is important for proper integration.

## What is shipment_number?

The `shipment_number` is equivalent to `orderNumber` in the v1 API and ShipStation UI. It's designed to be:

- **Human-readable**: Easy to reference in conversations and support tickets
- **Unique per account**: No two shipments can have the same `shipment_number`
- **Optional**: You can provide your own or let the system generate one
- **Mutable**: Can be updated after creation (unlike `external_shipment_id`)


### v1 to v2 Mapping

| **v1 / UI Term** | **v2 Term** | **Purpose** |
|  --- | --- | --- |
| orderNumber | shipment_number | User-friendly display number |


## Uniqueness Rules

### Enforced Uniqueness

The `shipment_number` field has **strict uniqueness enforcement** at the account level:

- ✅ Each `shipment_number` must be unique within your ShipStation account
- ❌ Attempting to create a shipment with a duplicate `shipment_number` will fail
- ⚠️ This applies across **all shipments**, regardless of status


**Example Error:**


```json
{
  "errors": [
    {
      "message": "A shipment with shipment_number 'ORDER-12345' already exists",
      "field": "shipment_number"
    }
  ]
}
```

### How external_shipment_id Differs

| Field | Uniqueness | Mutability | Auto-Generated |
|  --- | --- | --- | --- |
| `shipment_number` | Required unique | Can be updated | Yes (if not provided) |
| `external_shipment_id` | Required unique | Cannot be changed | Yes (if not provided) |


Both fields must be unique, but `shipment_number` can be updated after creation while `external_shipment_id` is immutable.

## Automatic Population Rules

ShipStation follows a **duplication rule** when neither field is provided:

### Scenario 1: You Provide Both


```json
{
  "external_shipment_id": "ORDER-2024-12345",
  "shipment_number": "ORD-12345",
  ...
}
```

**Result:** Both values are used as provided.

### Scenario 2: You Provide Only external_shipment_id


```json
{
  "external_shipment_id": "ORDER-2024-12345",
  // shipment_number not provided
  ...
}
```

**Result:**

- `external_shipment_id` = `"ORDER-2024-12345"` (your value)
- `shipment_number` = `"ORDER-2024-12345"` (duplicated from external_shipment_id)


Common Pattern
Many integrations only provide `external_shipment_id` and let the system duplicate it to `shipment_number`. This works well if your external IDs are already human-readable.

### Scenario 3: You Provide Only shipment_number


```json
{
  // external_shipment_id not provided
  "shipment_number": "ORD-12345",
  ...
}
```

**Result:**

- `shipment_number` = `"ORD-12345"` (your value)
- `external_shipment_id` = `"se-123456789"` (system-generated based on shipment_id)


### Scenario 4: You Provide Neither


```json
{
  // Neither field provided
  ...
}
```

**Result:** Both are auto-generated based on the internal `shipment_id`:

- `external_shipment_id` = `"se-123456789"`
- `shipment_number` = `"se-123456789"`


Not Recommended
Relying on auto-generated values makes it harder to correlate ShipStation records with your own system. Always provide at least `external_shipment_id`.

## Best Practices

### Use Meaningful Identifiers


```json
// ✅ Good - Clear, readable identifiers
{
  "external_shipment_id": "SHOPIFY-ORDER-98765",
  "shipment_number": "WEB-2024-0615-001"
}

// ❌ Not ideal - Cryptic or auto-generated values
{
  "external_shipment_id": "se-123456789",
  "shipment_number": "se-123456789"
}
```

### Handle Uniqueness Conflicts

If you encounter a duplicate `shipment_number` error:

1. **Check if the shipment already exists** - Query by `external_shipment_id` to see if you already created it
2. **Use a different number** - Append a suffix or increment a counter
3. **Update the existing shipment** - If you're re-creating a canceled shipment



```javascript
// Example: Retry with incremented number
try {
  await createShipment({
    external_shipment_id: "ORDER-12345",
    shipment_number: "ORD-12345"
  });
} catch (error) {
  if (error.field === 'shipment_number') {
    // Retry with suffixed number
    await createShipment({
      external_shipment_id: "ORDER-12345",
      shipment_number: "ORD-12345-RETRY"
    });
  }
}
```

### Leverage the Duplication Rule

If your `external_shipment_id` values are already user-friendly, just provide that:


```json
{
  "external_shipment_id": "ORDER-2024-06-15-001"
  // shipment_number will automatically duplicate: "ORDER-2024-06-15-001"
}
```

This reduces redundancy and ensures consistency.

## Updating shipment_number

Unlike `external_shipment_id`, you **can update** the `shipment_number` after creation:


```http
PUT /v2/shipments/se-123456
{
  "shipment_number": "NEW-NUMBER-456"
}
```

Must Still Be Unique
The new `shipment_number` must still be unique across your account. If another shipment already has that number, the update will fail.

## Common Scenarios

### E-commerce Integration


```json
{
  "external_shipment_id": "SHOPIFY-98765",
  "shipment_number": "ORDER-2024-001",
  // external_shipment_id tracks the Shopify order
  // shipment_number is what customers see
}
```

### Sequential Order Numbers


```json
{
  "external_shipment_id": "UUID-a1b2c3d4",
  "shipment_number": "100001",  // Sequential counter
}
```

### Date-Based Order Numbers


```json
{
  "external_shipment_id": "INTERNAL-789",
  "shipment_number": "20240615-001",  // YYYYMMDD-sequence
}
```

## Related Guides

- **[External Identifiers Guide](/orders/external-identifiers)** - Deep dive on `external_shipment_id` and `external_order_id`
- **[Understanding Orders & Shipments](/orders/understanding-orders-shipments)** - Core concepts overview
- **[Legacy API Migration](/orders/legacy-migration)** - Migrating from v1 `orderNumber`