Amazon Multi-Channel Fulfillment (MCF) lets a seller hold one pool of stock inside Amazon's fulfilment centres and ship it to orders that did not come from Amazon: a Shopify store, a WooCommerce site, eBay, a wholesale order. For a commerce database MCF is a third party logistics connector, not a sales channel. The orders we push into it are already in our database from somewhere else, and what comes back is the physical half of the record: whether stock exists, what fulfilling will cost, which fulfilment centre shipped it, which carrier and tracking number carried it, and whether it came back. All of it is part of the Selling Partner API, so the credentials, the token flow and the notification plumbing are shared with the marketplace connector at /connectors/amazon. This page covers the fulfilment surface only and does not restate the auth walkthrough, the Listings API or the Orders API.
At a glance
There are two live versions of the Fulfillment Outbound API and they are different object models, not variations. v2026-07-04 is current and uses orderId, lineItems, productIdentifier.amazonSku, fulfillmentConfiguration and statuses such as COMPLETE_PARTIAL. v2020-07-01 is legacy and uses sellerFulfillmentOrderId, items, sellerSku, shippingSpeedCategory and statuses such as CompletePartialled. No sunset date for the legacy version was published as of 2026-09-22. Pick one per seller connection and store the version next to the credential.
What it is
Multi-Channel Fulfillment is Amazon's offer to use the FBA network as a general purpose third party logistics provider. Stock goes into an Amazon fulfilment centre exactly as it would for FBA, and that same pooled inventory then serves both Amazon marketplace orders and orders created through the Fulfillment Outbound API from anywhere else. Amazon picks, packs and ships, and charges a fulfilment fee per unit plus the usual FBA storage fees.
It is available in every major Amazon store including amazon.in, where MCF is commonly used by Indian D2C brands already running FBA who want their own website orders shipped from the same stock. Amazon publishes India specific guidance for MCF order creation, and India is the one place where perUnitDeclaredValue is documented as required rather than optional.
Three things separate MCF from a normal 3PL for integration purposes. There is no catalogue on the fulfilment side: the unit of inventory is a seller SKU that already exists in the seller's FBA account, so MCF cannot ship stock that is not an FBA SKU. Packaging is a negotiated feature: parcels arrive in Amazon branded boxes unless the seller is eligible for BLANK_BOX on the legacy version or sets packagingOption: UNBRANDED on the current one. And Amazon Logistics can be excluded with the BLOCK_AMZL feature, which sellers use where a competing marketplace refuses Amazon branded delivery.
API access
MCF needs no separate developer programme. The steps are the SP-API steps:
- Register as a developer in the Solution Provider Portal and create an application, public or private.
- Request the
Amazon Fulfillmentrole. Every Fulfillment Outbound operation lists it as the required role, and the FBA report types below need it too, some of them alongsidePricingorInventory and Order Tracking. - Have the seller authorise the application through the Selling Partner Appstore or your own website authorisation workflow. The seller needs an active FBA account in the store being fulfilled from.
- For a single brand building its own connector, register the application as private and self authorise from that seller's Seller Central.
Versions in force as of 2026-09-22:
Amazon generates official SDKs from the same models for Java, C#, PHP, Python, JavaScript and Rust, and publishes a Postman collection. The models are plain Swagger 2.0, so generating your own client from fulfillmentOutbound_2026-07-04.json is reasonable and common.
Authentication
Identical to the marketplace connector, so only the fulfilment specific parts are repeated. The full walkthrough including the consent URL, the authorization code exchange and restricted data tokens is at /connectors/amazon.
- The seller authorises your application. Store the
refresh_tokenfrom the code exchange, one per seller per region. - Exchange it for an access token at
https://api.amazon.com/auth/o2/token. The access token lives one hour. - Send it as
x-amz-access-tokenon every call. AWS Signature Version 4 is no longer required. - No restricted data token is needed on this surface. The destination address on an MCF order is one we supplied, so reading it back is not restricted buyer data.
curl -X POST https://api.amazon.com/auth/o2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=refresh_token' \ -d 'refresh_token=Atzr|IwEBIA...' \ -d 'client_id=amzn1.application-oa2-client.xxxx' \ -d 'client_secret=xxxx'
curl -X GET \ 'https://sellingpartnerapi-na.amazon.com/fulfillment/outbound/2026-07-04/orders?updatedAfter=2026-09-01T00:00:00Z' \ -H 'x-amz-access-token: Atza|IwEBIA...' \ -H 'Accept: application/json'
Regional hosts are the SP-API hosts: sellingpartnerapi-na.amazon.com, sellingpartnerapi-eu.amazon.com, sellingpartnerapi-fe.amazon.com. India sits in the EU group, marketplace id A21TJRUUN4KGV. A seller fulfilling in more than one region needs one authorisation and one refresh token per region.
The current version accepts an optional x-amzn-fulfillment-service-id header on every operation, described as the identifier of the fulfilment service used for the operation, example value FS01-o8vlfw8b1tiu1. It is not required for standard MCF.
Objects we can read
Orders
An MCF fulfilment order is the unit of work, created by us. Reading it back is how we learn what Amazon did with it.
The current list takes updatedAfter (ISO 8601), pageToken, and shipments to control whether shipment detail is inlined. The legacy list takes queryStartDate and nextToken. Neither has a status or marketplace filter, so the sync pattern is a rolling watermark.
Status values differ by version. Current: PROCESSING, COMPLETE, COMPLETE_PARTIAL, CANCELLED, UNFULFILLABLE, INVALID. Legacy: New, Received, Planning, Processing, Cancelled, Complete, CompletePartialled, Unfulfillable, Invalid. The legacy documentation adds a rule that matters operationally: an order in Received or Planning can still be cancelled, an order in Processing cannot, because picking has started on at least one shipment.
Sample getOrder, current version, trimmed to one line item and one shipment. The delivery address is customer PII.
{"order": {
"orderId": "ABC123XYZ", "channel": "SHOPIFY",
"receiveTime": "2025-04-21T10:30:00Z", "status": "PROCESSING",
"statusUpdateTime": "2025-04-21T11:45:00Z",
"fulfillmentConfiguration": {
"serviceLevel": {"serviceTiers": ["STANDARD"]}, "action": "HOLD", "policy": "FILL_ALL_AVAILABLE",
"services": {"packaging": {"packagingOption": "UNBRANDED"}, "additional": {}}},
"origin": {"countryCode": "US"},
"destination": {"deliveryAddress": {
"name": "Shopper Name", "addressLine1": "1000 Winthrop Ave N", "city": "Seattle",
"stateOrRegion": "WA", "postalCode": "98103", "countryCode": "US",
"phone": "123-456-7890", "email": "shopper@email.com"}},
"lineItems": [{
"lineItemId": "someLineItemId",
"product": {"productIdentifier": {"amazonSku": "BOOK-123-HC"},
"perUnitDeclaredValue": {"currencyCode": "USD", "amount": "14.99"}},
"amount": {"unit": "EACHES", "value": "1.0"},
"cancelledAmount": {"unit": "EACHES", "value": "0.0"},
"unfulfillableAmount": {"unit": "EACHES", "value": "0.0"}}],
"shipments": [{
"amazonShipmentId": "SHIP901234", "amazonFacility": {"facilityId": "FC456"},
"status": "SHIPPED", "shipTime": "2025-04-21T15:00:00Z", "deliveryTime": "2025-04-23T12:00:00Z",
"items": [{"shipmentItemId": "SI001", "lineItemId": "LI789012",
"productIdentifier": {"amazonSku": "SKU123"},
"amount": {"value": "1.0", "unit": "EACHES"}}],
"packages": [{"packageId": "PKG-abc123def456", "status": "DELIVERED", "shipmentItemIds": ["SI001"],
"tracking": {"carrier": {"carrierCode": "FEDEX", "trackingNumber": "123456789"},
"amazon": {"trackingNumber": "123456789"}}}]}],
"paymentInformation": {"payments": [
{"paymentId": "PAY-12345", "paymentMethod": "CREDIT_CARD", "paymentTime": "2019-10-13T13:53:49Z"}]}
}}
The channel field on the current version is the sales channel the order came from, SHOPIFY in Amazon's own example. It maps straight onto orders.channel, which means the legacy version's lack of it is a real loss that has to be reconstructed from our own record.
Order items
Items are nested inside the order, there is no separate items endpoint in either version. Legacy getFulfillmentOrder, trimmed:
{"payload": {
"fulfillmentOrder": {
"sellerFulfillmentOrderId": "FBATestOrder-1", "marketplaceId": "ATVPDKIKX0DER",
"displayableOrderId": "TestOrder-FBAOutbound", "displayableOrderDate": "2020-01-09T19:46:45Z",
"shippingSpeedCategory": "Standard", "fulfillmentAction": "Ship", "fulfillmentPolicy": "FillOrKill",
"destinationAddress": {"name": "Amazon", "addressLine1": "1234 Amazon Way", "city": "Troy",
"stateOrRegion": "MI", "postalCode": "48084", "countryCode": "US"},
"receivedDate": "2020-02-07T01:23:30Z", "fulfillmentOrderStatus": "PROCESSING",
"statusUpdatedDate": "2020-02-07T02:33:31Z"},
"fulfillmentOrderItems": [{
"sellerSku": "PSMM-TEST-SKU-Jan-21_19_59_44-0738", "sellerFulfillmentOrderItemId": "OrderItemID2",
"quantity": 1, "fulfillmentNetworkSku": "B07CGHKWZP", "orderItemDisposition": "Sellable",
"cancelledQuantity": 0, "unfulfillableQuantity": 0,
"estimatedShipDate": "2020-02-08T01:23:31Z", "estimatedArrivalDate": "2020-02-15T01:23:31Z",
"perUnitDeclaredValue": {"currencyCode": "USD", "value": "18.99"}}],
"fulfillmentShipments": [{
"amazonShipmentId": "DchKfcZ9N", "fulfillmentCenterId": "RNO1",
"fulfillmentShipmentStatus": "PENDING", "shippingDate": "2020-02-07T02:33:23Z",
"fulfillmentShipmentItem": [{"sellerSku": "CR-47K6-H6QN", "sellerFulfillmentOrderItemId": "OrderItemID1",
"quantity": 3, "packageNumber": 0, "manufacturerLotCodes": ["LOT0822-1234", "LOT1030-5678"]}]}],
"returnItems": [], "returnAuthorizations": []
}}
cancelledQuantity and unfulfillableQuantity are how you detect a partial fulfilment: a line with quantity: 3 and unfulfillableQuantity: 1 shipped two. Storing only quantity loses the story. manufacturerLotCodes and serialNumber appear per shipped item where the seller uses them.
Products and listings
No catalogue surface. MCF operates on seller SKUs that already exist in the seller's FBA account, and the only identifiers returned are sellerSku (or amazonSku), fnSku (Amazon's fulfilment network SKU, a barcode level identifier) and asin. For titles, attributes, images, price or listing state use the Listings Items and Catalog Items APIs at /connectors/amazon.
One eligibility surface is worth pulling on the legacy version: GET /fba/outbound/2020-07-01/features returns the features the seller is eligible for, for example BLANK_BOX ("ship in non-Amazon branded packaging") and PSLIP ("insert customized packing slips"), each with sellerEligible. GET .../features/inventory/{featureName} lists eligible SKUs with sellerSku, fnSku, asin, skuCount and overlappingSkus, and GET .../features/inventory/{featureName}/{sellerSku} answers for one SKU with isEligible and ineligibleReasons.
Inventory
FBA Inventory API v1, one operation: GET /fba/inventory/v1/summaries.
Amazon publishes the schema but no sample response for this operation, so the keys below are exact and the values are illustrative.
{"payload": {
"granularity": {"granularityType": "Marketplace", "granularityId": "ATVPDKIKX0DER"},
"inventorySummaries": [{
"asin": "B00EXAMPLE", "fnSku": "X0014BIZ8T", "sellerSku": "CR-47K6-H6QN",
"condition": "NewItem", "productName": "Example product",
"totalQuantity": 48, "lastUpdatedTime": "2026-09-21T11:02:14Z",
"inventoryDetails": {
"fulfillableQuantity": 40, "inboundWorkingQuantity": 0,
"inboundShippedQuantity": 6, "inboundReceivingQuantity": 2,
"reservedQuantity": {"totalReservedQuantity": 5, "pendingCustomerOrderQuantity": 4,
"pendingTransshipmentQuantity": 1, "fcProcessingQuantity": 0},
"researchingQuantity": {"totalResearchingQuantity": 0, "researchingQuantityBreakdown": []},
"unfulfillableQuantity": {"totalUnfulfillableQuantity": 3, "customerDamagedQuantity": 1,
"warehouseDamagedQuantity": 0, "distributorDamagedQuantity": 0,
"carrierDamagedQuantity": 0, "defectiveQuantity": 2,
"expiredQuantity": 0}}}]
}}
The three inbound quantities matter for planning and mean different things: inboundWorkingQuantity is in a plan that has not shipped, inboundShippedQuantity is in transit, inboundReceivingQuantity has arrived and is being checked in. There is no warehouse level breakdown here, FBA reports stock at the network level for a marketplace. For per fulfilment centre placement use the GET_AFN_INVENTORY_DATA_BY_COUNTRY and GET_RESERVED_INVENTORY_DATA reports.
Shipments and tracking
On the current version shipments and packages are inlined in getOrder and listOrders when shipments is requested. Shipment status is PROCESSING, SHIPPED or CANCELLED. Package status is PROCESSING, IN_TRANSIT, DELAYED, OUT_FOR_DELIVERY, DELIVERED, UNDELIVERABLE or EXPIRED, with a tracking object carrying both the carrier's number and Amazon's own.
The legacy version has a dedicated tracking operation that returns a scan history, which the current version's inlined package object does not: GET /fba/outbound/2020-07-01/tracking?packageNumber={packageNumber}.
{"payload": {
"packageNumber": 212794778, "trackingNumber": "1Z50V7420354708051", "carrierCode": "UPS",
"customerTrackingLink": "https%3A%2F%2Fwww.swiship.com%2Ftrack%3Fid%3D1Z50V7420354708051",
"shipToAddress": {"city": "Troy", "state": "MI", "country": "US"},
"currentStatus": "DELIVERED", "currentStatusDescription": "Delivered to the destination address",
"additionalLocationInfo": "AS_INSTRUCTED",
"trackingEvents": [
{"eventDate": "2020-01-22T00:15:55Z", "eventCode": "EVENT_301", "eventDescription": "Delivered.",
"eventAddress": {"city": "Troy", "state": "MI", "country": "US"}},
{"eventDate": "2019-10-30T23:33:28Z", "eventCode": "EVENT_206",
"eventDescription": "In transit to pickup location",
"eventAddress": {"city": "Phoenix", "state": "AZ", "country": "US"}}]
}}
packageNumber comes from fulfillmentShipmentPackage[].packageNumber on the fulfilment order. The eventCode values are Amazon's own codes in the form EVENT_nnn, not carrier scan codes, so a separate status mapping table is needed if you also ingest carrier level tracking from /connectors/delhivery or the other carriers. Amazon documents a proof of delivery use case returning a photo or signature for a delivered package, and a multi shipment tracking use case for orders split across packages.
Returns and cancellations
Returns against an MCF order are raised by us, not by Amazon, because the customer bought elsewhere. The legacy version exposes this directly through GET /fba/outbound/2020-07-01/returnReasonCodes and PUT /fba/outbound/2020-07-01/fulfillmentOrders/{sellerFulfillmentOrderId}/return. Reason codes are the seller facing set, for example CR-UNWANTED_ITEM, CR-DEFECTIVE, CR-ORDERED_WRONG_ITEM, AMZ-PG-BAD-DESC.
{"payload": {
"returnItems": [{
"sellerReturnItemId": "testReturn11", "sellerFulfillmentOrderItemId": "OrderItemID2",
"amazonShipmentId": "D4yZjWZVN", "returnComment": "TestReturn",
"amazonReturnReasonCode": "UNKNOWN_OTHER_REASON", "status": "New",
"statusChangedDate": "2020-02-07T04:14:38Z", "returnAuthorizationId": "RMA3JTIPBJM42UU6"}],
"invalidReturnItems": [],
"returnAuthorizations": [{
"returnAuthorizationId": "RMA3JTIPBJM42UU6", "fulfillmentCenterId": "TUS1",
"returnToAddress": {"name": "Returns Department", "addressLine1": "5333 W. Lower Buckeye Road",
"city": "Phoenix", "stateOrRegion": "AZ", "postalCode": "85043",
"countryCode": "US"},
"amazonRmaId": "D50WttPHRRMA", "rmaPageURL": "https://www.amazon.com/gp/orc/rml/D50WttPHRRMA"}]
}}
rmaPageURL is the printable return label page to surface to the shopper. returnItems[].status moves from New to Processed when a fulfilment centre handles it, and returnReceivedCondition then carries the disposition: Sellable, Defective, CustomerDamaged, CarrierDamaged or FulfillerDamaged. That disposition is the difference between stock returning to fulfillableQuantity and stock landing in unfulfillableQuantity.
The v2026-07-04 model as published on 2026-09-22 contains no create return operation, and returns are read back through getOrder. If raising returns through the API matters, that is a reason to stay on the legacy version for now.
Cancellation is PUT .../orders/{orderId}/cancel or PUT .../fulfillmentOrders/{sellerFulfillmentOrderId}/cancel and answers 202, not 200. It is a request to stop, not a guarantee, so re-read the order afterwards.
Payments and settlements
No JSON endpoint returns what an MCF shipment actually cost. Two things come close, then you fall back to reports.
The preview operations return an estimate before the order exists, which is the number for a margin check: POST /fulfillment/outbound/2026-07-04/previews, or POST /fba/outbound/2020-07-01/fulfillmentOrders/preview on the legacy version, whose estimatedFees array carries named fees such as FBAPerUnitFulfillmentFee alongside isFulfillable, estimatedShippingWeight and unfulfillablePreviewItems.
{"plannedShipments": [{
"estimatedShippingWeight": {"unit": "KG", "value": "2.0"},
"items": [{"productIdentifier": {"amazonSku": "someSku"},
"amount": {"unit": "EACHES", "value": "1.0"}}],
"offers": [{
"fulfillmentConfiguration": {
"serviceLevel": {"serviceTier": "STANDARD",
"deliveryInterval": {"startTime": "2025-04-21T12:34:56Z", "endTime": "2025-04-22T12:34:56Z"},
"shipInterval": {"startTime": "2025-04-21T10:00:00Z", "endTime": "2025-04-21T14:00:00Z"}},
"services": {"packaging": {"packagingOption": "UNBRANDED"},
"delivery": {"paymentOnDelivery": "ENABLED"}, "additional": {}}},
"estimatedPrice": {
"rollupPrices": [{"type": "MCFTransportationFee",
"value": {"currencyCode": "USD", "amount": "4.25"}}],
"totalPrice": {"currencyCode": "USD", "amount": "4.25"}}}]}],
"constraints": [{"message": "There is not enough quantity of item xyz.", "type": "ValidationError",
"code": "ItemQuantityNotAvailable"}]}
POST /fulfillment/outbound/2026-07-04/offers (getOffers) is the lighter cousin: for a list of SKUs and a destination it returns serviceTier and deliveryInterval per offer with an expiryTime, and constraints where a tier is unavailable. It is the right call for a delivery promise on a product page.
Actual charged amounts come from the Reports API, all requiring the Amazon Fulfillment role:
All are tab delimited flat files fetched through createReport, getReport, getReportDocument, downloaded from a pre signed URL and usually gzipped.
MCF fees for orders that did not originate on Amazon are billed against the seller's Amazon account and appear in the FBA fee reports and in Finances, not in a settlement report keyed by our external order id. The join key is sellerFulfillmentOrderId or orderId, both values we chose, so reconciliation works as long as we make them unique and never reuse them.
Customers
No customer object. MCF holds only the destination address and optional email we supplied on order creation and returns them unchanged. There is no customer id, no order history and no masking, because Amazon is not the merchant of record for these orders. Treat the address as our own PII under our retention policy, not Amazon's buyer data policy.
Locations
No locations endpoint. Fulfilment centres appear only as identifiers on other objects: fulfillmentCenterId on the legacy shipment and return authorisation (RNO1, TUS1), amazonFacility.facilityId on the current shipment. Return authorisations carry a full returnToAddress, and inbound shipments carry a destination with a warehouse id and address. Those are the only places a real fulfilment centre address is returned.
Inbound plans and inbound shipments
Sending stock in is Fulfillment Inbound 2024-03-20, a workflow API rather than an object store. You create a plan, generate and confirm packing options, generate and confirm placement options, set packing information, generate and confirm transportation options, and only then do shipments exist with confirmation ids.
Every generate and confirm operation is asynchronous and returns an operationId you poll through getInboundOperationStatus. This is the one place on the fulfilment surface where a state machine in our own store is unavoidable.
createInboundPlan takes destinationMarketplaces (array, currently one), sourceAddress, optional name, and items[] where each item carries msku, quantity, labelOwner (AMAZON, SELLER or NONE), prepOwner, and optional expiration and manufacturingLotCode. A plan reads back with inboundPlanId, name, status (ACTIVE, VOIDED among others), marketplaceIds, sourceAddress, createdAt, lastUpdatedAt, and once generated, packingOptions, placementOptions and shipments summaries. A shipment carries shipmentId, shipmentConfirmationId (the FBA prefixed id printed on labels), amazonReferenceId, status, source, destination, dates, selectedDeliveryWindow, selectedTransportationOptionId, freightInformation and trackingDetails split into spdTrackingDetail for small parcel and ltlTrackingDetail for less than truckload. Amazon publishes schemas but no full JSON sample for these operations, so no sample response is reproduced here.
Writing back: listings, price and stock
MCF has no listings, no price and no stock to write. Stock arrives physically through the inbound flow above, and price is whatever our own channel charged. What we write is orders.
Create an MCF order, current version
POST /fulfillment/outbound/2026-07-04/orders
{"orderId": "orderId", "channel": "SHOPIFY",
"fulfillmentConfiguration": {
"serviceLevel": {"serviceTiers": ["STANDARD"]}, "action": "HOLD", "policy": "FILL_ALL_AVAILABLE",
"services": {"packaging": {"packagingOption": "UNBRANDED"}, "additional": {}}},
"origin": {"countryCode": "US"},
"destination": {"deliveryAddress": {
"name": "Shopper Name", "addressLine1": "1000 Winthrop Ave N", "city": "Seattle",
"stateOrRegion": "WA", "postalCode": "98103", "countryCode": "US",
"phone": "123-456-7890", "email": "shopper@email.com"}},
"lineItems": [{
"lineItemId": "someLineItemId",
"product": {"productIdentifier": {"amazonSku": "BOOK-123-HC"},
"perUnitDeclaredValue": {"currencyCode": "USD", "amount": "14.99"}},
"amount": {"unit": "EACHES", "value": "1.0"},
"fulfillmentConfiguration": {"services": {
"packaging": {"packingSlip": {"templateName": "templateName", "templateAttributes": {
"orderId": "MyOrder-123", "orderTime": "2026-07-01T10:00:00Z",
"orderText": "Thank you for your purchase!"}}},
"delivery": {"paymentOnDelivery": {
"perUnitServicePrice": {"currencyCode": "USD", "amount": "14.99"}}}}}}],
"paymentInformation": {"payments": [
{"paymentId": "PAY-12345", "paymentMethod": "CREDIT_CARD", "paymentTime": "2019-10-13T13:53:49Z"}]}}
createOrder answers either 200 with the full order or 202 with {"orderId": "...", "status": "PROCESSING"}, so handle both. action: HOLD creates the order without releasing it to picking, which is what you want before payment capture, and PUT /orders/{orderId}/status with {"status": "PROCESSING"} releases it. paymentOnDelivery is the cash on delivery mechanism, which is why an Indian integration usually sets perUnitServicePrice per line. The per line packingSlip block is how a custom packing slip template is applied.
Create an MCF order, legacy version
POST /fba/outbound/2020-07-01/fulfillmentOrders. Required: sellerFulfillmentOrderId, displayableOrderId, displayableOrderDate, displayableOrderComment, shippingSpeedCategory, destinationAddress, items. Each item requires sellerSku, sellerFulfillmentOrderItemId and quantity, maximum 100 items per order.
Two policy fields decide partial fulfilment behaviour:
fulfillmentAction:Ship(release immediately) orHold.fulfillmentPolicy:FillOrKill(ship only if the whole order can be filled by the expected date, otherwise cancel),FillAll(never cancel, wait for stock),FillAllAvailable(ship what exists, cancel the rest).
shippingSpeedCategory takes Standard, Expedited, Priority or ScheduledDelivery, and ScheduledDelivery requires a deliveryWindow. perUnitDeclaredValue is documented as required for India.
Other writes
Inbound writes are createInboundPlan, the three confirm operations, setPackingInformation, setPrepDetails, updateItemComplianceDetails, createMarketplaceItemLabels, updateShipmentTrackingDetails, updateShipmentSourceAddress and cancelInboundPlan.
Webhooks and notifications
Delivery is through the Notifications API into an SQS queue or EventBridge bus that you own. Amazon never POSTs to an HTTPS endpoint of yours, so there is no HMAC signature to verify: the trust boundary is the IAM policy on your queue. Destination and subscription operations are shared with the marketplace connector and documented at /connectors/amazon.
FULFILLMENT_ORDER_STATUS is sent whenever the status of a Multi-Channel Fulfillment order changes and supports CEL based filterExpression filtering. The EventType field distinguishes Order, Shipment and Return variants of the same notification.
{"NotificationVersion": "1.0", "NotificationType": "FULFILLMENT_ORDER_STATUS",
"PayloadVersion": "1.0", "EventTime": "2020-01-11T00:09:53.109Z",
"Payload": {"FulfillmentOrderStatusNotification": {
"SellerId": "merchantId", "EventType": "Shipment",
"StatusUpdatedDateTime": "2020-01-11T00:09:53.109Z",
"SellerFulfillmentOrderId": "OrderId", "FulfillmentOrderStatus": "Complete",
"FulfillmentShipment": {
"FulfillmentShipmentStatus": "Shipped", "AmazonShipmentId": "DZRSmwG2N",
"EstimatedArrivalDateTime": "2014-12-19T22:59:59Z",
"FulfillmentShipmentPackages": [
{"PackageNumber": 1, "CarrierCode": "HERMESIT", "TrackingNumber": "0113838XXXXXX8300169397"}]}}},
"NotificationMetadata": {
"ApplicationId": "amzn1.sellerapps.app.f1234566-aaec-55a6-b123-bcb752069ec5",
"SubscriptionId": "7d78cc50-95c8-4641-add7-10af4b1fedc9",
"PublishTime": "2020-01-11T00:02:50.501Z",
"NotificationId": "2012e8e5-b365-4cb1-9fd8-be9dfc6d5eaf"}}
This notification carries the tracking number directly, so shipped and tracking state can be kept current without polling getOrder at all.
FBA_INVENTORY_AVAILABILITY_CHANGES is sent whenever FBA inventory quantities change and carries a snapshot across all eligible Amazon stores in a region. Its shape is SellerId, FNSKU, ASIN, SKU and FulfillmentInventoryByMarketplace[], where each entry holds MarketplaceId, ItemName, Stores[] and a FulfillmentInventory object with Fulfillable, Unfulfillable, Researching, FutureSupplyBuyable, an InboundQuantityBreakdown and a ReservedQuantityBreakdown. It also supports CEL filtering.
FBA_OUTBOUND_SHIPMENT_STATUS is not the MCF one. Amazon's reference states it fires when Amazon creates or cancels an FBA shipment, that it is only for FBA Onsite shipments, and that it is available only in the Amazon Brazil store. Do not subscribe to it expecting MCF events.
Without notifications, poll listOrders on a rolling updatedAfter every 15 minutes and getInventorySummaries with startDateTime hourly.
Rate limits and pagination
Rates are per pair of selling partner and application, refilled as a token bucket, with HTTP 429 and a QuotaExceeded error on an empty bucket. The x-amzn-RateLimit-Limit response header reports the rate actually applied and is best effort.
getInventorySummaries with a burst of 2 is the tightest limit here and shapes the sync design. Do not walk SKUs one at a time: pass sellerSkus as an array, or drop the SKU filter entirely and page the whole account with startDateTime set to the last successful sync.
Pagination differs per API: nextToken echoed back with every other parameter unchanged on Fulfillment Outbound v2020-07-01 and FBA Inventory, pageToken on Fulfillment Outbound v2026-07-04, paginationToken with pageSize on Fulfillment Inbound 2024-03-20.
A practical cadence for one seller: listOrders on a rolling updatedAfter every 15 minutes, or event driven from FULFILLMENT_ORDER_STATUS with a six hourly reconciliation sweep; getInventorySummaries hourly with details=true; fee and ledger reports daily; inbound plans polled only while a plan is open.
Mapping to the unified model
orders
order_items
listings
Not applicable, MCF has no listing object. Map listings from /connectors/amazon or from the originating channel.
inventory
unfulfillableQuantity has no unified field. Carry it in an extension column, it is the early warning for damaged and expired stock.
shipments
returns
settlements
locations
Gaps and open questions
- The v2026-07-04 model as published on 2026-09-22 has no create return operation and no tracking operation with a scan history. Whether those are coming, or whether Amazon expects returns to be raised only on the legacy version, is not stated in the model and needs confirmation from release notes or developer support.
- No sunset date for Fulfillment Outbound v2020-07-01 was found. The deprecation schedule page renders its body client side and was not readable by the fetcher, so treat this as unverified rather than as a guarantee.
x-amzn-fulfillment-service-idis described only as the identifier of the fulfilment service used for the operation. Valid values and when it becomes required are not documented.- MCF fee rates per unit are deliberately not quoted here. They vary by store, size tier, weight and promotion and are republished several times a year. Read them from
GET_FBA_ESTIMATED_FBA_FEES_TXT_DATArather than hard coding a table. - FBA Inventory reports network level availability per marketplace, not per fulfilment centre. Confirm whether
GET_AFN_INVENTORY_DATA_BY_COUNTRYandGET_RESERVED_INVENTORY_DATAgive enough granularity before promising per centre stock. - The inbound API publishes schemas but no full JSON response samples, so the inbound detail here is a field list rather than a verbatim response.
- Sandbox behaviour for Fulfillment Outbound is documented as dynamic but has not been exercised against a live application, so its fidelity on partial fulfilment and cancellation paths is unverified.
Sources
- Fulfillment Outbound API use case guide, read 2026-09-22, which lists v2026-07-04 as current and v2020-07-01 as legacy
- selling-partner-api-models, fulfillmentOutbound_2026-07-04.json, parsed 2026-09-22
- selling-partner-api-models, fulfillmentOutbound_2020-07-01.json, parsed 2026-09-22, source of the legacy samples
- selling-partner-api-models, fbaInventory.json, parsed 2026-09-22
- selling-partner-api-models, fulfillmentInbound_2024-03-20.json, parsed 2026-09-22
- Notification type values, read 2026-09-22, source of the
FULFILLMENT_ORDER_STATUSsample and theFBA_OUTBOUND_SHIPMENT_STATUSBrazil restriction - FBA report type values, read 2026-09-22
- SP-API llms.txt index
- /connectors/amazon for the shared authentication, notification and rate limit machinery