Decoration Partner Orders API (GraphQL)
This guide is for decoration partners that pull work from Stylux over GraphQL. The typical integration:
- Authenticate with a partner scoped signed API key
- Pull partner fulfillments assigned to you (optionally via
orders-> nestedpartnerFulfillments) - For each partner fulfillment, treat every line item on it as something you are responsible for decorating and fulfilling
- Respect hold statuses; when ready to ship, update the partner fulfillment with status and tracking
For request signing (headers, canonical string, working example), see Signed API Authentication.
Endpoint
Send a POST to /graphql.
| Environment | URL |
|---|---|
| Production | https://api.stylux.io/graphql |
| Staging | https://api-stg.stylux.io/graphql |
| Development | https://api-dev.stylux.io/graphql |
Use Content-Type: application/json and Accept: application/json.
Authentication
Server integrations use HMAC signed API keys. Follow Signed API Authentication for every request.
Decoration partners will use partner scoped API keys. Those keys only return partner fulfillments assigned to that partner; you will not see partner fulfillments assigned to other partners. Nested order.partnerFulfillments is filtered the same way; only your assignments appear.
Your signed API key must include at least:
read:ordersfororder/ordersread:partnersforpartnerFulfillment/partnerFulfillments/partnerLocationsupdate:ordersforupdatePartnerFulfillmentread:productsif you select nestedproductfields on line itemsread:merchantsif you select nestedmerchantfields
Domain model
Order
shippingAddress / customer / merchant (context for the shipment)
partnerFulfillments[] (only partner fulfillments assigned to you)
partnerLocation
lineItems[] (items you must fulfill on this partner fulfillment)
status, holdReason, abortReason
trackingNumber, trackingUrl, shippingCompany
giftNote / giftBoxes (D2C extras when present)
A partner fulfillment is work assigned to your partner at a partner location. Each line item on that partner fulfillment is work you own; decorate it and fulfill it as part of that partner fulfillment. An order may also have line items or partner fulfillments for other partners; with a partner scoped key those do not appear in your results.
Recommended approach: query partnerFulfillments (and nest order for shipping / merchant context). You can also start from orders with withPartnerFulfillments: true and read nested partnerFulfillments; both return the same assigned partner fulfillments.
Paginated fields use Relay style connections: nodes, edges { cursor node }, and pageInfo { hasNextPage hasPreviousPage startCursor endCursor }. Every paginated field requires first or last (max 250). Nested lineItems and partnerFulfillments need their own first/last.
Pull partner fulfillments (recommended)
query PartnerFulfillmentsPage(
$first: Int!
$after: String
$filter: GetManyPartnerFulfillmentsFilter
) {
partnerFulfillments(first: $first, after: $after, filter: $filter) {
pageInfo {
hasNextPage
endCursor
}
nodes {
id
shortId
status
holdReason
abortReason
shippingCompany
trackingNumber
trackingUrl
createdDate
updatedDate
partnerLocation {
id
address1
city
provinceCode
countryCode
zip
partner {
id
partnerName
}
}
giftNote {
lineItemId
message
}
giftBoxes {
lineItemId
}
lineItems(first: 50) {
nodes {
id
lineItemId
quantity
price
sku
productId
productName
properties
product {
id
sku
title
productId
}
}
}
order {
id
orderId
orderNumber
status
fulfillmentStatus
createdDate
notes
shippingAddress {
firstName
lastName
address1
address2
city
province
provinceCode
country
countryCode
zip
}
customer {
firstName
lastName
email
}
merchant {
id
merchantName
}
}
}
}
}Variables example:
{
"first": 50,
"after": null,
"filter": {
"statuses": ["PENDING", "AUTO_HOLD", "MANUAL_HOLD"]
}
}Walk pages while pageInfo.hasNextPage is true; pass pageInfo.endCursor as after on the next request. Sign each request separately.
Partner scoping is applied by your API key. You do not need to filter by partner id to hide other partners' work; results are already limited to fulfillments assigned to you. Optional filters narrow within that set:
| Filter | Notes |
|---|---|
statuses | One or more PartnerFulfillmentStatusEnum (for example open work) |
orderIds | Merchant / external order ids |
partnerLocationIds | Limit to specific locations you operate |
partnerIds | Usually unnecessary with a partner scoped key; reserved for credentials that span multiple partners |
Fetch one partner fulfillment by Stylux UUID:
query PartnerFulfillmentById($id: UUID!) {
partnerFulfillment(id: $id) {
id
shortId
status
order {
id
orderId
}
lineItems(first: 50) {
nodes {
id
lineItemId
quantity
sku
}
}
}
}Pull via orders
Use orders when you prefer paging by order (for example filter by merchant order id, then read nested partner fulfillments). Nested partnerFulfillments still only include partner fulfillments assigned to your partner.
query OrdersForPartner(
$first: Int!
$after: String
$filter: GetManyOrdersFilter
) {
orders(first: $first, after: $after, filter: $filter) {
pageInfo {
hasNextPage
endCursor
}
nodes {
id
orderId
orderNumber
status
fulfillmentStatus
shippingAddress {
firstName
lastName
address1
city
provinceCode
countryCode
zip
}
partnerFulfillments(first: 20) {
nodes {
id
shortId
status
partnerLocation {
id
}
lineItems(first: 50) {
nodes {
id
lineItemId
quantity
sku
}
}
}
}
}
}
}Useful GetManyOrdersFilter fields for partners:
| Filter | Notes |
|---|---|
withPartnerFulfillments | Prefer true so you only page orders that have work assigned to a partner |
partnerFulfillmentStatuses | Orders that have one of your fulfillments in these statuses |
partnerLocationIds | Orders with your fulfillments at these locations |
statuses / fulfillmentStatuses | Order-level status filters |
merchantIds | When you fulfill for more than one merchant |
orderTextSearchQuery | Search across order identifiers / related text |
Single order:
query OrderById($id: UUID!) {
order(id: $id) {
id
orderId
orderNumber
status
partnerFulfillments(first: 20) {
nodes {
id
shortId
status
}
}
}
}Partner fulfillment fields
| Field | Notes |
|---|---|
id | Stylux partner fulfillment UUID |
shortId | Short human-readable partner fulfillment id |
status | See state machine below |
holdReason / abortReason | Required when entering MANUAL_HOLD / ABORTED |
partnerLocation | Location (and nested partner) assigned to the partner fulfillment |
lineItems | Items you are responsible for fulfilling on this partner fulfillment |
order | Parent order (shipping address, merchant, identifiers) |
shippingCompany | Carrier name |
trackingNumber / trackingUrl | Tracking number and URL |
giftNote | Gift message for this partner fulfillment when present (D2C) |
giftBoxes | Gift box line items joined to this partner fulfillment |
createdDate / updatedDate | ISO 8601 timestamps |
giftNote.lineItemId and giftBoxes[].lineItemId match partnerFulfillment.lineItems.nodes.id (the Stylux line item UUID), not the merchant lineItemId.
Integration expectations
Decoration partner integrations are responsible for processing assigned work and reporting ship with tracking. Stylux owns later carrier progress updates.
Holds (AUTO_HOLD / MANUAL_HOLD)
AUTO_HOLD / MANUAL_HOLD)Respect hold statuses. Do not decorate or ship a partner fulfillment while it is AUTO_HOLD or MANUAL_HOLD.
In your system, either:
- Ignore held partner fulfillments until Stylux moves them out of hold, or
- Import them as held so operators see the work but cannot proceed
Only proceed (produce, pack, or ship) after the status on the Stylux side changes to a state that is not a hold, such as PENDING. Poll or use Order Update Webhooks to learn when a hold clears.
Shipping and tracking
When you ship, update the partner fulfillment with status IN_PROGRESS and tracking (shippingCompany, trackingNumber, and trackingUrl when available). Tracking is required for decoration partner integrations; this is how Stylux learns the shipment left your facility.
When tracking is first reported, status must be IN_PROGRESS (the same status Stylux uses when tracking is first synced for built in shipping integrations). Do not jump ahead to later carrier statuses such as IN_TRANSIT, OUT_FOR_DELIVERY, or DELIVERED in that update.
You are not required to keep status in sync as the carrier progresses the shipment. Stylux updates later states automatically from tracking (for example IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERED). After you report IN_PROGRESS with tracking, leave subsequent carrier transitions to Stylux.
Update a partner fulfillment
mutation UpdatePartnerFulfillment($input: UpdatePartnerFulfillmentInput!) {
updatePartnerFulfillment(input: $input) {
id
shortId
status
holdReason
abortReason
shippingCompany
trackingNumber
trackingUrl
updatedDate
}
}UpdatePartnerFulfillmentInput:
| Field | Notes |
|---|---|
partnerFulfillmentId | Required. Stylux UUID |
status | Optional. Must be a valid transition from the current status |
shippingCompany | Carrier name; include when shipping |
trackingNumber | Tracking number; required when you ship |
trackingUrl | Tracking URL when available |
holdReason | Required when moving to MANUAL_HOLD. Incompatible with abortReason |
abortReason | Required when moving to ABORTED. Incompatible with holdReason |
lineItems | Never required for decoration partners; omit this field |
Ship with tracking example
{
"input": {
"partnerFulfillmentId": "21f7ca12-5fd7-4769-9d99-563a7d38fef3",
"status": "IN_PROGRESS",
"shippingCompany": "USPS",
"trackingNumber": "9400111899223344556677",
"trackingUrl": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223344556677"
}
}Hold example
{
"input": {
"partnerFulfillmentId": "21f7ca12-5fd7-4769-9d99-563a7d38fef3",
"status": "MANUAL_HOLD",
"holdReason": "INVENTORY_OUT_OF_STOCK"
}
}Read lineItems on each partner fulfillment for your work queue. Changing membership with lineItems on updatePartnerFulfillment is never required for decoration partners; omit it.
State machine
Statuses:
AUTO_HOLD, MANUAL_HOLD, PENDING, IN_PROGRESS, IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERY_ATTEMPTED, DELIVERED, DELIVERY_FAILED, RETURN_TO_SENDER, ABORTED
Allowed transitions:
| From | To |
|---|---|
AUTO_HOLD | ABORTED, MANUAL_HOLD, PENDING |
MANUAL_HOLD | ABORTED, PENDING |
PENDING | IN_PROGRESS |
IN_PROGRESS | DELIVERED, DELIVERY_ATTEMPTED, DELIVERY_FAILED, IN_TRANSIT, OUT_FOR_DELIVERY, RETURN_TO_SENDER |
IN_TRANSIT | DELIVERED, DELIVERY_ATTEMPTED, DELIVERY_FAILED, OUT_FOR_DELIVERY, RETURN_TO_SENDER |
OUT_FOR_DELIVERY | DELIVERED, DELIVERY_ATTEMPTED, DELIVERY_FAILED, IN_TRANSIT, RETURN_TO_SENDER |
DELIVERY_ATTEMPTED | ABORTED, DELIVERED, DELIVERY_FAILED, IN_TRANSIT, OUT_FOR_DELIVERY, RETURN_TO_SENDER |
DELIVERY_FAILED | ABORTED, RETURN_TO_SENDER |
RETURN_TO_SENDER | ABORTED |
Rules:
MANUAL_HOLDrequiresholdReasonABORTEDrequiresabortReason- Invalid transitions return GraphQL
UNPROCESSABLE_ENTITY(HTTP 422)
For decoration partners, the important transitions are usually hold handling (wait for Stylux to move AUTO_HOLD / MANUAL_HOLD -> PENDING) and ship with tracking (PENDING -> IN_PROGRESS plus tracking fields). Later carrier statuses are updated by Stylux.
Hold and abort reason enums
PartnerFulfillmentHoldReasonEnum: CUSTOMER_REQUEST, INCORRECT_ADDRESS, INVENTORY_OUT_OF_STOCK, MERCHANT_REQUEST, OTHER
PartnerFulfillmentAbortReasonEnum: CUSTOMER_CHANGED_OR_CANCELED_ORDER, HIGH_FRAUD_RISK, INTERNATIONAL_SHIPPING_ISSUE, MERCHANT_CHANGED_OR_CANCELED_ORDER, OTHER, STAFF_ERROR
Fulfilled vs unfulfilled
Treat these as unfulfilled for operational purposes: AUTO_HOLD, MANUAL_HOLD, PENDING, ABORTED.
Treat these as fulfilled (shipment side underway or complete): IN_PROGRESS, IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERY_ATTEMPTED, DELIVERED, DELIVERY_FAILED, RETURN_TO_SENDER.
Partner locations
List locations your credentials can access:
query PartnerLocations($first: Int!) {
partnerLocations(first: $first) {
nodes {
id
address1
city
provinceCode
countryCode
zip
partner {
id
partnerName
}
}
}
}Push updates via webhooks
If you need push notifications when orders or partner fulfillments change, register an ORDER_UPDATE webhook and validate inbound delivery signatures. That flow (including the partner fulfillments shape on the order payload) is documented in Order Update Webhooks. Registration and payload fetch calls use the same signed API authentication as GraphQL.
Updated 8 days ago
