# Sales channels

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /sales-channel/channels

**List supported channels**

`operationId: SalesChannelController_getAvailableChannels`

Every channel the platform can sell through, with the capabilities each one supports — order sync, pricing sync, inventory sync. Static platform capability, not org configuration; nothing here means the org can actually sell on it.

#### Signature

```http
GET /sales-channel/channels () -> Channels keyed by id
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/channels/configured`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Channels keyed by id |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/channels/configured

**List configured channels**

`operationId: SalesChannelController_getConfiguredChannels`

The same channel list, each flagged with whether **this org** has working integration credentials. This is the one to read before offering a channel in a UI.

#### Signature

```http
GET /sales-channel/channels/configured () -> Channels with an `enabled` flag
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/channels`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Channels with an `enabled` flag |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/channels/status

**Get all channel statuses**

`operationId: SalesChannelController_getAllChannelStatuses`

Live connection status for every configured channel — whether credentials still authenticate and when each last synced. Use it for a health board; a channel can be enabled but broken.

#### Signature

```http
GET /sales-channel/channels/status () -> Per-channel status
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/channels/{channelId}/status`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-channel status |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/channels/{channelId}/status

**Get one channel's status**

`operationId: SalesChannelController_getChannelStatus`

Connection status and last-sync detail for a single channel.

#### Signature

```http
GET /sales-channel/channels/{channelId}/status (channelId: string) -> The channel status
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/channels/status`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The channel status |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/channels/{channelId}/enable

**Enable a channel**

`operationId: SalesChannelController_enableChannel`

Stores the org's credentials for a channel and turns it on. The body shape is per-channel — a marketplace seller id and API keys, an OAuth token — so read `GET /sales-channel/channels` for what the channel expects.

Enabling does not push anything: listings, inventory and prices still have to be synced explicitly.

#### Signature

```http
POST /sales-channel/channels/{channelId}/enable (channelId: string, body) -> The enable result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Stores credentials — do not log the request body.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/channels/{channelId}/disable`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

Channel credentials and options.

```json
{
  "sellerId": "A1B2C3D4",
  "apiKey": "<key>",
  "marketplace": "US"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The enable result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/channels/{channelId}/disable

**Disable a channel**

`operationId: SalesChannelController_disableChannel`

Turns a channel off so nothing further syncs to it. Listings already live on the marketplace are **not** taken down — they stop receiving inventory and price updates, which leaves them selling at the last synced values. End listings on the channel itself if that is what you want.

#### Signature

```http
POST /sales-channel/channels/{channelId}/disable (channelId: string) -> The disable result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Live listings stay up and stop being updated.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/channels/{channelId}/enable`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The disable result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/sync/history

**Get sync history**

`operationId: SalesChannelController_getSyncHistory`

The log of sync operations across channels — what ran, when, and whether it succeeded. The first place to look when a channel's stock or prices are stale.

#### Signature

```http
GET /sales-channel/sync/history (channelId?: string, operation?: string, limit?: integer) -> Sync history entries, newest first
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/inventory/sync`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | query | string | — |  |
| `operation` | query | string | — | Operation name, e.g. `inventory-sync`. |
| `limit` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Sync history entries, newest first |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/channels/{channelId}/execute

**Execute a channel operation**

`operationId: SalesChannelController_executeChannelOperation`

Escape hatch: runs a named operation against one channel, passing `data` through to the channel adapter. Which operations exist depends on the channel — this is the route to use when a capability has no dedicated endpoint.

Because it is a passthrough, the payload is not validated here; the channel decides what is acceptable.

#### Signature

```http
POST /sales-channel/channels/{channelId}/execute (channelId: string, body) -> The channel's response
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Unvalidated passthrough — the channel accepts or rejects the payload.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/channels/bulk-execute`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The operation and its payload.

```json
{
  "operation": "update-listing",
  "data": {
    "sku": "COLA-330",
    "title": "Cola 330ml"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The channel's response |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/channels/bulk-execute

**Execute an operation on many channels**

`operationId: SalesChannelController_executeBulkOperation`

Runs the same operation against several channels in one call. Each channel is attempted independently, so a partial failure is normal — read the per-channel results rather than assuming a 2xx means everything succeeded.

#### Signature

```http
POST /sales-channel/channels/bulk-execute (body) -> Per-channel results
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Partial success is expected — inspect each channel's result.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/channels/{channelId}/execute`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Channels, operation and payload.

```json
{
  "channelIds": [
    "amazon",
    "ebay"
  ],
  "operation": "update-listing",
  "data": {
    "sku": "COLA-330"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-channel results |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/inventory/{sku}

**Get master inventory for a SKU**

`operationId: InventorySyncController_getMasterInventory`

The authoritative stock figure for a SKU — the single number every channel is synced from.

#### Signature

```http
GET /sales-channel/inventory/{sku} (sku: string) -> Master inventory
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/inventory/{sku}/channels`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Master inventory |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /sales-channel/inventory/{sku}

**Update master inventory**

`operationId: InventorySyncController_updateMasterInventory`

Sets the master stock level for a SKU. `syncToChannels` decides whether the new figure is pushed to the marketplaces immediately — leave it off and the channels keep selling against the old number until a sync runs.

#### Signature

```http
PUT /sales-channel/inventory/{sku} (sku: string, body) -> The updated inventory
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Absolute set, not a delta.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | PRODUCT_NOT_FOUND | Product <sku> not found | No product carries that SKU. Returned as 400, not 404. | Check the SKU against the catalogue. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /sales-channel/inventory/bulk/update`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |

### Request body

The new quantity.

```json
{
  "quantity": 120,
  "syncToChannels": true,
  "reason": "Stock count"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated inventory |
| `400` | Product <sku> not found — No product carries that SKU. Returned as 400, not 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /sales-channel/inventory/bulk/update

**Bulk-update master inventory**

`operationId: InventorySyncController_bulkUpdateInventory`

Sets stock for many SKUs at once — the endpoint a stock count or a warehouse feed uses. Each quantity is absolute, not a delta.

#### Signature

```http
PUT /sales-channel/inventory/bulk/update (body) -> Per-SKU results
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Quantities are absolute.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /sales-channel/inventory/{sku}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The updates.

```json
{
  "updates": [
    {
      "sku": "COLA-330",
      "quantity": 120
    },
    {
      "sku": "COLA-500",
      "quantity": 40
    }
  ],
  "syncToChannels": true
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-SKU results |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/inventory/reserve

**Reserve inventory for an order**

`operationId: InventorySyncController_reserveInventory`

Holds stock for an order so it cannot be sold twice while the order is being paid for or fulfilled. Reservations are the mechanism that prevents oversells across channels.

Every reservation must end in a `commit` or a `release` — one left open holds stock indefinitely.

#### Signature

```http
POST /sales-channel/inventory/reserve (body) -> The reservation
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Always follow with commit or release.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | PRODUCT_NOT_FOUND | Product <sku> not found | No product carries that SKU. Returned as 400, not 404. | Check the SKU against the catalogue. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/inventory/reservation/{reservationId}/commit`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

What to reserve and for which order.

```json
{
  "items": [
    {
      "sku": "COLA-330",
      "quantity": 2
    }
  ],
  "orderId": "ORD-4821"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The reservation |
| `400` | Product <sku> not found — No product carries that SKU. Returned as 400, not 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/inventory/reservation/{reservationId}/release

**Release a reservation**

`operationId: InventorySyncController_releaseReservation`

Returns held stock to available — the order was cancelled or the payment failed. Run this on abandoned checkouts; unreleased holds slowly starve the sellable quantity.

#### Signature

```http
POST /sales-channel/inventory/reservation/{reservationId}/release (reservationId: string) -> The release result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | RESERVATION_NOT_FOUND | Reservation <id> not found | No reservation has that id. | Check the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/inventory/reserve`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `reservationId` | path | string | yes | Reservation id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The release result |
| `400` | Reservation <id> not found — No reservation has that id. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/inventory/reservation/{reservationId}/commit

**Commit a reservation**

`operationId: InventorySyncController_commitReservation`

Converts a hold into an actual stock decrement — the order shipped or was paid. Irreversible through this API: undoing it means putting the stock back with an inventory update.

#### Signature

```http
POST /sales-channel/inventory/reservation/{reservationId}/commit (reservationId: string) -> The commit result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Permanently decrements stock.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | RESERVATION_NOT_FOUND | Reservation <id> not found | No reservation has that id. Returned as 400, not 404. | Check the id from the reserve response. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/inventory/reservation/{reservationId}/release`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `reservationId` | path | string | yes | Reservation id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The commit result |
| `400` | Reservation <id> not found — No reservation has that id. Returned as 400, not 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/inventory/sync/{channelId}

**Push inventory to one channel**

`operationId: InventorySyncController_syncToChannel`

Pushes the given SKUs' stock levels to a single channel.

#### Signature

```http
POST /sales-channel/inventory/sync/{channelId} (channelId: string, body) -> The sync result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/inventory/sync`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The items to push.

```json
{
  "items": [
    {
      "sku": "COLA-330",
      "quantity": 120
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The sync result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/inventory/sync

**Push inventory to all channels**

`operationId: InventorySyncController_syncToAllChannels`

Pushes the given SKUs' stock to every configured channel. Channels are attempted independently — check the per-channel results, since a single failure leaves that marketplace stale and able to oversell.

#### Signature

```http
POST /sales-channel/inventory/sync (body) -> Per-channel results
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Partial failure leaves that channel stale.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/sync/history`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The items to push.

```json
{
  "items": [
    {
      "sku": "COLA-330",
      "quantity": 120
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-channel results |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/inventory/pull/{channelId}

**Pull inventory from a channel**

`operationId: InventorySyncController_pullFromChannel`

Reads stock levels back from a channel — for reconciling after a marketplace-side change, or for a first import. Pulling does not overwrite master; compare before deciding which side is right.

#### Signature

```http
POST /sales-channel/inventory/pull/{channelId} (channelId: string) -> What the channel reports
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/inventory/{sku}/channels`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | What the channel reports |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/inventory/alerts/low-stock

**List low-stock items**

`operationId: InventorySyncController_getLowStockItems`

SKUs at or below their reorder threshold — what to restock, or to pull from channels before it oversells.

#### Signature

```http
GET /sales-channel/inventory/alerts/low-stock () -> Low-stock items
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /sales-channel/inventory/bulk/update`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Low-stock items |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/inventory/{sku}/channels

**Get a SKU's stock across channels**

`operationId: InventorySyncController_getInventoryAcrossChannels`

What each channel currently believes the stock is, next to the master figure. Divergence here is what causes oversells — a channel still showing stock that master no longer has.

#### Signature

```http
GET /sales-channel/inventory/{sku}/channels (sku: string) -> Per-channel quantities
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/inventory/sync`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-channel quantities |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/categories

**List category mappings**

`operationId: ChannelMappingController_getAllCategoryMappings`

How the org's own categories translate to each channel's taxonomy. Marketplaces reject listings in the wrong category, so these mappings are what make a listing publishable.

#### Signature

```http
GET /sales-channel/mappings/categories () -> Category mappings
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/categories`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Category mappings |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/mappings/categories

**Save a category mapping**

`operationId: ChannelMappingController_saveCategoryMapping`

Creates or replaces a category mapping. Saving by source category, so re-posting the same source category overwrites the previous mapping rather than adding a second.

#### Signature

```http
POST /sales-channel/mappings/categories (body) -> The saved mapping
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /sales-channel/mappings/categories/{mappingId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The mapping.

```json
{
  "sourceCategory": "beverages",
  "channelId": "amazon",
  "channelCategory": "16310101"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The saved mapping |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/categories/{sourceCategory}

**Get a category mapping**

`operationId: ChannelMappingController_getCategoryMapping`

The mapping for one source category across all channels.

#### Signature

```http
GET /sales-channel/mappings/categories/{sourceCategory} (sourceCategory: string) -> The mapping
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/mappings/categories/{sourceCategory}/channel/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sourceCategory` | path | string | yes | The org's own category. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The mapping |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /sales-channel/mappings/categories/{mappingId}

**Delete a category mapping**

`operationId: ChannelMappingController_deleteCategoryMapping`

Removes a category mapping. Products in that category can no longer be transformed for the affected channel until a new mapping exists.

#### Signature

```http
DELETE /sales-channel/mappings/categories/{mappingId} (mappingId: string) -> The delete result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/categories`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `mappingId` | path | string | yes | Mapping id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The delete result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/categories/{sourceCategory}/channel/{channelId}

**Resolve a category for a channel**

`operationId: ChannelMappingController_getChannelCategory`

Resolves one source category to the specific category id that channel expects — the single lookup a listing builder needs.

#### Signature

```http
GET /sales-channel/mappings/categories/{sourceCategory}/channel/{channelId} (sourceCategory: string, channelId: string) -> The channel category
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/transform/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sourceCategory` | path | string | yes | The org's own category. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The channel category |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/attributes

**List attribute mappings**

`operationId: ChannelMappingController_getAllAttributeMappings`

How the org's product fields map onto each channel's attribute names — `colour` to `color_name`, and so on.

#### Signature

```http
GET /sales-channel/mappings/attributes () -> Attribute mappings
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/attributes`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Attribute mappings |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/mappings/attributes

**Save an attribute mapping**

`operationId: ChannelMappingController_saveAttributeMapping`

Creates or replaces an attribute mapping. A mapping can be marked required — a product missing that source field then fails validation rather than publishing an incomplete listing.

#### Signature

```http
POST /sales-channel/mappings/attributes (body) -> The saved mapping
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/validate/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The mapping.

```json
{
  "sourceField": "colour",
  "channelId": "amazon",
  "targetField": "color_name",
  "required": true
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The saved mapping |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/attributes/{sourceAttribute}

**Get an attribute mapping**

`operationId: ChannelMappingController_getAttributeMapping`

The mapping for one source attribute.

#### Signature

```http
GET /sales-channel/mappings/attributes/{sourceAttribute} (sourceAttribute: string) -> The mapping
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/mappings/attributes`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sourceAttribute` | path | string | yes | The org's own field name. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The mapping |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /sales-channel/mappings/attributes/{mappingId}

**Delete an attribute mapping**

`operationId: ChannelMappingController_deleteAttributeMapping`

Removes an attribute mapping. Transformed listings will no longer carry that field.

#### Signature

```http
DELETE /sales-channel/mappings/attributes/{mappingId} (mappingId: string) -> The delete result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/attributes`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `mappingId` | path | string | yes | Mapping id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The delete result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/templates

**List channel templates**

`operationId: ChannelMappingController_getChannelTemplates`

Listing templates — reusable sets of defaults and field rules applied when building a listing for a channel.

#### Signature

```http
GET /sales-channel/mappings/templates (channelId?: string) -> Templates
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/apply-template/{templateId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Templates |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/mappings/templates

**Save a channel template**

`operationId: ChannelMappingController_saveChannelTemplate`

Creates or replaces a listing template.

#### Signature

```http
POST /sales-channel/mappings/templates (body) -> The saved template
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/mappings/templates`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The template.

```json
{
  "name": "Beverages — Amazon",
  "channelId": "amazon",
  "defaults": {
    "brand": "Acme"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The saved template |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/templates/{templateId}

**Get a channel template**

`operationId: ChannelMappingController_getChannelTemplate`

Fetches one listing template.

#### Signature

```http
GET /sales-channel/mappings/templates/{templateId} (templateId: string) -> The template
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | TEMPLATE_NOT_FOUND | Template <templateId> not found | No template has that id. Returned as 400, not 404. | List templates first. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/templates`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `templateId` | path | string | yes | Template id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The template |
| `400` | Template <templateId> not found — No template has that id. Returned as 400, not 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /sales-channel/mappings/templates/{templateId}

**Delete a channel template**

`operationId: ChannelMappingController_deleteChannelTemplate`

Removes a listing template. Listings already published are unaffected; future builds lose its defaults.

#### Signature

```http
DELETE /sales-channel/mappings/templates/{templateId} (templateId: string) -> The delete result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/templates`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `templateId` | path | string | yes | Template id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The delete result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/mappings/transform/{channelId}

**Transform a product for a channel**

`operationId: ChannelMappingController_transformProduct`

Runs a product through the category and attribute mappings and returns the channel-shaped payload — exactly what would be sent to the marketplace. Read-only preview: nothing is published.

#### Signature

```http
POST /sales-channel/mappings/transform/{channelId} (channelId: string, body) -> The channel-shaped product
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/validate/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The product to transform.

```json
{
  "sku": "COLA-330",
  "title": "Cola 330ml",
  "category": "beverages",
  "colour": "red"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The channel-shaped product |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/mappings/apply-template/{templateId}

**Apply a template to a product**

`operationId: ChannelMappingController_applyTemplate`

Merges a template's defaults into a product and returns the result. A preview — the product itself is not modified.

#### Signature

```http
POST /sales-channel/mappings/apply-template/{templateId} (templateId: string, body) -> The product with template defaults applied
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/transform/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `templateId` | path | string | yes | Template id. |

### Request body

The product.

```json
{
  "sku": "COLA-330",
  "title": "Cola 330ml"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The product with template defaults applied |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/mappings/validate/{channelId}

**Validate a product for a channel**

`operationId: ChannelMappingController_validateProduct`

Checks one product against a channel's requirements and reports what would be rejected — the cheap check to run before publishing, since marketplace rejections are slow and opaque.

#### Signature

```http
POST /sales-channel/mappings/validate/{channelId} (channelId: string, body) -> Validation result with any problems found
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/mappings/validate/{channelId}/bulk`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The product to validate.

```json
{
  "sku": "COLA-330",
  "title": "Cola 330ml",
  "category": "beverages"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Validation result with any problems found |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/mappings/validate/{channelId}/bulk

**Validate the whole catalogue for a channel**

`operationId: ChannelMappingController_bulkValidate`

Validates every product against one channel and reports the failures — the pre-flight before a first publish to a new marketplace.

Note this is a **GET** that scans the full catalogue, so it can be slow on a large one and is not cheap to poll.

#### Signature

```http
GET /sales-channel/mappings/validate/{channelId}/bulk (channelId: string) -> Per-product validation results
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Scans the entire catalogue — expect a long response time.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/mappings/validate/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-product validation results |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/orders/sync/{channelId}

**Pull orders from a channel**

`operationId: OrderAggregationController_syncChannel`

Fetches orders from one marketplace into the aggregated order list. Without a date range the channel's own default window applies, so pass `fromDate` when back-filling.

#### Signature

```http
POST /sales-channel/orders/sync/{channelId} (channelId: string, body) -> The sync result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/orders/sync`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

Optional window and status filter.

```json
{
  "fromDate": "2026-08-01"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The sync result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/orders/sync

**Pull orders from all channels**

`operationId: OrderAggregationController_syncAll`

Runs the order pull across every configured channel. Channels that do not support order sync are skipped rather than failing the call — read the per-channel results.

#### Signature

```http
POST /sales-channel/orders/sync (body) -> Per-channel results
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/orders`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Optional window.

```json
{
  "fromDate": "2026-08-01"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-channel results |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/orders

**List aggregated orders**

`operationId: OrderAggregationController_getOrders`

Orders from every channel in one list with a common shape — the single queue an operations team works from instead of logging into each marketplace.

#### Signature

```http
GET /sales-channel/orders (channel?: string, status?: string, fromDate?: string, toDate?: string, page?: integer, pageSize?: integer) -> Aggregated orders
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/orders/{orderId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channel` | query | string | — |  |
| `status` | query | string | — |  |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Aggregated orders |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/orders/{orderId}

**Get an aggregated order**

`operationId: OrderAggregationController_getOrder`

One order with its items, buyer detail and channel of origin.

#### Signature

```http
GET /sales-channel/orders/{orderId} (orderId: string) -> The order
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORDER_NOT_FOUND | Order <orderId> not found | No aggregated order has that id. Returned as 400, not 404. | Check the id from the order list. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /sales-channel/orders/{orderId}/status`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `orderId` | path | string | yes | Aggregated order id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The order |
| `400` | Order <orderId> not found — No aggregated order has that id. Returned as 400, not 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /sales-channel/orders/{orderId}/status

**Update an order's status**

`operationId: OrderAggregationController_updateStatus`

Moves an aggregated order to a new status, optionally attaching a tracking number. Marking an order shipped with tracking is what pushes fulfilment back to the marketplace — the buyer sees it, so the tracking number must be real.

#### Signature

```http
PUT /sales-channel/orders/{orderId}/status (orderId: string, body) -> The updated order
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Shipment status is visible to the marketplace buyer.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORDER_NOT_FOUND | Order <orderId> not found | No aggregated order has that id. | Check the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/orders`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `orderId` | path | string | yes | Aggregated order id. |

### Request body

The new status.

```json
{
  "status": "shipped",
  "trackingNumber": "1Z999AA10123456784"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The updated order |
| `400` | Order <orderId> not found — No aggregated order has that id. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/orders/stats/summary

**Get order statistics**

`operationId: OrderAggregationController_getStats`

Order counts and value by channel over a date range.

#### Signature

```http
GET /sales-channel/orders/stats/summary (fromDate?: string, toDate?: string) -> Order statistics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/summary`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Order statistics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/pricing/rules

**List pricing rules**

`operationId: PricingController_getPricingRules`

Rules that derive a channel price from the base price — marketplace fee uplifts, per-channel margins, floors. Optionally filtered to one channel.

#### Signature

```http
GET /sales-channel/pricing/rules (channel?: string) -> Pricing rules
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/rules`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channel` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Pricing rules |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/pricing/rules

**Save a pricing rule**

`operationId: PricingController_savePricingRule`

Creates or replaces a pricing rule. Rules change what customers are charged on live marketplaces the next time prices sync — calculate first and check the numbers before syncing.

#### Signature

```http
POST /sales-channel/pricing/rules (body) -> The saved rule
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Affects live selling prices once synced.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/calculate/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The rule.

```json
{
  "name": "Amazon fee uplift",
  "channel": "amazon",
  "adjustmentType": "percentage",
  "adjustmentValue": 15,
  "minMargin": 10
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The saved rule |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/pricing/rules/{ruleId}

**Get a pricing rule**

`operationId: PricingController_getPricingRule`

Fetches one pricing rule.

#### Signature

```http
GET /sales-channel/pricing/rules/{ruleId} (ruleId: string) -> The rule
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /sales-channel/pricing/rules/{ruleId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `ruleId` | path | string | yes | Rule id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The rule |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /sales-channel/pricing/rules/{ruleId}

**Delete a pricing rule**

`operationId: PricingController_deletePricingRule`

Removes a pricing rule. Prices already pushed to channels stay as they are until the next sync recalculates them without the rule — which can drop a marketplace price below the margin the rule was protecting.

#### Signature

```http
DELETE /sales-channel/pricing/rules/{ruleId} (ruleId: string) -> The delete result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Re-sync deliberately after deleting a rule.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/sync/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `ruleId` | path | string | yes | Rule id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The delete result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/pricing/calculate/{channelId}

**Calculate a channel price**

`operationId: PricingController_calculateChannelPrice`

Runs the pricing rules for one channel against a product and returns the resulting price with its breakdown. Pure calculation — nothing is saved or pushed.

#### Signature

```http
POST /sales-channel/pricing/calculate/{channelId} (channelId: string, body) -> The calculated price and breakdown
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/calculate/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The product to price.

```json
{
  "sku": "COLA-330",
  "price": 1.99,
  "cost": 0.8
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The calculated price and breakdown |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/pricing/calculate/all

**Calculate prices for every channel**

`operationId: PricingController_calculateAllChannelPrices`

Prices one product for all configured channels side by side — the preview to check before a price sync.

#### Signature

```http
POST /sales-channel/pricing/calculate/all (body) -> Per-channel prices
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/sync/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The product to price.

```json
{
  "sku": "COLA-330",
  "price": 1.99,
  "cost": 0.8
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-channel prices |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/pricing/sync/{channelId}

**Push prices to a channel**

`operationId: PricingController_syncPricesToChannel`

Recalculates and pushes prices to a channel. Omit `skus` and the **whole catalogue** is repriced on that marketplace — run `calculate/all` on a sample first.

#### Signature

```http
POST /sales-channel/pricing/sync/{channelId} (channelId: string, body) -> The sync result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- An empty body reprices the entire catalogue on that channel.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/calculate/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

Optional SKU list; omit for the whole catalogue.

```json
{
  "skus": [
    "COLA-330",
    "COLA-500"
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The sync result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/pricing/history/{sku}

**Get price history for a SKU**

`operationId: PricingController_getPriceHistory`

What a SKU has been priced at over time, optionally on one channel — the record for answering why a customer was charged what they were.

#### Signature

```http
GET /sales-channel/pricing/history/{sku} (sku: string, channel?: string, limit?: integer) -> Price history, newest first
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/pricing/compare/{sku}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |
| `channel` | query | string | — |  |
| `limit` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Price history, newest first |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/pricing/competitor

**Record a competitor price**

`operationId: PricingController_saveCompetitorPrice`

Stores an observed competitor price for a SKU. Feeds the comparison view and any repricing rules that key off competitor data — it is an observation, so record where it came from.

#### Signature

```http
POST /sales-channel/pricing/competitor (body) -> The recorded price
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/pricing/competitor/{sku}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The observation.

```json
{
  "sku": "COLA-330",
  "competitor": "BigMart",
  "price": 1.79,
  "url": "https://bigmart.example.com/cola-330"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The recorded price |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/pricing/competitor/{sku}

**Get competitor prices for a SKU**

`operationId: PricingController_getCompetitorPrices`

Recorded competitor prices for one SKU. Each carries its observation time — treat older entries as stale rather than current market truth.

#### Signature

```http
GET /sales-channel/pricing/competitor/{sku} (sku: string) -> Competitor prices
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/pricing/competitor`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Competitor prices |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/pricing/compare/{sku}

**Compare a SKU's prices**

`operationId: PricingController_getPriceComparison`

The org's price on each channel alongside recorded competitor prices — the one view for deciding whether a SKU is mispriced.

#### Signature

```http
GET /sales-channel/pricing/compare/{sku} (sku: string) -> The comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/pricing/history/{sku}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/analytics/metrics/sync/{channelId}

**Sync sales metrics from a channel**

`operationId: ChannelAnalyticsController_syncSalesMetrics`

Pulls the channel's own sales figures into the analytics store, so channel reporting reflects marketplace-side numbers rather than only locally aggregated orders.

#### Signature

```http
POST /sales-channel/analytics/metrics/sync/{channelId} (channelId: string) -> The sync result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/metrics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The sync result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/analytics/metrics/{channelId}

**Record sales metrics**

`operationId: ChannelAnalyticsController_recordSalesMetrics`

Writes sales metrics for a channel directly — for channels with no metrics API, or for back-filling. Manually written figures sit alongside synced ones and are not distinguished in reports.

#### Signature

```http
POST /sales-channel/analytics/metrics/{channelId} (channelId: string, body) -> The stored metrics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /sales-channel/analytics/metrics/sync/{channelId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The metrics.

```json
{
  "revenue": 12400,
  "orders": 320,
  "units": 890
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The stored metrics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/analytics/metrics

**Get sales metrics**

`operationId: ChannelAnalyticsController_getSalesMetrics`

Sales metrics over a date range, optionally for one channel.

#### Signature

```http
GET /sales-channel/analytics/metrics (channel?: string, fromDate?: string, toDate?: string) -> Metrics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/summary`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channel` | query | string | — |  |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Metrics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/analytics/products/{sku}/{channelId}

**Record product performance**

`operationId: ChannelAnalyticsController_recordProductPerformance`

Writes performance metrics for one SKU on one channel — views, conversion, units.

#### Signature

```http
POST /sales-channel/analytics/products/{sku}/{channelId} (sku: string, channelId: string, body) -> The stored metrics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/products`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | path | string | yes | Product SKU. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The metrics.

```json
{
  "views": 4200,
  "unitsSold": 118,
  "conversionRate": 2.8
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The stored metrics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/analytics/products

**Get product performance**

`operationId: ChannelAnalyticsController_getProductPerformance`

Per-product performance across channels — which SKUs sell where, and which listings get traffic without converting.

#### Signature

```http
GET /sales-channel/analytics/products (sku?: string, channel?: string, fromDate?: string, toDate?: string) -> Product performance
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/compare`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | query | string | — |  |
| `channel` | query | string | — |  |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Product performance |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/analytics/summary

**Get an analytics summary**

`operationId: ChannelAnalyticsController_getChannelSummary`

Headline figures across all channels for a date range.

#### Signature

```http
GET /sales-channel/analytics/summary (fromDate?: string, toDate?: string) -> The summary
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/dashboard`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The summary |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/analytics/dashboard

**Get the channel dashboard**

`operationId: ChannelAnalyticsController_getDashboardMetrics`

The composed dashboard payload — summary, per-channel breakdown and top products in one response, so a dashboard renders from a single call.

#### Signature

```http
GET /sales-channel/analytics/dashboard (fromDate?: string, toDate?: string) -> The dashboard payload
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/summary`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The dashboard payload |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/analytics/compare

**Compare channels**

`operationId: ChannelAnalyticsController_getChannelComparison`

Puts named channels side by side over the same date range — the read for deciding where a product actually earns its margin.

#### Signature

```http
GET /sales-channel/analytics/compare (channels?: string, fromDate?: string, toDate?: string) -> The comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/analytics/dashboard`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channels` | query | string | yes | Comma-separated channel ids. |
| `fromDate` | query | string | — | ISO date, inclusive. |
| `toDate` | query | string | — | ISO date, inclusive. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/optimization/analyze/{channelId}

**Analyse a listing**

`operationId: ListingOptimizationController_analyzeProduct`

Scores one product's listing for a channel and returns improvement suggestions — title length, missing attributes, image count, keyword coverage. Analysis only; nothing is changed until a suggestion is applied.

#### Signature

```http
POST /sales-channel/optimization/analyze/{channelId} (channelId: string, body) -> Score and suggestions
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/optimization/suggestions`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Request body

The product to analyse.

```json
{
  "sku": "COLA-330",
  "title": "Cola 330ml",
  "description": "Refreshing cola."
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Score and suggestions |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /sales-channel/optimization/analyze/{channelId}/bulk

**Analyse the whole catalogue**

`operationId: ListingOptimizationController_bulkAnalyze`

Runs listing analysis across every product for a channel and stores the scores and suggestions. Catalogue-wide, so it can run for a while on a large catalogue.

#### Signature

```http
POST /sales-channel/optimization/analyze/{channelId}/bulk (channelId: string) -> The analysis result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | UNKNOWN_CHANNEL | Unknown channel: <channelId> | The channel id is not one the platform supports. | List supported channels with `GET /sales-channel/channels`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/optimization/scores`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `channelId` | path | string | yes | Channel identifier, e.g. `amazon`, `ebay`, `etsy`, `walmart`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The analysis result |
| `400` | Unknown channel: <channelId> — The channel id is not one the platform supports. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/optimization/scores

**List listing scores**

`operationId: ListingOptimizationController_getListingScores`

Stored listing-quality scores, filterable by SKU or channel — where to focus listing work.

#### Signature

```http
GET /sales-channel/optimization/scores (sku?: string, channel?: string) -> Scores
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/optimization/summary`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | query | string | — |  |
| `channel` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Scores |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/optimization/suggestions

**List optimisation suggestions**

`operationId: ListingOptimizationController_getSuggestions`

Individual suggestions from listing analysis, filterable by SKU, channel, priority and whether they have already been applied. Filter `applied=false` for the outstanding work.

#### Signature

```http
GET /sales-channel/optimization/suggestions (sku?: string, channel?: string, priority?: string, applied?: boolean) -> Suggestions
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PUT /sales-channel/optimization/suggestions/{suggestionId}/apply`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sku` | query | string | — |  |
| `channel` | query | string | — |  |
| `priority` | query | string | — |  |
| `applied` | query | boolean | — | Filter by whether the suggestion has been applied. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Suggestions |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PUT /sales-channel/optimization/suggestions/{suggestionId}/apply

**Apply an optimisation suggestion**

`operationId: ListingOptimizationController_markSuggestionApplied`

Applies a suggestion to the listing and marks it applied. This edits real listing content — review the suggestion before applying, particularly anything that rewrites a title or description.

#### Signature

```http
PUT /sales-channel/optimization/suggestions/{suggestionId}/apply (suggestionId: string) -> The applied suggestion
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Modifies listing content.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/optimization/suggestions`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `suggestionId` | path | string | yes | Suggestion id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The applied suggestion |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /sales-channel/optimization/summary

**Get an optimisation summary**

`operationId: ListingOptimizationController_getOptimizationSummary`

Aggregate listing health — average scores and outstanding suggestion counts by channel.

#### Signature

```http
GET /sales-channel/optimization/summary () -> The summary
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /sales-channel/optimization/scores`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The summary |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

