Core concepts

The handful of ideas every endpoint is built on: money in cents, your balance buckets, customers, item stacks and idempotency.

On this page

Money#

Every amount on the partner rails is an integer number of US cents, and every field carrying one says so in its name: payoutCents, chargedCents, priceCents. Responses that carry money also carry "currency": "USD" so nothing has to be inferred. There are no floats and no coins.

Your company holds money in one prepaid balance with named buckets. Funding it, and taking money out, happens in the console; the API only ever spends from it or credits it.

BucketWhat it is
SpendableMoney you can move into a pool, or withdraw. Top-ups land here.
Payments poolMoney reserved for buying items from your users when you fund MM2 Payments yourself. A sale debits it.
Payouts floatMoney reserved for buying items for your users. A payout order debits it. Kept separate from the Payments pool unless you choose to share one.
ClaimableMoney MM2Empire has credited you for payments it funded, waiting for an owner to claim it into spendable. Owed from the moment the item moves.

Customers#

A customer is one of your users, identified by their Roblox account and linked to your company. Linking creates an MM2Empire account for that Roblox id if none exists, or attaches to the one that does, so a person who deposits before ever signing up on MM2Empire and one who already has an account both resolve to the same place.

Wherever the API takes a customerRef it accepts any of four identifiers, all resolved within your company only: your own externalRef, the Roblox id, the Roblox username, or the customerId we returned. You cannot address a person you have not linked, and a person linked to another partner reads as not found in exactly the same words as one who does not exist.

Items and stacks#

Items are named by their catalogue id, itemValueId (for example chroma_luger). Because copies of one item are interchangeable, the API works in stacks: { itemValueId, quantity } for things a customer holds, and { itemValueId, priceCents, quantity } for things on the marketplace. You never see or name an individual copy.

Each item also has a catalogue value in cents (itemValueCents), which is the reference figure MM2 Payments prices are expressed against, and a rarity and type you can filter on.

Idempotency#

Every request that creates or moves something takes an Idempotency-Key header: a string of up to 128 characters that you generate, such as a UUID. Replaying a request with the same key returns the original response without doing the work again, so a timeout on your side is safe to retry.

SituationResult
Same key, same body, after the first finishedThe stored response is returned. Nothing runs twice.
Same key, different body409 idempotency_key_conflict. Use a new key for a new intent.
Same key while the first is still running409 idempotency_in_progress. Retry shortly.
No header on a route that needs one422 idempotency_key_required.

Keys are scoped to your company and the operation. On the two routes that move money for a customer (/payments/sell and /payouts/orders) they are scoped to the customer as well, so two of your users checking out the same basket with the same key never share a result.

Partial success is normal#

Both products buy and sell off a live market where a listing can disappear between a quote and a click. Requests that act on several items therefore report per-item outcomes rather than succeeding or failing as a whole: a basket may come back with three payments and two refusals, and that is the honest answer. Nothing is rolled back for a refused line, and you are only ever charged or credited for what landed.

Always render the response, not the request. The failed array carries a code and a message per item you can show your user.