Appearance
Accounts
7 reads, no writes, on train 2026-11. Scopes: accounts:read.
| Operation | Method | Scope | Path |
|---|---|---|---|
| List edi documents | GET | accounts:read | /api/v1/wholesale/edi/documents |
| Every trading account | GET | accounts:read | /api/v1/wholesale/retailers |
| The brand's contacts at one account | GET | accounts:read | /api/v1/wholesale/retailers/{partner_id}/contacts |
| One account's stock position | GET | accounts:read | /api/v1/wholesale/retailers/{partner_id}/overview |
| One account's products | GET | accounts:read | /api/v1/wholesale/retailers/{partner_id}/products |
| The values and ranges the account products table can be filtered on | GET | accounts:read | /api/v1/wholesale/retailers/{partner_id}/products/filters |
| What this account should be sent next | GET | accounts:read | /api/v1/wholesale/retailers/{partner_id}/replenishment-recommendations |
List edi documents
GET /api/v1/wholesale/edi/documents
Scopes: accounts:read
Every EDI document this organisation has exchanged with its accounts: purchase orders (850) in, acknowledgements (855), shipping notices (856) and invoices (810) out, and the inventory (846) and sell-out (852) reports that arrive on the same connection. Each row says which account it belongs to, which order it became or answered, what state it reached, and the sentence behind that state where it has one, so a file that was refused or an acknowledgement a network would not take is readable here rather than in the network's own console. network says which lane a document came through, and it is also the filter: this log holds every lane an order can arrive on, so ask for network=sps_commerce for the EDI lane alone. Read only: documents are made by the acts that make them, never posted here.
| Optional | In | What it is |
|---|---|---|
trading_partner_id | query | One account's documents only. |
document_type | query | One kind of document only, by its X12 number. |
direction | query | Documents that arrived (inbound) or that Tightly sent (outbound). |
state | query | Documents in this state only. |
network | query | The lane the document came through. |
offset | query | Rows to skip before the page starts. |
limit | query | Rows on the page. |
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/edi/documents" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"filtered_max_size": 2,
"max_size": 50,
"offset": 0,
"rows": [
{
"account": {
"name": "Coastline Department Stores",
"trading_partner_id": "tp_coastline"
},
"control_number": "CDS-90114",
"direction": "outbound",
"document_id": 42,
"document_type": "855",
"file_path": "in/855-CDS-90114.xml",
"network": "sps_commerce",
"order": {
"name": "ORD-00000412",
"order_id": "ord_01JQ8ZK7C4N2R9V6T3M0X5A1BD"
},
"received_at": null,
"sent_at": "2026-09-05T17:30:00+00:00",
"sentence": null,
"state": "sent"
},
{
"account": {
"name": "Coastline Department Stores",
"trading_partner_id": "tp_coastline"
},
"control_number": "CDS-90114",
"direction": "inbound",
"document_id": 41,
"document_type": "850",
"file_path": "out/PO/PO584615-1-v7.7-BulkImport.xml",
"network": "sps_commerce",
"order": {
"name": "ORD-00000412",
"order_id": "ord_01JQ8ZK7C4N2R9V6T3M0X5A1BD"
…
}
}
]
}
}What it refuses
- 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludes: Accounts is sold with Tightly Connect on Essentials+ and this organisation's plan does not include it;scope_missing: the key does not hold Accounts;account_mismatch: a key issued to one account named another. - 429
Every trading account
GET /api/v1/wholesale/retailers
Scopes: accounts:read
Every trading account, with the identity a sell-out write and an order-book read both name an account from: its id, the account's own buyer reference, its name, its sales channel, transit time, when its data last synced, its standing terms (tier, fill-rate target, cancellation term and notice days), the next estimated order date, the trading figures read off its own reports, and portal_seats, the account's side of the buyer's portal: how many buyers hold a live seat, how many invitations are still unopened, and when any of them last opened it.
| Optional | In | What it is |
|---|---|---|
retailer_ids | query | Restrict to these accounts, comma-separated. |
variant_id | query | Only accounts that carry this variant, which accounts stock it. |
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/retailers" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"retailers": [
{
"account_tier": 1,
"buyer_id": "SLF-4471",
"cancellation_notice_days": 30,
"cancellation_term": "window",
"cancellation_term_note": null,
"fill_rate_target_pct": 97,
"id": "tp_00417",
"last_data_synced_at": "2026-09-03T02:14:00+00:00",
"name": "Selfridges",
"next_estimated_sale_order_date": "2026-09-21",
"next_estimated_sale_order_in_weeks": 2,
"portal_seats": {
"accepted": 2,
"invited": 1,
"last_opened_at": "2026-09-03T16:40:00+00:00"
},
"sales_channel_id": "61240442",
"sales_velocity_per_week": 184.5,
"sell_through_rate": 0.86,
"total_skus": 412,
"transit_time_days": 4
}
]
},
"message": {
"desc": "OK",
"service": "wholesale",
"severity": "INFO"
}
}What it refuses
- 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludeswhen Accounts is sold with Essentials+ and this organisation's plan does not include it;scope_missingwhen the key does not hold Accounts;organization_mismatchwhen the path names an organisation that is not the key's;ip_not_allowedwhen the caller's address is outside the key's allowlist. - 429
The brand's contacts at one account
GET /api/v1/wholesale/retailers/{partner_id}/contacts
Scopes: accounts:read
The brand's contacts at one account and the email domains that make a thread theirs: the account's name, its recorded domains, and one entry per contact with name, email, phone, role, department, contact type, last interaction date and whether they are the main contact.
| Required | In | What it is |
|---|---|---|
partner_id | path | The account. An id, never a name. Duplicate account names are ordinary in apparel. |
| Optional | In | What it is |
|---|---|---|
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/retailers/<partner_id>/contacts" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"contacts": [
{
"contact_type": "buyer",
"department": "Womenswear",
"email": "morgan@retailer.example",
"id": 4471,
"is_main": true,
"last_interaction_date": "2026-08-28",
"name": "Morgan Example",
"phone": null,
"role": "Buyer"
}
],
"domains": [
"retailer.example"
],
"domains_reason": null,
"name": "Selfridges",
"trading_partner_id": "tp_00417"
},
"message": {
"desc": "OK",
"service": "wholesale",
"severity": "INFO"
}
}What it refuses
- 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludeswhen Accounts is sold with Essentials+ and this organisation's plan does not include it;scope_missingwhen the key does not hold Accounts;organization_mismatchwhen the path names an organisation that is not the key's;ip_not_allowedwhen the caller's address is outside the key's allowlist;account_mismatchwhen a key issued to one account names another in the path, and the sentence names both accounts. - 429
One account's stock position
GET /api/v1/wholesale/retailers/{partner_id}/overview
Scopes: accounts:read
One account's stock position: the estimated stock on hand for the current week, the timeline behind it, the forward projection, and the last and next delivery either side of today.
| Required | In | What it is |
|---|---|---|
partner_id | path | The account. An id, never a name. Duplicate account names are ordinary in apparel. |
| Optional | In | What it is |
|---|---|---|
variant_id | query | Scope the overview to one variant. |
product_id | query | Scope the overview to every variant of one product. |
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/retailers/<partner_id>/overview" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"current_stock": {
"end_date": "2026-09-06",
"estimated_stock_on_hand": 302,
"start_date": "2026-08-31"
},
"forecasted_stock_timeline": [
{
"date": "2026-09-07",
"on_hand": 218
}
],
"last_delivery": {
"date": "2026-08-11",
"quantity": 600
},
"next_delivery": {
"date": "2026-09-22",
"quantity": 800
},
"replenishment_date": null,
"replenishment_qty": null,
"stock_timeline": [
{
"date": "2026-08-24",
"on_hand": 411
},
{
"date": "2026-08-31",
"on_hand": 302
}
]
},
"message": {
"desc": "OK",
"service": "wholesale",
"severity": "INFO"
}
}What it refuses
- 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludeswhen Accounts is sold with Essentials+ and this organisation's plan does not include it;scope_missingwhen the key does not hold Accounts;organization_mismatchwhen the path names an organisation that is not the key's;ip_not_allowedwhen the caller's address is outside the key's allowlist;account_mismatchwhen a key issued to one account names another in the path, and the sentence names both accounts. - 429
One account's products
GET /api/v1/wholesale/retailers/{partner_id}/products
Scopes: accounts:read
A page of one account's products: the brand's unit cost and both prices beside the account's own on-hand quantity, incoming units, weeks of cover and sell-through rate, with the variant's identity, supplier and velocity figures.
| Required | In | What it is |
|---|---|---|
partner_id | path | The account. An id, never a name. Duplicate account names are ordinary in apparel. |
| Optional | In | What it is |
|---|---|---|
limit | query | Rows per page. |
offset | query | Rows to skip. |
search | query | Matches product title, variant title, SKU, product id or variant id. |
filter_args | query | A JSON array of {key, operation, value}. |
sort_args | query | Comma-separated columns; - for descending. |
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/retailers/<partner_id>/products" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"filtered_max_size": 412,
"offset": 0,
"rows": [
{
"category": "Knitwear",
"default_supplier_name": "Porto Knits",
"health": "caution",
"product_id": "4410092",
"product_image": "https://cdn.example.com/terry-crew.jpg",
"product_title": "Terry Crew",
"product_type": "Knitwear",
"production_type": "buy_only",
"retailer_incoming_units": 120,
"retailer_on_hand": 42,
"retailer_weeks_of_cover": 2,
"sales_velocity_30_days": 3.6,
"sales_velocity_7_days": 4.1,
"sales_velocity_90_days": 3.2,
"sell_in_price": 29.5,
"sell_out_price": 79,
"sell_out_velocity_per_week": 21,
"sell_through_rate": 0.86,
"sku": "TB-CREW-BLK-M",
"supplier_details": [],
"supplier_id": "sup_0031",
"unit_cost": 12.4,
"variant_id": "44100920011",
"variant_title": "Black / M"
}
],
"size": 1
},
"message": {
"desc": "OK",
"service": "wholesale",
"severity": "INFO"
}
}What it refuses
- 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludeswhen Accounts is sold with Essentials+ and this organisation's plan does not include it;scope_missingwhen the key does not hold Accounts;organization_mismatchwhen the path names an organisation that is not the key's;ip_not_allowedwhen the caller's address is outside the key's allowlist;account_mismatchwhen a key issued to one account names another in the path, and the sentence names both accounts. - 429
The values and ranges the account products table can be filtered on
GET /api/v1/wholesale/retailers/{partner_id}/products/filters
Scopes: accounts:read
The values and ranges the account products table can be filtered on: a flat map keyed by filter key, carrying the distinct categorical values this account's variants actually carry and a {min, max} pair for each numeric range.
| Required | In | What it is |
|---|---|---|
partner_id | path | The account. An id, never a name. Duplicate account names are ordinary in apparel. |
| Optional | In | What it is |
|---|---|---|
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/retailers/<partner_id>/products/filters" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"category": [
"Knitwear",
"Outerwear"
],
"production_type": [
"buy_only",
"manufacturable"
],
"retailer_incoming_units": {
"max": 2400,
"min": 0
},
"retailer_on_hand": {
"max": 1840,
"min": 0
},
"retailer_weeks_of_cover": {
"max": 41,
"min": 0
},
"sales_velocity": {
"max": 18.4,
"min": 0
},
"sell_in_price": {
"max": 190,
"min": 12
},
"sell_out_price": {
"max": 420,
"min": 29
},
"supplier": [
{
"supplier_id": "sup_0031",
"supplier_name": "Porto Knits"
}
]
…
}
}What it refuses
- 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludeswhen Accounts is sold with Essentials+ and this organisation's plan does not include it;scope_missingwhen the key does not hold Accounts;organization_mismatchwhen the path names an organisation that is not the key's;ip_not_allowedwhen the caller's address is outside the key's allowlist;account_mismatchwhen a key issued to one account names another in the path, and the sentence names both accounts. - 429
What this account should be sent next
GET /api/v1/wholesale/retailers/{partner_id}/replenishment-recommendations
Scopes: accounts:read
What this account should be sent next, highest composite score first: one row per variant with the recommended quantity, the impact level, the replenishment date, the destination location and the default supplier, and production_type saying which act follows, a basket for a bought item or a manufacturing order for a made one.
| Required | In | What it is |
|---|---|---|
partner_id | path | The account. An id, never a name. Duplicate account names are ordinary in apparel. |
| Optional | In | What it is |
|---|---|---|
limit | query | How many rows to return. Clamped to 1 to 100. |
Tightly-Version | header | The date train to answer on. |
bash
curl "https://api.app.tightly.io/api/v1/wholesale/retailers/<partner_id>/replenishment-recommendations" \
-H "Authorization: Bearer $TIGHTLY_API_KEY"What it answers
json
{
"data": {
"rows": [
{
"composite_score": 0.82,
"id": 90114,
"impact_level": "high",
"location_id": "loc_0004",
"location_name": "London DC",
"product_id": "4410092",
"product_image": "https://cdn.example.com/terry-crew.jpg",
"product_title": "Terry Crew",
"production_type": "buy_only",
"recommended_quantity": 240,
"replenishment_date": "2026-09-21",
"sku": "TB-CREW-BLK-M",
"supplier_id": "sup_0031",
"supplier_name": "Porto Knits",
"variant_id": "44100920011",
"variant_title": "Black / M"
}
]
},
"message": {
"desc": "OK",
"service": "wholesale",
"severity": "INFO"
}
}What it refuses
- 400
limitis not an integer. - 401
key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for. - 403
plan_excludes: "This organisation's plan does not include Tightly Connect. It is sold with Essentials+." The key may not reach this operation.plan_excludeswhen Accounts is sold with Essentials+ and this organisation's plan does not include it;scope_missingwhen the key does not hold Accounts;organization_mismatchwhen the path names an organisation that is not the key's;ip_not_allowedwhen the caller's address is outside the key's allowlist;account_mismatchwhen a key issued to one account names another in the path, and the sentence names both accounts. - 429