Pay an invoice through the API
3 steps · Checked against the API code 3 November 2026
A guide does one task from start to finish. Every endpoint, with all its fields and cases, is in the API reference.
There are three ways to pay an invoice through the API. Charge the card saved on the account. Use account credit. Create a payment link for someone who pays in a browser. Each call returns the result at once. There is no job to follow.
Before you start
Section titled “Before you start”- An API key with the scope
write:billing. It also coversread:billing, which steps 1 and 3 need. Keys and scopes - The requests read the key from
$HOSTUP_API_KEY, as set in the Quickstart. - To pay by card: a card saved on the account. List payment methods shows it.
1. Find the invoice
Section titled “1. Find the invoice”Call GET /api/v2/billing/invoices with status=unpaid. That includes the overdue ones. Use status=overdue for only those past their due date. To find one invoice by its number, add searchQuery=202600001.
curl "https://cloud.hostup.se/api/v2/billing/invoices?status=unpaid&limit=20" \ -H "Authorization: Bearer $HOSTUP_API_KEY"{ "data": [ { "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3", "number": "202600001", "totals": { "currencyCode": "SEK", "outstanding": 249, "…": "…" }, "actions": { "canPay": { "allowed": true, "reason": null }, "canGeneratePaymentLink": { "allowed": true, "reason": null }, "…": "…" }, "paymentMethods": { "card": { "available": true, "…": "…" }, "accountCredit": { "available": true, "requirements": { "maximumAmount": { "amount": 249, "currencyCode": "SEK", "comparison": "less_than_or_equal" }, "…": "…" }, "…": "…" }, "…": "…" }, "isBulkPaymentChild": false, "bulkPaymentParentId": null, "…": "…" } ], "hasMore": false, "nextCursor": null}Keep the id of the invoice you want to pay:
export INVOICE_ID="inv_…" # data[].id of that invoiceWhen hasMore is true, send nextCursor as cursor for the next page. Pagination
actions.canPay says whether the invoice can be paid at all. Decide from it, not from status. When allowed is false, reason says why. Every way of paying is then blocked.
When canPay.allowed is true, three fields tell you which way of paying works for this invoice:
paymentMethods.card.available: the invoice can be paid by card in step 2. It isfalsewhen the balance is at or below the card minimum.reasonthen says so. Use account credit for such an invoice. This field does not say whether a card is saved. List payment methods does.paymentMethods.accountCredit.available: the account has credit in the invoice’s currency to use in step 2.requirements.maximumAmountis the most you can apply.actions.canGeneratePaymentLink.allowed: a payment link can be created in step 2. The payer then chooses among the methods the invoice allows.
If you placed an order
Section titled “If you placed an order”The order response has the invoice ID in invoice.id. Keep it:
export INVOICE_ID="inv_…" # invoice.id from the order responseGET /api/v2/billing/invoices/{id} returns that one invoice with the same actions and paymentMethods. Read it as in step 3.
If the invoice is part of another invoice
Section titled “If the invoice is part of another invoice”When isBulkPaymentChild is true, the invoice is already included in another invoice. bulkPaymentParentId is that invoice’s ID. Pay that invoice instead: put its ID in INVOICE_ID. canPay still says allowed for the included invoice. The pay calls accept it too. Paying it does not lower the other invoice. The same amount would then be asked for twice.
2. Pay the invoice
Section titled “2. Pay the invoice”Pick one of the ways below. Step 1 shows which ones this invoice allows.
| Way | Use it when |
|---|---|
| Let the automatic card charge pay it | A card is saved and payment on the due date is early enough. |
| With the saved card | You want it paid now and paymentMethods.card.available is true. |
| With account credit | paymentMethods.accountCredit.available is true. |
| With a payment link | Someone else pays in a browser. Also when the bank asks for 3-D Secure. |
Let the automatic card charge pay it
Section titled “Let the automatic card charge pay it”Call GET /api/v2/billing/unpaid-summary. It adds up what is owed. It also says whether automatic card payment will settle the invoices on their due date.
curl "https://cloud.hostup.se/api/v2/billing/unpaid-summary" \ -H "Authorization: Bearer $HOSTUP_API_KEY"{ "totalAmount": 249, "currencyCode": "SEK", "count": 1, "invoices": [ { "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3", "number": "202600001", "amount": 249, "dueStatus": "upcoming", "daysUntilDue": 9, "…": "…" } ], "autoCharge": { "enabled": true, "status": "scheduled", "scheduledAt": "2026-11-11T19:00:00.000Z", "failureKind": null, "…": "…" }, "…": "…"}autoCharge.statusscheduled: the saved card is charged automatically atscheduledAt, 20:00 Swedish time on the earliest due date. Pay now only if you want the invoice settled earlier.autoCharge.statusfailed: an invoice is past due and the automatic charge did not go through.failureKindsays why. Pay it another way below.autoCharge.statusoff: automatic card payment is turned off or no card is saved. Nothing is charged until you pay.
With the saved card
Section titled “With the saved card”Call POST /api/v2/billing/invoices/{id}/actions/pay. Send {} to charge the whole outstanding amount to the saved card. To pay part of the balance, send amount in the invoice’s currency. It cannot be more than what is outstanding. It must also be above the card minimum in paymentMethods.card.requirements.minimumAmount.
curl -X POST "https://cloud.hostup.se/api/v2/billing/invoices/$INVOICE_ID/actions/pay" \ -H "Authorization: Bearer $HOSTUP_API_KEY" \ -H "Content-Type: application/json" \ -d '{}'{ "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3", "number": "202600001", "status": "paid", "dates": { "paidAt": "2026-11-02T10:15:41.000Z", "…": "…" }, "totals": { "currencyCode": "SEK", "amountPaid": 249, "outstanding": 0, "…": "…" }, "…": "…"}After a part payment, totals.outstanding shows what is left.
A 502 upstream_invoice_shape_invalid means the card was charged but the updated invoice could not be read. Read it as in step 3. Do not pay again.
A charge the bank refuses returns 400 payment_failed. Errors you may hit says what to do for each reason.
If the bank asks for 3-D Secure
Section titled “If the bank asks for 3-D Secure”The response is 400 payment_failed with paymentFailure.kind authentication_required. The bank wants the card holder to confirm the payment. A charge sent from your server cannot do that. Send a payment link instead. The card holder then pays in the browser, where that confirmation can take place.
With account credit
Section titled “With account credit”Call POST /api/v2/billing/invoices/{id}/actions/apply-credit. Send the amount of credit to apply. It must be more than zero. paymentMethods.accountCredit.requirements.maximumAmount from step 1 is the highest amount that works.
curl -X POST "https://cloud.hostup.se/api/v2/billing/invoices/$INVOICE_ID/actions/apply-credit" \ -H "Authorization: Bearer $HOSTUP_API_KEY" \ -H "Content-Type: application/json" \ -d '{"amount": 249}'{ "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3", "number": "202600001", "status": "paid", "totals": { "currencyCode": "SEK", "creditApplied": 249, "outstanding": 0, "…": "…" }, "…": "…"}When the credit covers only part of the invoice, the rest stays unpaid. Pay it with the card or a payment link.
With a payment link
Section titled “With a payment link”Call POST /api/v2/billing/invoices/{id}/actions/generate-payment-link. A payment link lets someone pay without an API key or a login, for example a colleague with the company card. Send the request with no body.
curl -X POST "https://cloud.hostup.se/api/v2/billing/invoices/$INVOICE_ID/actions/generate-payment-link" \ -H "Authorization: Bearer $HOSTUP_API_KEY" \ -H "Content-Type: application/json"{ "paymentUrl": "https://cloud.hostup.se/billing/pay/550e8400-e29b-41d4-a716-446655440000", "expiresAt": "2026-12-02T10:15:41.000Z", "invoice": { "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3", "number": "202600001", "amount": 249, "currencyCode": "SEK", "dueAt": "2026-11-11T00:00:00.000Z", "status": "unpaid", "paymentUrl": "https://cloud.hostup.se/billing/pay/550e8400-e29b-41d4-a716-446655440000" }}Send paymentUrl to the payer yourself. Hostup does not e-mail it. The page shows the invoice with its lines and the ways it can be paid, such as card or Swish. A card used on the page is not saved on the account. Anyone who has the link can open it. Share it only with the payer.
This paymentUrl is a full URL. The invoice.paymentUrl in an order response is not: it is a path on https://cloud.hostup.se.
invoice.amount is the invoice total, not what is still owed. The page asks only for the outstanding amount. To tell the payer how much to pay, use totals.outstanding from step 1.
The link works for 30 days, until expiresAt. Asking again while a link is active returns the same link. The link stops working when the invoice is paid.
3. Confirm that the invoice is paid
Section titled “3. Confirm that the invoice is paid”Read the invoice with GET /api/v2/billing/invoices/{id} and skipCache=1. skipCache=1 makes sure you get its current payment state. After a payment link, poll it every few minutes until the payer has paid.
curl "https://cloud.hostup.se/api/v2/billing/invoices/$INVOICE_ID?skipCache=1" \ -H "Authorization: Bearer $HOSTUP_API_KEY"{ "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3", "number": "202600001", "status": "paid", "dates": { "paidAt": "2026-11-02T10:15:41.000Z", "…": "…" }, "totals": { "outstanding": 0, "…": "…" }, "payments": [ { "kind": "payment", "method": "card", "methodLabel": "Card", "amount": 249, "currencyCode": "SEK", "at": "2026-11-02T10:15:41.000Z" } ], "…": "…"}status paid and totals.outstanding 0 mean the invoice is settled. payments lists each payment with its method.
What happens next
Section titled “What happens next”Once the invoice is paid, Hostup carries out what it was for. A new order is set up: Order a VPS and Register a domain show how to follow it. A renewal moves the service’s next due date forward. A paid upgrade, IP change or extra bandwidth is applied. A Cloud VPS that was paused over unpaid invoices comes back when every invoice behind the pause is paid.
Errors you may hit
Section titled “Errors you may hit”-
400
payment_failed: the card was not charged.detailgives the reason. Don’t retry the same card in a loop.paymentFailure.kindsays what to do:card_declined,card_expiredorcard_missing: save a new card in the client area and pay again.insufficient_funds: try again later. A payment link also works.authentication_required: send a payment link (3-D Secure).unknown: readdetail. It may be theamount, not the card. Anamountabove the balance or at or below the card minimum gives this kind.
The card payment also uses this code with status
409when the invoice changed during the call. With status503, the invoice could not be read. Read the invoice again before you pay. A decline from this call is reported only in the response. Hostup normally sends no card-decline e-mail for it. -
502
upstream_invoice_shape_invalid: the payment or credit went through. Reading the updated invoice afterwards failed. Do not pay again. Read the invoice as in step 3. -
409
payment_method_invalid: the account has no saved card. The same code comes back when the card insavedCardIdno longer exists. The response haspaymentLinkGeneratorUrl, the path of the payment-link call for this invoice. POST to it as shown under With a payment link. You can also save a card in the client area first. -
409
invoice_payment_in_progress: a payment of this invoice is already running. Wait a moment. Read the invoice before you try again. It may be paid already. A paid invoice returns409invoice_already_paid. -
409
invoice_not_payable: from account credit, the invoice is in another currency than the account. The same code comes for an invoice that adds funds to the account credit.detailsays which. -
400
invalid_request: the body is wrong. The usual causes are a field the call does not take, anamountthat is not a positive number and asavedCardIdthat is not a card on this account. Account credit also needsamount. For the card payment,detaillists every rule at once. It does not say which one failed. For account credit,errors[0].pointernames the field. There,errors[0].codeamount_exceeds_available_creditoramount_exceeds_invoice_balancemeansamountis too high. Lower it topaymentMethods.accountCredit.requirements.maximumAmount.
Next: Order a VPS