Docs
Firmly Agentic Commerce
Set theme to dark (⇧+D)

Set Fulfillment Type

POST https://api.firmly.work/api/v2/domains/{domain}/cart/shipments/fulfillment-type

Switch a shipment’s fulfillment type. Each shipment exposes the values you can set via its fulfillment_type_options array. The shipment is initialized with the merchant’s default after Set Shipping Info; call this endpoint only when the buyer wants a different option.

​​ Authentication

  • x-firmly-authorization (string, required) — Device access token from Browser Session

​​ Path Parameters

  • domain (string, required) — The merchant’s domain (e.g. staging.luma.gift).

​​ Request Body

  • shipment_id (string, required) — Target shipment identifier (from the cart’s shipments[].shipment_id).

  • fulfillment_type (string, required) — New fulfillment method. One of:

    • SHIP_TO_ADDRESS
    • SCHEDULED_DELIVERY
    • PICKUP_IN_STORE Must also be present in the target shipment’s fulfillment_type_options; otherwise the request returns 400 InvalidFulfillmentType.
  • location_id (string) — Store location identifier. Required when fulfillment_type is PICKUP_IN_STORE.

​​ Response

Returns the full cart — same schema as Get Cart. The target shipment’s fulfillment_type is updated (and, for PICKUP_IN_STORE, its selected_location); shipping_method_options are refreshed for the new type and cart totals are recalculated.

  • shipments (object[]) — The cart’s shipments. Each shipment has the shape below.

    Shipment
    • shipment_id (string, required) — Unique shipment identifier.
    • platform_shipment_id (string) — Merchant-side shipment identifier, when available.
    • line_item_ids (string[], required) — IDs of the line items grouped into this shipment.
    • fulfillment_type (object, required) — The selected fulfillment type.
    fulfillment_type
    • id (string, required) — One of SHIP_TO_ADDRESS, SCHEDULED_DELIVERY, PICKUP_IN_STORE.
    • name (string, required) — Display name.
    • description (string, required) — Description.
    • fulfillment_type_options (object[]) — Fulfillment types available for this shipment (same shape as fulfillment_type).
    • shipping_method_options (object[]) — Shipping methods available for the selected fulfillment type (same shape as shipping_method).
    • shipping_method (object) — The selected shipping method, when one is set.
    shipping_method
    • id (string, required) — Method identifier.
    • description (string, required) — Method description.
    • price (object) — Cost (Amount). Required unless hide_price is true.
    • hide_price (boolean) — When true, suppress the price in the UI.
    • message (string) — Optional merchant note about this method.
    • estimated_delivery (string) — Delivery estimate.
    • selected_location (object) — Pickup location — present for PICKUP_IN_STORE.
    selected_location
    • location_id (string, required) — Location identifier.
    • name (string, required) — Location name.
    • address (object, required) — Location address (same fields as a shipping address).
    • phone (string) — Location phone number.
    • operating_hours (object[]) — Per-day hours: { day, open_time, close_time, is_closed? }.
    • distance (object) — Distance from the buyer: { value, unit, formatted }.
    • pickup_options (object[]) — Available pickup dates/slots: { date, time_slots }.
    • selected_date (string) — Selected delivery date for SCHEDULED_DELIVERY (YYYY-MM-DD).
    • selected_time_slot (object) — Selected time slot for SCHEDULED_DELIVERY: { slot_id?, start_time, end_time, description?, price? }.
    • pickup_option (object) — Selected pickup option: { id, description, price? }.
    • notes (string) — Delivery notes for this shipment.

  • shipping_total (object) — Total shipping cost across all shipments (Amount).

  • tax_total (object) — Total tax (Amount).

  • total (object) — Grand total (Amount).

​​ Examples


curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/shipments/fulfillment-type \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"shipment_id": "8568658c-bee9-9666-4547-a545fe27391b",
"fulfillment_type": "SHIP_TO_ADDRESS"
}'

curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/shipments/fulfillment-type \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"shipment_id": "840b0477-b913-191a-2b4f-dc232a779f0c",
"fulfillment_type": "SCHEDULED_DELIVERY"
}'

curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/shipments/fulfillment-type \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"shipment_id": "8568658c-bee9-9666-4547-a545fe27391b",
"fulfillment_type": "PICKUP_IN_STORE",
"location_id": "store-downtown-001"
}'

The response below corresponds to the Switch to Standard Shipping example above — the target shipment’s fulfillment_type is now SHIP_TO_ADDRESS.

​​ Response Example


{
"cart_id": "a5600193-2c13-3356-d063-711da63b7cd7",
"platform_id": "example_commerce",
"shop_id": "staging.luma.gift",
"display_name": "Luma Store",
"cart_status": "active",
"line_items": [
{
"line_item_id": "c62279b9-3a72-0bbd-1377-be0033ad23dd",
"platform_line_item_id": "0",
"sku": "MH07-XS-Gray",
"description": "Hero Hoodie",
"base_sku": "MH07",
"quantity": 2,
"price": {
"currency": "USD",
"value": 49.99,
"number": 4999,
"symbol": "$"
},
"line_price": {
"currency": "USD",
"value": 99.98,
"number": 9998,
"symbol": "$"
},
"msrp": {
"currency": "USD",
"value": 49.99,
"number": 4999,
"symbol": "$"
},
"image": {
"url": "https://cdn.staging.luma.gift/hero-hoodie.jpg",
"alt": "Hero Hoodie",
"type": "default"
},
"requires_shipping": true
}
],
"shipments": [
{
"shipment_id": "8568658c-bee9-9666-4547-a545fe27391b",
"line_item_ids": ["c62279b9-3a72-0bbd-1377-be0033ad23dd"],
"fulfillment_type": {
"id": "SHIP_TO_ADDRESS",
"name": "Ship to Address",
"description": "Standard shipping to your address"
},
"fulfillment_type_options": [
{
"id": "SHIP_TO_ADDRESS",
"name": "Ship to Address",
"description": "Standard shipping to your address"
},
{
"id": "SCHEDULED_DELIVERY",
"name": "Scheduled Delivery",
"description": "Choose a delivery date and time"
}
],
"shipping_method_options": [
{
"id": "STANDARD_GROUND",
"description": "Standard Ground",
"price": {
"currency": "USD",
"value": 9.99,
"number": 999,
"symbol": "$"
},
"estimated_delivery": "5-7 business days"
},
{
"id": "EXPRESS_2DAY",
"description": "2-Day Express",
"price": {
"currency": "USD",
"value": 19.99,
"number": 1999,
"symbol": "$"
},
"estimated_delivery": "2 business days"
}
],
"shipping_method": null,
"notes": ""
}
],
"sub_total": {
"currency": "USD",
"value": 99.98,
"number": 9998,
"symbol": "$"
},
"shipping_total": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"tax_total": {
"currency": "USD",
"value": 8.00,
"number": 800,
"symbol": "$"
},
"fees": [
{
"description": "Recycle fee",
"currency": "USD",
"value": 2.00,
"number": 200,
"symbol": "$"
}
],
"fee_total": {
"currency": "USD",
"value": 2.00,
"number": 200,
"symbol": "$"
},
"total": {
"currency": "USD",
"value": 109.98,
"number": 10998,
"symbol": "$"
},
"addons": {
"offers": [],
"selections": []
},
"addon_total": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"payment_method_options": [
{
"type": "CreditCard",
"wallet": "user"
},
{
"type": "PayPal",
"wallet": "paypal"
}
],
"schema_version": "2.0"
}

​​ Multi-Shipment

Each shipment in the cart carries its own fulfillment_type. A cart with multiple shipments can mix types — for example, heavy items on SCHEDULED_DELIVERY while small items ship via SHIP_TO_ADDRESS, or items picked up at different store locations. Call this endpoint once per shipment.

​​ Next Steps

  • SHIP_TO_ADDRESS or SCHEDULED_DELIVERY → Set Shipping Method (pass selected_date / selected_time_slot for SCHEDULED_DELIVERY).
  • SCHEDULED_DELIVERY (before the above) → Get Availability to retrieve eligible dates and time slots.
  • PICKUP_IN_STORE → no further call required; location_id is already set in this request.

​​ Error Responses

Errors return a JSON body with code, error, and description. Program against the error value — descriptions are human-readable and may change.

400 — MissingAuthHeader

The x-firmly-authorization header is missing or empty.


{ "code": 400, "error": "MissingAuthHeader", "description": "x-firmly-authorization header is missing or invalid." }
400 — InvalidToken

The authorization token is not a valid JWT structure.


{ "code": 400, "error": "InvalidToken", "description": "Jwt token is invalid." }
400 — InvalidAPIToken

The API token (server-to-server secret) is invalid or has been revoked.


{ "code": 400, "error": "InvalidAPIToken", "description": "API token is invalid." }
400 — BadRequest

Server-to-server auth was attempted but required headers are missing or malformed.


{ "code": 400, "error": "BadRequest", "description": "Bad request." }
400 — InvalidFulfillmentType

The supplied fulfillment_type is not in the target shipment’s fulfillment_type_options.


{ "code": 400, "error": "InvalidFulfillmentType", "description": "Invalid fulfillment type." }
401 — Unauthorized

The authorization token was rejected.


{ "code": 401, "error": "Unauthorized", "description": "Unauthorized." }
401 — InvalidJWTToken

The device JWT signature does not verify, or required claims are missing.


{ "code": 401, "error": "InvalidJWTToken", "description": "Jwt token is invalid." }
404 — PartnerNotFound

The appid claim on the device JWT does not map to a known partner / tenant.


{ "code": 404, "error": "PartnerNotFound", "description": "Partner not found." }
404 — DomainNotFound

The {domain} path parameter does not match any merchant configured with Firmly, or the merchant has been disabled.


{ "code": 404, "error": "DomainNotFound", "description": "This domain was not found in firmly servers." }
404 — CartNotFound

No cart exists for this device on this domain.


{ "code": 404, "error": "CartNotFound", "description": "Cart was not found." }
404 — ShipmentNotFound

The supplied shipment_id does not match any shipment on the current cart. Re-read the cart to obtain a current id.


{ "code": 404, "error": "ShipmentNotFound", "description": "Shipment not found." }
404 — LocationNotFound

The supplied location_id is not a valid pickup location for this merchant. Returned only when fulfillment_type is PICKUP_IN_STORE.


{ "code": 404, "error": "LocationNotFound", "description": "Location not found." }
412 — OperationNotSupported

The merchant’s platform does not support this operation.


{ "code": 412, "error": "OperationNotSupported", "description": "This operation is not supported for this store." }
400 — InvalidInputBody

Request body fails schema validation. Ensure shipment_id is a non-empty string and fulfillment_type is one of SHIP_TO_ADDRESS, SCHEDULED_DELIVERY, PICKUP_IN_STORE.


{ "code": 400, "error": "InvalidInputBody", "description": "The body is not processable" }
422 — UnprocessableEntity

The request is well-formed but cannot be processed — typically because the merchant API rejected the fulfillment-type change for a reason not covered by the more specific errors above.


{ "code": 422, "error": "UnprocessableEntity", "description": "The given payload has unprocessable, invalid or non-existent data. Please check the data and try again." }
501 — NotImplemented

The merchant adapter is V1 and does not support this endpoint. Use V2 endpoints, or set the fulfillment configuration via Set Shipping Method where supported.


{ "code": 501, "error": "NotImplemented", "description": "Operation not implemented." }
503 — StoreUnavailable

The merchant’s API returned an unexpected response and the request could not be fulfilled. Retry with backoff.


{ "code": 503, "error": "StoreUnavailable", "description": "Store is unavailable." }