Migrate from the Legacy API
Move a Magma integration from the deprecated api.amboss.space endpoint to magma.amboss.tech/graphql. Operation-by-operation mapping for buyers and sellers.
The old Magma operations on https://api.amboss.space/graphql are deprecated. Everything Magma-related now lives on its own endpoint:
https://magma.amboss.tech/graphqlThis page maps every legacy operation to its replacement so you don't have to guess.
The legacy seller accept path is no longer reliable. If you sell liquidity, migrate sellerAcceptOrder first.
What stays the same
- Your API key. Keys minted at account.amboss.tech/settings/api-keys work on both endpoints. Same
Authorization: Bearerheader, no re-issuing needed. - Order IDs and offer IDs. Same UUIDs, same records. An order created on the legacy API can be finished on the new one.
- Order statuses. The
MarketOrderStatusenum has the same 17 values as the legacyOrderStatus, with the same names.
What changes shape
- Operations are namespaced. Instead of a flat
sellerAcceptOrder, you traversemarket.order.seller.accept. Queries hang offmarket,user, andnode. - Arguments moved into
inputobjects. LegacysellerAcceptOrder(id:, request:)becomesaccept(input: { order_id, payment_request }). - Mutations return objects, not
Boolean. Most return{ success }, so you select a field instead of reading a bare boolean. - Lists are paginated. Anything returning a list takes
page: { limit, offset }and returns{ list, total, pagination }. - Sizes are strings.
sizeon order creation is aString, not aFloat.
Seller operations
| Legacy | New | Notes |
|---|---|---|
sellerAcceptOrder(id, request) | market.order.seller.accept(input) | input: { order_id, payment_request }. Still a BOLT11 HODL invoice, still needs at least 48 hours of expiry. See Sell Liquidity. |
sellerRejectOrder(id) | market.order.seller.reject(input) | input: { order_id }. |
sellerAddTransaction(id, transaction) | market.order.seller.add_transaction(input) | input: { order_id, tx_id }. The field is named tx_id but the format is unchanged: TXID:OUTPUT_INDEX, for example 5e8a3f...c4f1:0. See Sell Liquidity. |
createOffer(input) | market.offer.create(input) | pubkey and min_block_length are now required. offer_side and offer_type are gone. See Create Offers. |
updateOffer(input) | market.offer.update(input) | offer is now offer_id, and total_size is optional. |
toggleOffer(id) | market.offer.toggle(input) | input: { offer_id }. |
getUserOffers / getUser.market.offers | user.market.offers.offers(page) | Paginated. |
getUser.market.orders(status) | user.market.orders.sales(input, page) | The legacy query mixed both sides of the book. sales is your seller orders, purchases is your buyer orders. |
getUser.market.pending_seller_orders | user.market.orders.sales(input: { action_needed: true }).total | Close, not identical. action_needed means WAITING_FOR_SELLER_APPROVAL, WAITING_FOR_CHANNEL_OPEN, and SELLER_SENT_TRANSACTION. The legacy count also included WAITING_FOR_ON_CHAIN_CONFIRMATION, where the seller has nothing left to do. Pass an explicit status list if you need the old set. |
getOfferOrders(id) / getUser.market.offer_orders(id) | user.market.offers.get_offer(offer_id).orders(page) | Orders grouped under one of your offers. |
Finding your own sales was the most common migration question, so here it is in full:
query MySales {
user {
market {
orders {
sales(input: { action_needed: true }, page: { limit: 25, offset: 0 }) {
total
list {
id
status
amount { satoshi { sats } }
destination { pubkey alias }
}
}
}
}
}
}Buyer operations
| Legacy | New | Notes |
|---|---|---|
createOrder(input) | market.order.create(input) | offer is now offer_id, and size is a String. Returns the order, not a boolean. |
cancelOrder(id, reason) | market.order.cancel(input) | input: { order_id, cancellation_reason }. See Errors. |
getOrder(id) | user.market.orders.get_order(order_id) | Moved under user. Access rules are unchanged: you must be a side of the order. See Tracking Orders. |
getUser.market.orders(status) | user.market.orders.purchases(input, page) | Buyer side of the split described above. |
getUser.market.pending_buyer_orders | user.market.orders.purchases(input: { action_needed: true }).total | Close, not identical. action_needed here means WAITING_FOR_BUYER_PAYMENT only. Pass an explicit status list if you need the old set. |
There is also a new one-shot buy flow, liquidity.buy, which picks a matching offer for you and works without an account. See Buy Liquidity.
Marketplace and account operations
| Legacy | New | Notes |
|---|---|---|
getOffers(...) | market.offer.offers(page) | Public, no credentials. Paginated. |
getOffer(id) | market.offer.get_offer(offer_id) | Public. |
getBitcoinTxInfo(txId) | market.transaction.get_outputs(tx_id) | Returns the outputs of a transaction, which is what you need to pick the channel output index. |
getSignInfo | node.identifier_info | The signing challenge for linking a node. |
addNewPubkeyToAccount(identifier, signature) | account.node.connect(input) | input: { identifier, signature }. |
getUser (nodes, email, telegram) | user | Root field, no get prefix. |
Fields that did not move
Some fields on the legacy OrderType have no equivalent on MarketOrder. Here is where each one stands and what you can use instead.
| Legacy field | Status | What to use instead |
|---|---|---|
payment_hash | Not exposed | It is the payment hash of the BOLT11 invoice you supplied in accept, so you already have it. It is also the hash of payment.lightning.invoice, which you can decode. |
updated_at | Not exposed | created_at is still there. For change detection, compare status and payment_status between polls. |
is_automated | Not exposed | No replacement. |
chat_enabled | Gone | There is no order messaging on the new API at all. |
cancellation_reason | Write only | You pass it in market.order.cancel(input), but you cannot read it back off an order. |
seller_close_side / buyer_close_side | Not exposed | No replacement today. See the note below. |
fee_above_cap_seconds | Not exposed | No replacement. |
closed_blocks_before_min | Not exposed | blocks_until_can_be_closed covers the forward-looking version: how many blocks are left before you may close the channel. |
locked_fee_rate / locked_base_fee | Exposed as amounts | See Fee fields changed meaning. |
messages | Gone | No order messaging on the new API. |
buyer_scores | Not exposed | No replacement. |
seller_close_side and buyer_close_side are the only way to tell whether a channel was closed early by the buyer rather than by the seller, which matters for reviewing sales quality. If your integration depends on them, tell us at [email protected] so we can weigh adding them back.
Fee fields changed meaning
This one bites if you skim it, because the names look similar but the units are not.
| Legacy | New | Unit |
|---|---|---|
amboss_fee_rate | not fees.amboss | Legacy was a ppm rate. New fees.amboss is the Amboss fee amount in sats for that order. Different field, different unit. |
fixed_fee | fees.fixed | Same value. Your agreed base fee, in sats. |
variable_fee | fees.variable | Same value, in sats. Your agreed rate applied to the order size. |
seller_invoice_amount | fees.seller | What you get paid, in sats. See the caveat below. |
buyer_invoice_amount | fees.buyer | What the buyer pays, in sats. See the caveat below. |
locked_fee_rate | not exposed | The rate itself isn't exposed, only the sats it produced. For accounting, use the amounts. |
locked_base_fee | fees.fixed | Same value. |
Every field under MarketOrderFees is a SatoshiValue, so it is an amount, never a rate. Select sats for the number and historical_usd if you want the USD value at the time of the order.
fees.seller and fees.buyer read the final settled amounts. They return 0 on an order that has not settled yet, where the legacy seller_invoice_amount fell back to a computed estimate. Do not treat a 0 as "this sale earned nothing", check status first.
Deprecation timeline
The Magma operations on the legacy endpoint are deprecated and will be removed. No date is set yet, and we will give notice here before anything is switched off, but plan for it going away rather than treating it as a supported option.
It is also no longer actively maintained, so bugs in it will not be fixed. The seller accept path has already been unreliable there. Migrate seller mutations first.
No replacement yet
These legacy operations have no equivalent on the new API. Tell us at [email protected] if your integration depends on one.
sendMagmaMessage(orderId, msg)- messaging a counterparty about an order.setOrderCloseSide(orderId, closedBy)- declaring which side closed the channel.getOfferRecommendations(channelSize)- server-side offer matching. Usemarket.offer.offersand filter yourself, or letliquidity.buydo the matching.getUser.market.pubkey_reputations- per-pubkey reputation scores.
Next steps
- API Reference - the full operation index for the new endpoint.
- Sell Liquidity - the seller flow end to end.
- Apollo Studio Explorer - run the new operations against the live schema.