Decoration Partner Orders API (GraphQL)

This guide is for decoration partners that pull work from Stylux over GraphQL. The typical integration:

  1. Authenticate with a partner scoped signed API key
  2. Pull partner fulfillments assigned to you (optionally via orders -> nested partnerFulfillments)
  3. For each partner fulfillment, treat every line item on it as something you are responsible for decorating and fulfilling
  4. 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.

EnvironmentURL
Productionhttps://api.stylux.io/graphql
Staginghttps://api-stg.stylux.io/graphql
Developmenthttps://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:orders for order / orders
  • read:partners for partnerFulfillment / partnerFulfillments / partnerLocations
  • update:orders for updatePartnerFulfillment
  • read:products if you select nested product fields on line items
  • read:merchants if you select nested merchant fields

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:

FilterNotes
statusesOne or more PartnerFulfillmentStatusEnum (for example open work)
orderIdsMerchant / external order ids
partnerLocationIdsLimit to specific locations you operate
partnerIdsUsually 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:

FilterNotes
withPartnerFulfillmentsPrefer true so you only page orders that have work assigned to a partner
partnerFulfillmentStatusesOrders that have one of your fulfillments in these statuses
partnerLocationIdsOrders with your fulfillments at these locations
statuses / fulfillmentStatusesOrder-level status filters
merchantIdsWhen you fulfill for more than one merchant
orderTextSearchQuerySearch 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

FieldNotes
idStylux partner fulfillment UUID
shortIdShort human-readable partner fulfillment id
statusSee state machine below
holdReason / abortReasonRequired when entering MANUAL_HOLD / ABORTED
partnerLocationLocation (and nested partner) assigned to the partner fulfillment
lineItemsItems you are responsible for fulfilling on this partner fulfillment
orderParent order (shipping address, merchant, identifiers)
shippingCompanyCarrier name
trackingNumber / trackingUrlTracking number and URL
giftNoteGift message for this partner fulfillment when present (D2C)
giftBoxesGift box line items joined to this partner fulfillment
createdDate / updatedDateISO 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)

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:

FieldNotes
partnerFulfillmentIdRequired. Stylux UUID
statusOptional. Must be a valid transition from the current status
shippingCompanyCarrier name; include when shipping
trackingNumberTracking number; required when you ship
trackingUrlTracking URL when available
holdReasonRequired when moving to MANUAL_HOLD. Incompatible with abortReason
abortReasonRequired when moving to ABORTED. Incompatible with holdReason
lineItemsNever 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:

FromTo
AUTO_HOLDABORTED, MANUAL_HOLD, PENDING
MANUAL_HOLDABORTED, PENDING
PENDINGIN_PROGRESS
IN_PROGRESSDELIVERED, DELIVERY_ATTEMPTED, DELIVERY_FAILED, IN_TRANSIT, OUT_FOR_DELIVERY, RETURN_TO_SENDER
IN_TRANSITDELIVERED, DELIVERY_ATTEMPTED, DELIVERY_FAILED, OUT_FOR_DELIVERY, RETURN_TO_SENDER
OUT_FOR_DELIVERYDELIVERED, DELIVERY_ATTEMPTED, DELIVERY_FAILED, IN_TRANSIT, RETURN_TO_SENDER
DELIVERY_ATTEMPTEDABORTED, DELIVERED, DELIVERY_FAILED, IN_TRANSIT, OUT_FOR_DELIVERY, RETURN_TO_SENDER
DELIVERY_FAILEDABORTED, RETURN_TO_SENDER
RETURN_TO_SENDERABORTED

Rules:

  • MANUAL_HOLD requires holdReason
  • ABORTED requires abortReason
  • 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.


Did this page help you?