Get API key

Pay with USDT

Let a customer pay a Lightning receive with USDT on Tron. One public mutation gives them a deposit address, and the receive settles like any other.

A customer who holds USDT on Tron can pay a receive without a Lightning wallet. public.create_swap gives them a Tron deposit address and an exact amount. When the USDT arrives, it's swapped and pays the receive's Lightning invoice. You still get bitcoin in your wallet, and the receive completes with the usual webhooks.

The mutation needs no API key, because the customer is the one paying. All it needs is the receive's ID.

Rules

  • Tron USDT only for now. Send source_chain: "tron" and source_asset: "USDT".
  • Live BTC receives only. The receive must be on a BTC wallet in a live environment, still PENDING, and not expired.
  • Exact amount. The customer sends exactly amount_in, before expires_at. Their wallet adds the Tron network fee on top.
  • Refunds. If the USDT arrives late or short, it goes back to refund_address, a Tron address the customer owns.

Start a swap

public.create_swap(input: CreateSwapInput) → Swap

FieldTypeRequiredNotes
transaction_idUUIDyesThe receive to pay
source_chainstringyes"tron"
source_assetstringyes"USDT"
refund_addressstringyesThe customer's Tron address, for late or short payments
mutation CreateSwap {
  public {
    create_swap(input: {
      transaction_id: "b2c4e6a8-1d3f-4b5a-9c7e-0f2a4c6e8b1d"
      source_chain: "tron"
      source_asset: "USDT"
      refund_address: "TCustomerRefundAddress111111111111"
    }) {
      deposit_address
      deposit_memo
      amount_in
      expires_at
    }
  }
}
curl -X POST https://app.amboss.tech/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation($input: CreateSwapInput!) { public { create_swap(input: $input) { deposit_address deposit_memo amount_in expires_at } } }",
    "variables": {
      "input": {
        "transaction_id": "b2c4e6a8-1d3f-4b5a-9c7e-0f2a4c6e8b1d",
        "source_chain": "tron",
        "source_asset": "USDT",
        "refund_address": "TCustomerRefundAddress111111111111"
      }
    }
  }'

Example response:

{
  "data": {
    "public": {
      "create_swap": {
        "deposit_address": "TDepositAddress1111111111111111111",
        "deposit_memo": null,
        "amount_in": "20123456",
        "expires_at": "2026-11-12T14:05:00.000Z"
      }
    }
  }
}

amount_in is in USDT's smallest unit. USDT on Tron has 6 decimals, so "20123456" is 20.123456 USDT. Show the customer deposit_address and the amount, and tell them to send before expires_at. If deposit_memo isn't null, they must add it to the transfer.

Calling it again with the same refund_address gives back the same address while it has more than a minute left. So a retry or a double click never shows the customer two addresses.

Limits

  • 10 calls a minute from one IP address.
  • 5 new deposit addresses a minute for one receive. Calls that give back an open address don't count.

Over a limit, the call fails with TOO_MANY_REQUESTS. Wait a minute and try again.

Errors

extensions.codeMeaning
BAD_REQUESTAn input is missing or invalid, or the chain and asset aren't tron and USDT.
NOT_FOUNDNo payable receive with this ID: it doesn't exist, isn't PENDING, has expired, or isn't on a live BTC wallet.
CONFLICTA USDT payment for this receive is already on its way, so don't start another. Or another call is creating an address right now: try again in a moment.
TOO_MANY_REQUESTSOver a limit.

Next steps