Record inventory movement
Writes an immutable movement in a warehouse, or a transfer between two, and can publish selected quantity.
Publish inventory
- MockDevelopment only
- Mercado LivreNot supported
- MagaluPlanned
- AmazonPlanned
- TikTok ShopPlanned
- ShopeePlanned
Send a whole-unit quantity compatible with the movement type. Only adjustment accepts a negative quantity; the other types need a positive one (otherwise 400). The Variant must have inventoryAuthority: "marketapi".
In which warehouse
warehouseId picks the warehouse. Without it, the movement goes to the seller's default warehouse. The warehouse must belong to the same seller as the Variant.
curl -X POST "$BACKEND_URL/v1/sellers/$SELLER_ID/inventory-movements" \
-H "Authorization: Bearer mk_your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"type":"adjustment","variantId":"'$VARIANT_ID'","warehouseId":"'$WAREHOUSE_ID'","quantity":10,"reason":"Initial count"}'Transfer between warehouses
With type: "transfer", warehouseId is the source and toWarehouseId is the destination. The quantity is positive and the two warehouses must differ.
curl -X POST "$BACKEND_URL/v1/sellers/$SELLER_ID/inventory-movements" \
-H "Authorization: Bearer mk_your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"type":"transfer","variantId":"'$VARIANT_ID'","warehouseId":"'$FROM_ID'","toWarehouseId":"'$TO_ID'","quantity":4,"reason":"Branch restock"}'A transfer writes two rows in the ledger, with the same transferId: an outbound (-4) at the source and an inbound (+4) at the destination. Everything happens or nothing does. The Variant total does not change, so it does not publish quantity by itself, not even with the automatic policy. Whoever sends publishTargets still gets the job.
What comes back
movements: the list of movements written. It has 1 item, or 2 for a transfer (the outbound first, then the inbound).balance: the Variant balance after the command, with the totals and thewarehouseslist. No need to read the balance again.publicationJobId: the publication job, when there was an eligible target.
publishTargets is optional: select Listings, bindings, or Connections in this same call, without a mandatory second request.
The inventory.movement_created webhook is sent once per ledger row. Each event carries the movement (with warehouseId and transferId) and the same full balance. The two events of a transfer carry the same balance.
Common errors
400: a quantity with the wrong sign for the type;toWarehouseIdmissing on a transfer, or sent on another type;toWarehouseIdequal towarehouseId.404: the seller, the Variant or a warehouse does not exist. A warehouse of another seller or another account returns404.409withdetails.reason = "warehouse_archived": the warehouse is archived and takes no movement.details.warehouseIdsays which one. Reactivate it first.409withdetails.reason = "inventory_underflow": the movement would leave the warehouse without enough stock.details.warehouseIdis the warehouse that went short (for a transfer, the source). Nothing is written and no event is sent. A Variant withallowBackordermay go negative.409withdetails.reason = "inventory_authority": the Variant is not managed by MarketAPI.
api_keyAuthorizationBearer <token>API key (mk_...)
sellerId*stringSeller the new resource belongs to.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidIdempotency-Key?stringOptional. A unique value (for example a UUID), 1 to 255 characters, that makes the request safe to retry: repeating it with the same body within 24h returns the original response with Idempotency-Replayed: true instead of running the operation again. Scoped to your account. Reusing it with a different body returns 409.
1 <= length <= 255application/json- body
One idempotent inventory movement in one warehouse (or a transfer between two), optionally followed by selected quantity publications.
type*stringKind of inventory ledger movement.
"adjustment""reservation""release""sale""return""transfer"variantId*stringVariant whose inventory changes.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidwarehouseId?stringWarehouse whose balance changes. Omit it to use the seller's default warehouse. For a transfer, this is the source warehouse. The warehouse must belong to the same seller as the variant and be active.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidtoWarehouseId?stringDestination warehouse of a transfer. Required when type is transfer and not accepted for any other type. It must differ from the source warehouse.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidquantity*integerSigned whole-unit change. The service validates the sign required by the movement type. A transfer takes a positive quantity: the units that leave the source warehouse and enter toWarehouseId.
-9007199254740991 <= value <= 9007199254740991reason*stringHuman-readable reason retained in the immutable ledger.
1 <= length <= 500reference?Optional external reference such as an order, transfer, or ERP document.
publishTargets?Explicit listing, binding, or connection targets for this quantity publication.
The immutable ledger movements (one, or two for a transfer: out of the source, into the destination), the balance of the variant after the command, and the optional quantity-publication job.
application/json- response
Committed inventory movements (one, or two for a transfer), the variant balance after them, and the optional asynchronous quantity publication they requested.
movements*array<>The ledger movements committed by this request: one, or two for a transfer (the outgoing movement from the source warehouse first, then the incoming one at the destination, both with the same transferId).
1 <= items <= 2balance*The balance of the variant after this request, in total and per warehouse.
publicationJobId*|Quantity publication job created with this movement, or null when no explicit or automatic target was eligible.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidcurl -X POST "https://example.com/v1/sellers/b6a1c0de-3f0c-4f53-9c6e-2a1d7d3b9e10/inventory-movements" \ -H "Content-Type: application/json" \ -d '{ "type": "adjustment", "variantId": "47c9f819-fcf6-4478-b21a-678ecc594a11", "warehouseId": "b7e2a1c4-5d3f-4e8a-9b6c-2f1d0a8e7c35", "quantity": 7, "reason": "Initial stock count", "publishTargets": { "listingIds": [ "0e2ce906-a6ab-4101-9461-4168c8b6b902" ] } }'{ "movements": [ { "id": "cf41b959-9430-4fef-8f8a-2c8edc9199b9", "sellerId": "3d1c8a52-7f0e-4b0a-8a65-9c1b2f6d7e01", "variantId": "47c9f819-fcf6-4478-b21a-678ecc594a11", "warehouseId": "b7e2a1c4-5d3f-4e8a-9b6c-2f1d0a8e7c35", "type": "adjustment", "quantity": 7, "reason": "Initial stock count", "reference": null, "transferId": null, "createdAt": "2026-10-10T12:00:00.000Z" } ], "balance": { "variantId": "47c9f819-fcf6-4478-b21a-678ecc594a11", "onHand": 10, "reserved": 2, "available": 8, "updatedAt": "2026-10-10T12:00:00.000Z", "warehouses": [ { "warehouseId": "b7e2a1c4-5d3f-4e8a-9b6c-2f1d0a8e7c35", "onHand": 7, "reserved": 0, "available": 7, "updatedAt": "2026-10-10T12:00:00.000Z" }, { "warehouseId": "e41c9a07-26b8-4d53-a0f1-8c3b7d5e9a12", "onHand": 3, "reserved": 2, "available": 1, "updatedAt": "2026-10-09T08:00:00.000Z" } ] }, "publicationJobId": "ce486d72-9e94-4f98-876e-26f4506d8d8b"}