Skip to content

Pay one of your invoices by card

The portal.invoices.pay operation: POST /api/v1/portal/me/invoices/{invoiceId}/pay in the REST API and the portal_invoices_pay tool in the MCP server.

POST/api/v1/portal/me/invoices/{invoiceId}/pay

Starts a card payment of one of the signed-in customer's open invoices, for its amount due, at the brand's processor: a one-off payment (no card is saved). expectedAmount is the amount due the customer saw; if it changed meanwhile, the payment is refused.

  • fake processor: the payment is confirmed here with the chosen test card (paymentMethod): succeeded, processing, requires_action (pay again to pass the fake 3-D Secure challenge) or a decline;
  • Stripe: the answer is client_confirm with the Payment Element's clientSecret; the browser confirms;
  • Mollie: the answer is redirect with redirectUrl, Mollie's payment page; the customer comes back to the invoice's hosted page.

The invoice is marked paid when the processor's webhook confirms the payment: read it again with portal.invoices.get. Customer portal only (portal:write).

At a glance

  • REST: POST /api/v1/portal/me/invoices/{invoiceId}/pay
  • MCP tool: portal_invoices_pay
  • Operation ID: portal.invoices.pay
  • Scope: Brand
  • Permission: portal:write
  • Risk tier: financial
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: A customer signed in to the customer portal (API keys can't call it)
  • Since: M9

Request

Path parameters

FieldTypeDescription
invoiceIdinv_… IDOne of your invoices (inv_…).

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
expectedAmountobjectYesThe amount due you saw; if it changed meanwhile, the payment is refused (invoice_payment_unavailable).
expectedAmount.amountstringYesInteger micros as a string.
expectedAmount.currencystringYes
paymentMethodstringNoFake processor only (development, CI): the test card, e.g. pm_fake_visa.

Response

200 OK with a JSON object:

FieldTypeDescription
object"hosted_invoice_payment"
invoiceIdinv_… ID
outcomeone of succeeded, processing, requires_action, client_confirm, redirectsucceeded (the invoice is marked paid when the processor's webhook arrives), processing, requires_action (confirm again: a fake 3-D Secure challenge), client_confirm (Stripe: confirm in the Payment Element with clientSecret) or redirect (Mollie: send the buyer to redirectUrl; they come back to the invoice page).
amountmoney
clientSecretstring or null
publishableKeystring or null
redirectUrlstring or null

Examples

Pay with a fake test card

HTTP
POST /api/v1/portal/me/invoices/inv_01m4tx5nj8emwbyf7y9vcf48b3/pay
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "expectedAmount": {
    "amount": "1200000000",
    "currency": "EUR"
  },
  "paymentMethod": "pm_fake_visa"
}

Response (200):

JSON
{
  "object": "hosted_invoice_payment",
  "invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf48b3",
  "outcome": "succeeded",
  "amount": {
    "amount": "1200000000",
    "currency": "EUR"
  },
  "clientSecret": null,
  "publishableKey": null,
  "redirectUrl": null
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400The invoice's ID or another field is malformed.Fix the fields listed in details.issues and send the request again.
resource_not_found404You have no such invoice (another customer's reads the same).Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
invoice_payment_unavailable409The invoice is paid or voided, has nothing due, its amount due changed, or the brand has no processor.The invoice is paid, voided or has nothing due, or the brand has no processor connection: check details.reason. Pay by bank transfer with the details on the invoice, or ask the seller.
processor_payment_declined502The card was declined; try another card or a bank transfer.Ask the customer for another payment method; details.decline_code says why the card was declined.
processor_request_failed502The processor couldn't create or confirm the payment; try again.If retryable is true, retry with the same Idempotency-Key after a short wait; otherwise check details.code.
livemode_not_allowed403The portal session is in the other mode than the request.Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin.
permission_denied403The caller isn't a customer signed in to this brand's portal (operators and API keys use the customer operations).Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, rate_limited, internal_error.