Inventory

Record inventory movement

Writes an immutable movement in a warehouse, or a transfer between two, and can publish selected quantity.

POST
/v1/sellers/{sellerId}/inventory-movements

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 the warehouses list. 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; toWarehouseId missing on a transfer, or sent on another type; toWarehouseId equal to warehouseId.
  • 404: the seller, the Variant or a warehouse does not exist. A warehouse of another seller or another account returns 404.
  • 409 with details.reason = "warehouse_archived": the warehouse is archived and takes no movement. details.warehouseId says which one. Reactivate it first.
  • 409 with details.reason = "inventory_underflow": the movement would leave the warehouse without enough stock. details.warehouseId is the warehouse that went short (for a transfer, the source). Nothing is written and no event is sent. A Variant with allowBackorder may go negative.
  • 409 with details.reason = "inventory_authority": the Variant is not managed by MarketAPI.

Authorization

api_key
headerAuthorizationBearer <token>

API key (mk_...)

Path Parameters

sellerId*string

Seller the new resource belongs to.

Match^([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)$
Formatuuid

Header Parameters

Idempotency-Key?string

Optional. 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.

Length1 <= length <= 255

Request Body

application/json
  1. body

One idempotent inventory movement in one warehouse (or a transfer between two), optionally followed by selected quantity publications.

type*string

Kind of inventory ledger movement.

Value in"adjustment""reservation""release""sale""return""transfer"
variantId*string

Variant whose inventory changes.

Match^([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)$
Formatuuid
warehouseId?string

Warehouse 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.

Match^([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)$
Formatuuid
toWarehouseId?string

Destination warehouse of a transfer. Required when type is transfer and not accepted for any other type. It must differ from the source warehouse.

Match^([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)$
Formatuuid
quantity*integer

Signed 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.

Range-9007199254740991 <= value <= 9007199254740991
reason*string

Human-readable reason retained in the immutable ledger.

Length1 <= length <= 500
reference?

Optional external reference such as an order, transfer, or ERP document.

publishTargets?

Explicit listing, binding, or connection targets for this quantity publication.

Response Body

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
  1. 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).

Items1 <= items <= 2
balance*

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.

Match^([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)$
Formatuuid
curl -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"}