Skip to main content

Partial Payments

A partial payment occurs when a customer sends less than the required invoice amount. Settlx keeps the invoice active and accepts additional payments until the full amount is received or the invoice expires.

How it works

  1. Customer sends 30 USDT against a $49.99 invoice
  2. Payment confirms on-chain → invoice.underpaid fires
  3. Invoice remains active — deposit address stays valid
  4. Customer sends another 20 USDT
  5. Combined total meets the invoice amount → invoice.confirmed fires
  6. Settlement proceeds normally → invoice.settled fires

The invoice.underpaid event

When the total received falls below the invoice amount, you receive an invoice.underpaid event:
{
  "event": "invoice.underpaid",
  "eventId": "evt_a1b2c3d4_invoice.underpaid_1744452600000",
  "timestamp": "2026-04-12T10:10:00.000Z",
  "data": {
    "invoice": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "amount": "49.99",
      "currency": "USD",
      "settlementCurrency": "USDT",
      "settlementChain": "polygon",
      "status": "pending",
      "createdAt": "2026-04-12T10:00:00.000Z",
      "metadata": { "orderId": "order_123" }
    },
    "payment": {
      "id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
      "transactionHash": "0xabc123...",
      "amount": "30.00",
      "currency": "USDT",
      "chain": "polygon",
      "confirmations": 12,
      "status": "confirmed"
    },
    "fees": {
      "platformFee": "0.45",
      "platformFeePercent": "1.5%",
      "networkFee": "0.50",
      "providerFee": "0.00",
      "totalFees": "0.95",
      "currency": "USDT"
    }
  }
}

Handling in your webhook

case 'invoice.underpaid': {
  const { invoice, payment } = event.data;
  const orderId = invoice.metadata?.orderId;

  const shortfall = (parseFloat(invoice.amount) - parseFloat(payment.amount)).toFixed(2);

  // Do not cancel — invoice stays open
  await db.orders.update({
    where: { id: orderId },
    data: { paymentStatus: 'partial' },
  });

  await emailService.sendPartialPaymentEmail({
    orderId,
    received: payment.amount,
    currency: payment.currency,
    shortfall,
  });

  break;
}

Multiple transactions

Customers can send multiple transactions to the same deposit address. Settlx automatically sums all confirmed payments against the invoice. You do not need to generate a new address or create a new invoice.

Exchange rate considerations

The crypto_amount shown at address generation reflects the exchange rate at that moment. If the customer sends a second transaction hours or days later, the exchange rate may have shifted.Settlx tracks the USD value of each confirmed payment. When the combined USD value meets or exceeds the invoice amount, the invoice is marked confirmed and settlement proceeds.

Invoice expiry with partial payments

If an invoice expires while underpaid:
  • An invoice.expired event fires
  • No automatic settlement is triggered for the partial amount
  • The deposit address becomes inactive
  • Contact Settlx support to manually process any funds already received
Set a generous expiry time when you expect partial or multi-transaction payments. For B2B invoices, 24 hours to 7 days is common.

Best practices

  • Do not create a new invoice for the remaining balance — the customer’s original deposit address is still valid
  • Notify customers promptly when a partial payment is received, showing the amount still needed
  • Set a sufficient expiry — 30–60 minutes for retail, longer for B2B
  • Show a countdown timer on your checkout page so customers know how long they have