> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trackstarhq.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Trackstar is a unified REST API for WMS, cart, and carrier systems. Base URL: https://production.trackstarhq.com. There is no SDK; call the API with plain HTTP.
> Send x-trackstar-api-key on every request. Endpoints scoped to one connection also need x-trackstar-access-token. Read both from environment variables and never print them.
> Reads return data Trackstar has already synced from the connected system. Writes (POST, PUT, PATCH, DELETE) are forwarded to the connected system immediately.
> A new connection has no data until its initial sync finishes. Wait for the connection.historical-sync-completed webhook, or poll GET /connections/{connection_id} and check historical_sync_completed.
> List endpoints page with page_token and next_token (limit is capped at 1000). Repeat every filter on every page. Filters use field[operator]=value, for example created_date[gte]=2026-01-01T00:00:00Z.
> Write bodies must not contain null or empty strings; omit the field instead. Call GET /integrations/{integration_type}/{integration_name}/write-info first to learn the exact fields an integration accepts.
> To test without real credentials, POST /sandbox/generate-sandbox/{wms|cart|carrier} with the API key returns a sandbox access token. Start at https://docs.trackstarhq.com/how-to-guides/build-with-ai.md and install the skills with: npx skills add https://docs.trackstarhq.com

# Writing Data

> Create and update records in connected systems, and find the fields each integration accepts

The Trackstar API enables you to write data into your end users' connected accounts.

Unlike reads, writes don't involve [syncing](/how-to-guides/syncing-data): when you perform a write operation (such as creating or updating a resource via `POST` or `PUT`), Trackstar forwards that request directly to the underlying integration in real time. We respond immediately with the success or error status from the integration, including any error messages or validation feedback provided by the integration itself. This ensures transparency and helps with rapid debugging and resolution when issues arise.

We have done the heavy lifting to unify the `body` of each action across integrations, so you can write data in a consistent way across all of them. The same field means the same thing no matter which integration you send it to.

Which fields are required or accepted still depends on the integration, and some integrations take a field that is unique to them. So the API reference shows one schema per integration for every write, starting with the [Sandbox](/how-to-guides/sandbox), which you can use to try a write before connecting a real account. See [Extensiv's Create Order Schema](/api-reference/wms-api/orders/post#extensiv-3-pl-central) for an example.

On the API side, we have created an endpoint that will return the required and optional fields for a given integration.

## The /write-info endpoint

The [GET Write Info](/api-reference/mgmt/integration-write-info) endpoint returns information on our supported integrations in standard OpenAPI format. The required and optional fields are denoted in the response. If you choose to pass in the optional access token, you will also get any connection-specific information you might need about writing data. Here's an example from hitting `/integrations/wms/ongoing` (truncated for just Returns):

```json theme={null}
{
  "openapi": "3.1.0",
  "paths": {
    "/wms/returns": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatewmsReturnOngoingSchema"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Create WMS Return output"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CreatewmsReturnOngoingSchema": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "description": "The ID of the order that the return is associated with. Can be passed into the [Order](/api-reference/wms-api/orders/get-item) endpoint for more details.",
            "example": "order_id"
          },
          "warehouse_id": {
            "type": "string",
            "description": "The ID of the warehouse receiving the return. Can be passed into the [Warehouse](/api-reference/wms-api/warehouses/get-item) endpoint for more details.",
            "example": "warehouse"
          },
          "line_items": {
            "type": "array",
            "description": "A list of inventory items included in the return.",
            "example": [
              {
                "sku": "TEST-SKU",
                "expected_quantity": 1,
                "return_cause": null
              }
            ],
            "items": {
              "$ref": "#/components/schemas/WmsReturnWriteLineItemongoing"
            }
          },
          "return_number": {
            "type": "string",
            "description": "Return number"
          },
          "tracking_number": {
            "type": "string",
            "description": ""
          },
          "tracking_url": {
            "type": "string",
            "description": ""
          },
          "trackstar_tags": {
            "type": [
              "array",
              "null"
            ],
            "description": "A list of custom tags associated with the resource. A tag can be either a string or a dictionary with one key-value pair.",
            "example": [
              "tag1",
              "tag2",
              {
                "tag3": "value3"
              }
            ],
            "items": {}
          }
        },
        "required": [
          "line_items",
          "order_id",
          "return_number"
        ],
        "additionalProperties": false,
        "title": "CreatewmsReturnOngoingSchema"
      },
      "WmsReturnWriteLineItemongoing": {
        "type": "object",
        "properties": {
          "sku": {
            "type": "string",
            "description": ""
          },
          "expected_quantity": {
            "type": "integer",
            "description": "",
            "example": 0
          },
          "return_cause": {
            "$ref": "#/components/schemas/ReturnCause"
          }
        },
        "required": [
          "expected_quantity",
          "sku"
        ],
        "additionalProperties": false,
        "title": "WmsReturnWriteLineItemongoing"
      },
      "ReturnCause": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "1",
              "13",
              "3"
            ],
            "description": "The reason code for this return. Specific to your connection."
          },
          "return_reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "damaged",
              "wrong size",
              "no longer needed"
            ],
            "description": "The reason description for this return. Specific to your connection."
          }
        },
        "required": [
          "code"
        ],
        "additionalProperties": false,
        "title": "ReturnCause"
      }
    }
  }
}
```

<Note>
  Write endpoints your org has [disabled](/how-to-guides/syncing-data#disabled-endpoints) return a `403` (e.g. `create_order is disabled for this connection`) without reaching the integration.
</Note>

## Example Create Return Request

Based on the response from the `/write-info` endpoint, the required and optional fields to create an order in the `Some WMS` integration are as follows:

| Field | Description | Type | Required |
| - | - | - | - |
| order\_id | The order ID associated with the return | string | Yes |
| warehouse\_id | The warehouse ID | string | No |
| line\_items | The line items | array | Yes |
| line\_items.sku | The SKU of the line item | string | Yes |
| line\_items.expected\_quantity | The expected quantity of the line item | number | Yes |
| line\_items.return\_cause | The reason for the line item's return | object | No |
| line\_items.return\_cause.code | The reason code for the line item's return. The values in this field are different for different connections - for this connection they are "1", "13", or "3" | string | Yes |
| line\_items.return\_cause.return\_reason | The reason description for the line item's return. The values in this field are different for different connections - for this connection they are "damaged", "wrong size", or "no longer needed" | string | No |
| return\_number | The RMA number | string | Yes |
| tracking\_number | The tracking number | string | No |
| tracking\_url | The tracking URL | string | No |
| trackstar\_tags | The [Trackstar Tags](/how-to-guides/trackstar-tags) | array | No |

Let's send in all of the fields for this request:

```bash theme={null}
curl -X POST https://production.trackstarhq.com/wms/returns \
  -H "x-trackstar-api-key: <x-trackstar-api-key>" \
  -H "x-trackstar-access-token: <x-trackstar-access-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "1234",
    "warehouse_id": "warehouse_1",
    "line_items": [
      {
        "sku": "123",
        "expected_quantity": 2,
        "return_cause": {
	  "code": "1",
	  "return_reason": "damaged"
	}
      }
    ],
    "return_number": "rma_456",
    "tracking_number": "tracking_abc",
    "tracking_url": "https://fedex.com/tracking_abc",
    "trackstar_tags": ["tag1"]
  }'
```

And that's it! You have successfully created an order in your end user's connected system.

## Non Nullable Fields

All fields in the write body are **non-nullable**. You cannot send a `null` / `"none"` / empty string for any field. This is because `null`s are ambiguous: they could mean you want the field blank on purpose, or maybe you're just using a default. The underlying systems also disagree on what a `null` should do (some clear the field, some reject the request, some ignore it). Rather than guess and risk writing data you didn't intend, we reject the request up front. If you don't mean to set a field, leave it out of the body entirely.

For example, `tracking_number` and `tracking_url` are optional fields. Sending in the following request will result in a 422 error response:

```bash theme={null}
  curl -X POST https://production.trackstarhq.com/wms/returns \
  -H "x-trackstar-api-key: <x-trackstar-api-key>" \
  -H "x-trackstar-access-token: <x-trackstar-access-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "1234",
    "warehouse_id": "warehouse_1",
    "line_items": [
      {
        "sku": "123",
        "expected_quantity": 2,
        "return_cause": {
	  "code": "1",
	  "return_reason": "damaged"
	}
      }
    ],
    "return_number": "rma_456",
    "tracking_number": "",
    "tracking_url": null
  }'
```

Instead, you should omit the fields from the request like so:

```bash theme={null}
  curl -X POST https://production.trackstarhq.com/wms/returns \
  -H "x-trackstar-api-key: <x-trackstar-api-key>" \
  -H "x-trackstar-access-token: <x-trackstar-access-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "1234",
    "warehouse_id": "warehouse_1",
    "line_items": [
      {
        "sku": "123",
        "expected_quantity": 2,
        "return_cause": {
	  "code": "1",
	  "return_reason": "damaged"
	}
      }
    ],
    "return_number": "rma_456"
  }'
```

## Safe Retries with Idempotency Keys

When you write to the integration, it happens right away. If the network has a problem or times out, you might not know if your write actually went through. If you try again without checking, the write could be applied twice in the connected system, such as a duplicate order or the same file attached again.

To make retrying safe, send an `Idempotency-Key` header with your write. Use a unique value for each write, like a UUID (up to 255 characters). If you retry with the same key, we'll give you the response from the first request instead of sending it to the integration again.

```bash theme={null}
curl -X POST https://production.trackstarhq.com/wms/returns \
  -H "x-trackstar-api-key: <x-trackstar-api-key>" \
  -H "x-trackstar-access-token: <x-trackstar-access-token>" \
  -H "Idempotency-Key: 9f1c2b1e-6d4a-4c1c-9a8e-2b7e3c5d1f00" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "1234",
    "line_items": [
      {
        "sku": "123",
        "expected_quantity": 2
      }
    ],
    "return_number": "rma_456"
  }'
```

The response to a retried request with the same key depends on what happened to the first request:

| First request | Retry with the same key |
| - | - |
| Succeeded | You get the first request's response, with an `Idempotent-Replayed: true` header. The write is not sent to the integration again. |
| Failed | The key gets released. Your retry is sent to the integration as a new write. |
| Still in progress | You get a `409`. Wait for the first request to finish, then try again. If it hasn't finished after 15 minutes, your retry is sent as a new write. |
| Sent to a different endpoint or with a different body | You get a `400`. A key belongs to one exact request. |

A few more things to know:

* Keys expire 24 hours after the first request. After that, the same key acts like a new one.
* Keys are tied to a connection. Using the same key on two different connections counts as two separate keys.
* A retry still counts as the same request if its body lists the fields in a different order or uses different spacing. Reordering the items inside a list, such as `line_items`, **does** make it a different request.
* Every write endpoint accepts this header, including cancels and batch writes. [Passthrough requests](/how-to-guides/passthrough-requests) don't.

<Warning>
  A key only replays a write that worked. If we return an error (5xx), a retry with the same key is sent to the integration again. In rare cases, the integration saves the record before the error happens. For example, it might accept an order but time out before it confirms the order. A retry then creates a duplicate unless the integration rejects duplicates itself, such as when it rejects a repeated order number.
</Warning>

## Don't See a Field You Need?

If the field is part of Trackstar's schema (think `order_number`, `carrier_name`, `expected_arrival_date` etc) then reach out to us and we'll gladly expose it for you if the integration allows.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.