Guides
Check Payment Status
How to verify payment status and handle the invoice callback.
Check Payment Status
After creating a payment, you need to know when it's completed. iPint uses webhooks + polling to keep you informed.
The flow
- iPint sends a callback to your
invoice_callback_urlwhen status changes - You call
GET /invoiceto verify the actual status (don't trust the callback body) - You mark the payment based on the
transaction_statusin the response
Calling GET /invoice
const response = await fetch(
`https://api.ipint.io:8003/invoice?invoice_id=${invoiceId}`
);
const invoice = await response.json();
// Check transaction_status
if (invoice.transaction_status === "COMPLETED") {
// Payment successful — fulfill the order
} else if (invoice.transaction_status === "FAILED") {
// Payment failed — cancel the order
} else {
// Still processing — wait for the next callback
}transaction_status values
| Status | Meaning | Action |
|---|---|---|
CHECKING | Checking for transaction on blockchain | Wait |
PROCESSING | Transaction hit blockchain, confirmations < 3 | Wait |
COMPLETED | Transaction completed | Mark successful. Stop querying. |
FAILED | Customer didn't pay, or transaction not included in a block | Mark failed. Stop querying. |
CANCELLED | Customer closed before QR was generated | Mark cancelled. Stop querying. |
If you get COMPLETED, FAILED, or CANCELLED, do not query further. These
are terminal states.
Verifying full payment
Sometimes invoices are underpaid or overpaid. Always compare the invoice amounts with the received amounts before giving credit:
const isFullyPaid =
invoice.received_amount_in_usd >= invoice.invoice_amount_in_usd &&
invoice.received_crypto_amount >= invoice.invoice_crypto_amount;| Compare | With |
|---|---|
invoice_amount_in_local_currency | received_amount_in_local_currency |
invoice_amount_in_usd | received_amount_in_usd |
invoice_crypto_amount | received_crypto_amount |
Handling the callback
app.post("/webhook", (req, res) => {
const { invoice_id } = req.body;
// 1. Respond 200 immediately
res.status(200).send();
// 2. Verify via GET /invoice (don't trust the callback body)
verifyInvoice(invoice_id).then((invoice) => {
switch (invoice.transaction_status) {
case "COMPLETED":
fulfillOrder(invoice_id);
break;
case "FAILED":
cancelOrder(invoice_id);
break;
case "CANCELLED":
markCancelled(invoice_id);
break;
}
});
});Callback security notes
- iPint does not send signed requests — do not trust the callback body.
- Use it only as a trigger to call
GET /invoice. - Do not whitelist iPint's IP addresses (they change without notice).
- Use HTTPS for your callback URL.
- Respond with HTTP 200 + empty body. Any other response = failed delivery.
Next steps
- GET /invoice reference — full response schema
- Webhooks reference — callback payload
- Go to Production — production checklist