Skip to content
Documentation menu

API reference

The Vitix Pay API is a predictable REST API: resource-oriented URLs, JSON request and response bodies, standard HTTP status codes and bearer authentication. Base URL: https://api.vitix.net.

Authentication

Authenticate every request with your secret key in the Authorization header. Keys starting with vx_test_ act on test data; vx_live_ keys on live data. Never expose a key in client-side code, mobile apps or public repositories. Requests without a valid key return 401; requests from a suspended account return 403.

bash
curl https://api.vitix.net/v1/account \  -H "Authorization: Bearer vx_test_••••••••"

Versioning & request ids

Every response carries vitix-version (currently 2026-10-01) and a unique request-id (req_…). Include the request id when you contact support; it is also in the body of every error. Backwards-incompatible changes ship under a new version date; additive changes (new fields, new event types, new enum values) can appear at any time, so parse defensively.

Idempotency

Add an Idempotency-Key header (any string up to 255 characters, typically a UUID or your own order id) to POST requests. The first response for a key is stored for 24 hours and returned verbatim for identical retries, with the header idempotent-replayed: true. Reusing a key with a different path or payload fails with idempotency_error. Keys are scoped to your account and mode.

bash
curl https://api.vitix.net/v1/checkouts \  -H "Authorization: Bearer vx_live_••••••••" \  -H "Content-Type: application/json" \  -H "Idempotency-Key: 9c1f7f8e-6b0c-4c87-9b4a-2b1d0a3e5f10" \  -d '{ "amount": 2000, "success_url": "https://app.example.com/ok" }'

Pagination

List endpoints return a list object with newest items first. Pass limit (1–100, default 20) and starting_after (the id of the last item you received) to fetch the next page while has_more is true.

json
{  "object": "list",  "data": [    {      "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",      "object": "payment",      "livemode": true,      "status": "succeeded",      "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",      "amount": 600000,      "currency": "vnd",      "amount_usd": 2308,      "fee_usd": 132,      "net_usd": 2176,      "refunded_usd": 0,      "description": "Acme credits",      "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },      "reference": "topup_8f1c",      "metadata": { "plan": "pro" },      "invoice_available": true,      "created_at": "2026-10-14T06:35:02.410Z"    }  ],  "has_more": false}

Amounts & currencies

Amounts are integers in the smallest unit: 2000 is $20.00 when currency is usd; 600000 is 600.000 ₫ when it is vnd. Customers are always charged in USD; VND requests are converted at 26,000 ₫ per USD and the charged figure is returned as amount_usd, alongside fee_usd and net_usd on payments. Live checkouts must be at least $10.00; the maximum per checkout is set on your account (GET /v1/account).

Currencyamount meansExample
usdUS cents2000 → $20.00
vndVietnamese đồng600000 → 600.000 ₫ ≈ $23.08

Rate limits

Each API key may make 100 requests per 10 seconds. Beyond that the API returns 429 with rate_limit_error; back off and retry with jitter. Webhooks are not subject to this limit.

Errors

Errors use conventional status codes and a single error object with a stable code you can branch on. The full list is on the Errors page.

400 Bad Request
{  "error": {    "type": "invalid_request_error",    "code": "amount_too_small",    "message": "Amount is below the minimum of $10.00 (≈ 260,000 VND).",    "param": "amount",    "request_id": "req_dCjruuTgsXzq3EwlIAWS"  }}

Checkouts

A checkout is a one-time payment attempt: it fixes an amount and a customer, exposes a hosted page where the customer pays, and turns into a payment when the money arrives. Create one per top-up; never reuse a checkout across customers.

The checkout object

Attributes

idstring
Unique id, prefixed cs_live_ or cs_test_.
objectstring
Always checkout.
livemodeboolean
Whether this is a live or test checkout.
statusenum
open while payable, complete once paid, expired after expires_at or an explicit expire call.
payment_statusenum
unpaid or paid.
amountinteger
The amount you requested, in the minor unit of currency (cents for usd, đồng for vnd).
currencyenum
usd or vnd.
amount_usdinteger
What the customer is charged, in USD cents. Equal to amount for usd; converted at 26,000 ₫/USD for vnd.
descriptionstring | null
Shown on the hosted page.
customerobject | null
The customer you passed.
Child attributes
idstring
Your own identifier for the paying user (max 128 chars). Echoed on the payment and usable as a list filter.
emailstring
Pre-fills the email on the hosted checkout and goes on the invoice. Strongly recommended.
namestring
Display name (max 120 chars).
referencestring | null
Your own reference (order id, invoice number). Copied to the payment.
metadataobject
Up to 20 string key/value pairs you attached. Copied to the payment.
success_urlstring
Your own success page, stored for your records. Vitix does not redirect the customer there.
cancel_urlstring | null
Stored for your records; the hosted page shows no link to your site.
urlstring
The Vitix-hosted checkout page (vitix.net/pay?cs=…). Redirect the customer here or open it in a popup window.
paymentstring | null
Id of the payment once paid.
expires_attimestamp
ISO 8601. The page stops accepting payment after this.
completed_attimestamp | null
When the payment succeeded.
created_attimestamp
ISO 8601.
The checkout object
{  "id": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "object": "checkout",  "livemode": true,  "status": "open",  "payment_status": "unpaid",  "amount": 600000,  "currency": "vnd",  "amount_usd": 2308,  "description": "Acme credits",  "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },  "reference": "topup_8f1c",  "metadata": { "plan": "pro" },  "success_url": "https://app.example.com/billing/success?cs={CHECKOUT_ID}",  "cancel_url": "https://app.example.com/billing",  "url": "https://vitix.net/pay?cs=cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "payment": null,  "expires_at": "2026-10-14T07:32:45.000Z",  "completed_at": null,  "created_at": "2026-10-14T06:32:45.156Z"}

Create a checkout

POST/v1/checkouts

Creates a checkout and the hosted page behind its url. Amount limits and the domain allow-list are validated before anything is created, so a 400 here has no side effects.

Parameters

amountintegerrequired
Positive integer in the minor unit of currency.
currencyenum
usd (default) or vnd.
success_urlstringrequired
Absolute https URL on one of your allowed domains (http://localhost is accepted in test mode). Stored on the checkout for your records; the customer is not redirected there.
cancel_urlstring
Absolute URL stored for your records; not shown on the hosted page.
customerobject
Who is paying.
Child attributes
idstringrequired
Your own identifier for the paying user (max 128 chars). Echoed on the payment and usable as a list filter.
emailstring
Pre-fills the email on the hosted checkout and goes on the invoice. Strongly recommended.
namestring
Display name (max 120 chars).
descriptionstring
Up to 200 characters, shown on the hosted page.
referencestring
Up to 128 characters. Your own id, copied to the payment and filterable on lists.
metadataobject
Up to 20 keys (40 chars) with string values (500 chars). Copied to the payment.
expires_ininteger
Seconds until the checkout expires, 300–86400. Default 3600.

Returns

The new checkout with status: "open". HTTP 201.

curl -X POST https://api.vitix.net/v1/checkouts \  -H "Authorization: Bearer vx_live_••••••••" \  -H "Content-Type: application/json" \  -H "Idempotency-Key: topup_8f1c" \  -d '{    "amount": 600000,    "currency": "vnd",    "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },    "description": "Acme credits",    "reference": "topup_8f1c",    "metadata": { "plan": "pro" },    "success_url": "https://app.example.com/billing/success?cs={CHECKOUT_ID}",    "cancel_url": "https://app.example.com/billing"  }'
Response
{  "id": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "object": "checkout",  "livemode": true,  "status": "open",  "payment_status": "unpaid",  "amount": 600000,  "currency": "vnd",  "amount_usd": 2308,  "description": "Acme credits",  "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },  "reference": "topup_8f1c",  "metadata": { "plan": "pro" },  "success_url": "https://app.example.com/billing/success?cs={CHECKOUT_ID}",  "cancel_url": "https://app.example.com/billing",  "url": "https://vitix.net/pay?cs=cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "payment": null,  "expires_at": "2026-10-14T07:32:45.000Z",  "completed_at": null,  "created_at": "2026-10-14T06:32:45.156Z"}

Retrieve a checkout

GET/v1/checkouts/:id

Typically called from your success page. Check payment_status; if it is still unpaid the webhook has not landed yet, so show a pending state rather than an error.

Returns

The checkout object, or 404 if the id does not exist in this account and mode.

curl https://api.vitix.net/v1/checkouts/cs_live_0aWdSNgZbvGU0BjvCISLh07o \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "object": "checkout",  "livemode": true,  "status": "complete",  "payment_status": "paid",  "amount": 600000,  "currency": "vnd",  "amount_usd": 2308,  "description": "Acme credits",  "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },  "reference": "topup_8f1c",  "metadata": { "plan": "pro" },  "success_url": "https://app.example.com/billing/success?cs={CHECKOUT_ID}",  "cancel_url": "https://app.example.com/billing",  "url": "https://vitix.net/pay?cs=cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "expires_at": "2026-10-14T07:32:45.000Z",  "completed_at": "2026-10-14T06:35:02.410Z",  "created_at": "2026-10-14T06:32:45.156Z"}

List checkouts

GET/v1/checkouts

Query parameters

statusenum
open, complete or expired.
customerstring
Only checkouts for this customer id.
limitinteger
1–100, default 20.
starting_afterstring
Cursor: the last id of the previous page.

Returns

A list object of checkouts, newest first.

curl https://api.vitix.net/v1/checkouts?customer=user_42&limit=10 \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",      "object": "checkout",      "livemode": true,      "status": "open",      "payment_status": "unpaid",      "amount": 600000,      "currency": "vnd",      "amount_usd": 2308,      "description": "Acme credits",      "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },      "reference": "topup_8f1c",      "metadata": { "plan": "pro" },      "success_url": "https://app.example.com/billing/success?cs={CHECKOUT_ID}",      "cancel_url": "https://app.example.com/billing",      "url": "https://vitix.net/pay?cs=cs_live_0aWdSNgZbvGU0BjvCISLh07o",      "payment": null,      "expires_at": "2026-10-14T07:32:45.000Z",      "completed_at": null,      "created_at": "2026-10-14T06:32:45.156Z"    }  ],  "has_more": false}

Expire a checkout

POST/v1/checkouts/:id/expire

Closes an open checkout early, for example when the customer cancels the order in your product. Emits checkout.expired.

Returns

The checkout with status: "expired". Fails with checkout_not_open if it is already complete or expired.

curl -X POST https://api.vitix.net/v1/checkouts/cs_live_0aWdSNgZbvGU0BjvCISLh07o/expire \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "object": "checkout",  "livemode": true,  "status": "expired",  "payment_status": "unpaid",  "amount": 600000,  "currency": "vnd",  "amount_usd": 2308,  "description": "Acme credits",  "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },  "reference": "topup_8f1c",  "metadata": { "plan": "pro" },  "success_url": "https://app.example.com/billing/success?cs={CHECKOUT_ID}",  "cancel_url": "https://app.example.com/billing",  "url": "https://vitix.net/pay?cs=cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "payment": null,  "expires_at": "2026-10-14T07:32:45.000Z",  "completed_at": null,  "created_at": "2026-10-14T06:32:45.156Z"}

Payments

A payment is money that actually arrived. Payments are created by Vitix when a checkout succeeds and announced by the payment.succeeded event. They are immutable except for their refund state.

The payment object

Attributes

idstring
Prefixed py_live_ or py_test_. Use it as the idempotency key of your own ledger row.
objectstring
Always payment.
livemodeboolean
Live or test.
statusenum
succeeded, partially_refunded or refunded.
checkoutstring | null
The checkout that produced this payment.
amountinteger
Requested amount in the minor unit of currency.
currencyenum
usd or vnd.
amount_usdinteger
Gross amount charged, USD cents.
fee_usdinteger
Processing fee retained by the payment provider, USD cents. 0 in test mode.
net_usdinteger
amount_usd minus fee_usd.
refunded_usdinteger
Total refunded so far, USD cents.
descriptionstring | null
From the checkout.
customerobject | null
From the checkout. The email may be updated with the address the customer actually used on the hosted page.
referencestring | null
From the checkout.
metadataobject
From the checkout.
invoice_availableboolean
True for live payments; fetch the PDF with GET /v1/payments/:id/invoice.
created_attimestamp
ISO 8601.
The payment object
{  "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "object": "payment",  "livemode": true,  "status": "succeeded",  "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "amount": 600000,  "currency": "vnd",  "amount_usd": 2308,  "fee_usd": 132,  "net_usd": 2176,  "refunded_usd": 0,  "description": "Acme credits",  "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },  "reference": "topup_8f1c",  "metadata": { "plan": "pro" },  "invoice_available": true,  "created_at": "2026-10-14T06:35:02.410Z"}

Retrieve a payment

GET/v1/payments/:id

Returns

The payment object.

curl https://api.vitix.net/v1/payments/py_live_4YMjlAzqiKxSYAIsAWEToqvL \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "object": "payment",  "livemode": true,  "status": "succeeded",  "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",  "amount": 600000,  "currency": "vnd",  "amount_usd": 2308,  "fee_usd": 132,  "net_usd": 2176,  "refunded_usd": 0,  "description": "Acme credits",  "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },  "reference": "topup_8f1c",  "metadata": { "plan": "pro" },  "invoice_available": true,  "created_at": "2026-10-14T06:35:02.410Z"}

List payments

GET/v1/payments

Useful for reconciliation jobs: page through everything since your last run and compare against your ledger.

Query parameters

customerstring
Filter by customer id.
referencestring
Filter by your reference.
checkoutstring
Filter by checkout id.
statusenum
succeeded, partially_refunded or refunded.
limitinteger
1–100, default 20.
starting_afterstring
Cursor.

Returns

A list object of payments, newest first.

curl https://api.vitix.net/v1/payments?reference=topup_8f1c \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",      "object": "payment",      "livemode": true,      "status": "succeeded",      "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",      "amount": 600000,      "currency": "vnd",      "amount_usd": 2308,      "fee_usd": 132,      "net_usd": 2176,      "refunded_usd": 0,      "description": "Acme credits",      "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },      "reference": "topup_8f1c",      "metadata": { "plan": "pro" },      "invoice_available": true,      "created_at": "2026-10-14T06:35:02.410Z"    }  ],  "has_more": false}

Get the invoice PDF

GET/v1/payments/:id/invoice

Invoices are issued by Vitix's merchant of record in the customer's name and show the USD amount charged.

Returns

An object with a short-lived url to the PDF (valid about an hour). Fetch a fresh one each time rather than storing it. Returns invoice_unavailable for test payments or while the PDF is still being generated (retry after a few seconds).

curl https://api.vitix.net/v1/payments/py_live_4YMjlAzqiKxSYAIsAWEToqvL/invoice \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "invoice",  "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "url": "https://…/invoice.pdf?X-Amz-Expires=3600&…",  "expires_in": 3600}

Refunds

Request a full or partial refund. No provider request is sent until Vitix staff approves. Live refunds are confirmed asynchronously by the payment provider: watch for refund.succeeded / refund.failed and payment.refunded. Processing fees are not returned.

The refund object

Attributes

idstring
Prefixed re_live_ or re_test_.
objectstring
Always refund.
livemodeboolean
Live or test.
paymentstring
The payment being refunded.
statusenum
requested awaiting Vitix review; rejected if declined; pending after approval, then succeeded or failed. Test refunds also require approval.
amount_usdinteger
Refunded amount in USD cents.
reasonenum | null
duplicate, fraudulent, customer_request or other.
created_attimestamp
ISO 8601.
The refund object
{  "id": "re_live_dwxgQnlN31ZGfcZECgvAFygc",  "object": "refund",  "livemode": true,  "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "status": "requested",  "amount_usd": 500,  "reason": "customer_request",  "reviewed_at": null,  "review_note": null,  "submission_error": null,  "created_at": "2026-10-15T09:12:00.000Z"}

Request a refund

POST/v1/refunds

Always send an Idempotency-Key: a retried refund call without one could refund twice (up to the remaining balance).

Parameters

paymentstringrequired
Id of the payment to refund.
amount_usdinteger
USD cents to refund. Defaults to the unrefunded balance. Must not exceed it.
reasonenum
duplicate, fraudulent, customer_request (default) or other.

Returns

The refund request with status: "requested". No money moves until Vitix approves. HTTP 201. Fails with refund_pending while another refund of the same payment is awaiting review or processing and amount_invalid if the amount exceeds the remaining balance.

curl -X POST https://api.vitix.net/v1/refunds \  -H "Authorization: Bearer vx_live_••••••••" \  -H "Content-Type: application/json" \  -H "Idempotency-Key: refund_8f1c" \  -d '{ "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL", "amount_usd": 500, "reason": "customer_request" }'
Response
{  "id": "re_live_dwxgQnlN31ZGfcZECgvAFygc",  "object": "refund",  "livemode": true,  "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "status": "requested",  "amount_usd": 500,  "reason": "customer_request",  "reviewed_at": null,  "review_note": null,  "submission_error": null,  "created_at": "2026-10-15T09:12:00.000Z"}

Retrieve a refund

GET/v1/refunds/:id

Returns

The refund object.

curl https://api.vitix.net/v1/refunds/re_live_dwxgQnlN31ZGfcZECgvAFygc \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "re_live_dwxgQnlN31ZGfcZECgvAFygc",  "object": "refund",  "livemode": true,  "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",  "status": "succeeded",  "amount_usd": 500,  "reason": "customer_request",  "reviewed_at": null,  "review_note": null,  "submission_error": null,  "created_at": "2026-10-15T09:12:00.000Z"}

List refunds

GET/v1/refunds

Query parameters

paymentstring
Only refunds of this payment.
limitinteger
1–100, default 20.
starting_afterstring
Cursor.

Returns

A list object of refunds, newest first.

curl https://api.vitix.net/v1/refunds?payment=py_live_4YMjlAzqiKxSYAIsAWEToqvL \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "re_live_dwxgQnlN31ZGfcZECgvAFygc",      "object": "refund",      "livemode": true,      "payment": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",      "status": "requested",      "amount_usd": 500,      "reason": "customer_request",      "reviewed_at": null,      "review_note": null,      "submission_error": null,      "created_at": "2026-10-15T09:12:00.000Z"    }  ],  "has_more": false}

Events

Every state change produces an event. Events are what webhooks deliver, and they stay queryable here so you can audit, backfill or replay them. The Webhooks page lists the event types and the delivery contract.

The event object

Attributes

idstring
Prefixed evt_live_ or evt_test_. Also sent as the webhook-id header; stable across redeliveries.
objectstring
Always event.
livemodeboolean
Live or test.
typestring
One of the event types.
created_attimestamp
ISO 8601.
data.objectobject
The resource the event is about (a checkout, payment or refund), in the state it had when the event was created.
The event object
{  "id": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",  "object": "event",  "livemode": true,  "type": "payment.succeeded",  "created_at": "2026-10-14T06:35:02.455Z",  "data": {    "object": {      "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",      "object": "payment",      "livemode": true,      "status": "succeeded",      "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",      "amount": 600000,      "currency": "vnd",      "amount_usd": 2308,      "fee_usd": 132,      "net_usd": 2176,      "refunded_usd": 0,      "description": "Acme credits",      "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },      "reference": "topup_8f1c",      "metadata": { "plan": "pro" },      "invoice_available": true,      "created_at": "2026-10-14T06:35:02.410Z"    }  }}

List events

GET/v1/events

If your webhook endpoint was down for longer than the retry window, page through this list to catch up.

Query parameters

typestring
Only events of this type, e.g. payment.succeeded.
limitinteger
1–100, default 20.
starting_afterstring
Cursor.

Returns

A list object of events, newest first.

curl https://api.vitix.net/v1/events?type=payment.succeeded&limit=50 \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",      "object": "event",      "livemode": true,      "type": "payment.succeeded",      "created_at": "2026-10-14T06:35:02.455Z",      "data": {        "object": {          "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",          "object": "payment",          "livemode": true,          "status": "succeeded",          "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",          "amount": 600000,          "currency": "vnd",          "amount_usd": 2308,          "fee_usd": 132,          "net_usd": 2176,          "refunded_usd": 0,          "description": "Acme credits",          "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },          "reference": "topup_8f1c",          "metadata": { "plan": "pro" },          "invoice_available": true,          "created_at": "2026-10-14T06:35:02.410Z"        }      }    }  ],  "has_more": false}

Retrieve an event

GET/v1/events/:id

A common hardening pattern: on receiving a webhook, fetch the event by id and act on the fetched copy rather than the posted body.

Returns

The event object.

curl https://api.vitix.net/v1/events/evt_live_dBbRDc4vUYcwjyp93GkDKtyF \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",  "object": "event",  "livemode": true,  "type": "payment.succeeded",  "created_at": "2026-10-14T06:35:02.455Z",  "data": {    "object": {      "id": "py_live_4YMjlAzqiKxSYAIsAWEToqvL",      "object": "payment",      "livemode": true,      "status": "succeeded",      "checkout": "cs_live_0aWdSNgZbvGU0BjvCISLh07o",      "amount": 600000,      "currency": "vnd",      "amount_usd": 2308,      "fee_usd": 132,      "net_usd": 2176,      "refunded_usd": 0,      "description": "Acme credits",      "customer": { "id": "user_42", "email": "[email protected]", "name": "Ana Nguyen" },      "reference": "topup_8f1c",      "metadata": { "plan": "pro" },      "invoice_available": true,      "created_at": "2026-10-14T06:35:02.410Z"    }  }}

List deliveries of an event

GET/v1/events/:id/deliveries

Returns

A list object of webhook deliveries (all attempts, all endpoints), newest first.

curl https://api.vitix.net/v1/events/evt_live_dBbRDc4vUYcwjyp93GkDKtyF/deliveries \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "wd_UZVVfiXb1UChe8HUwzXN",      "object": "webhook_delivery",      "event": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",      "endpoint": "we_y2uBTZdXLUmV9dRRQ3Rh",      "attempt": 1,      "status": "succeeded",      "next_attempt_at": null,      "response_status": 200,      "response_body": "ok",      "error": null,      "duration_ms": 184,      "delivered_at": "2026-10-14T06:35:02.700Z",      "created_at": "2026-10-14T06:35:02.460Z"    }  ],  "has_more": false}

The webhook_delivery object

One row per attempt. Read-only.

Attributes

idstring
Prefixed wd_.
eventstring
The event delivered.
endpointstring
The endpoint it was sent to.
attemptinteger
1 for the first try, then 2…6 for automatic retries. Manual redeliveries continue the count.
statusenum
pending, sending, succeeded or failed.
next_attempt_attimestamp | null
When a pending delivery will be sent.
response_statusinteger | null
HTTP status your endpoint returned.
response_bodystring | null
First 1,000 characters of your response, to help debugging.
errorstring | null
Transport error, e.g. timeout after 10s or HTTP 500.
duration_msinteger | null
Round-trip time.
delivered_attimestamp | null
When a 2xx was received.
created_attimestamp
ISO 8601.
The webhook_delivery object
{  "id": "wd_UZVVfiXb1UChe8HUwzXN",  "object": "webhook_delivery",  "event": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",  "endpoint": "we_y2uBTZdXLUmV9dRRQ3Rh",  "attempt": 1,  "status": "succeeded",  "next_attempt_at": null,  "response_status": 200,  "response_body": "ok",  "error": null,  "duration_ms": 184,  "delivered_at": "2026-10-14T06:35:02.700Z",  "created_at": "2026-10-14T06:35:02.460Z"}

Redeliver an event

POST/v1/events/:id/redeliver

Queues a fresh delivery immediately. The event keeps its id, so a correctly idempotent handler will treat it as a duplicate.

Query parameters

endpointstring
Only resend to this endpoint id. Default: all enabled endpoints of the event's mode.

Returns

A list object of the newly queued deliveries. HTTP 201.

curl -X POST https://api.vitix.net/v1/events/evt_live_dBbRDc4vUYcwjyp93GkDKtyF/redeliver \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "wd_UZVVfiXb1UChe8HUwzXN",      "object": "webhook_delivery",      "event": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",      "endpoint": "we_y2uBTZdXLUmV9dRRQ3Rh",      "attempt": 2,      "status": "pending",      "next_attempt_at": null,      "response_status": 200,      "response_body": "ok",      "error": null,      "duration_ms": 184,      "delivered_at": "2026-10-14T06:35:02.700Z",      "created_at": "2026-10-14T06:35:02.460Z"    }  ],  "has_more": false}

Webhook endpoints

Register up to 10 URLs per mode to receive events. Each endpoint has its own signing secret. Endpoints created with a test key only receive test events, and vice versa.

The webhook_endpoint object

Attributes

idstring
Prefixed we_.
objectstring
Always webhook_endpoint.
livemodeboolean
Endpoints are mode-scoped: a live endpoint only receives live events. The mode is taken from the key used to create it.
urlstring
Where events are POSTed. Must be https in live mode.
descriptionstring
Free text.
eventsstring[]
Event types to deliver, or ["*"] for all.
statusenum
enabled or disabled. Disabled endpoints receive nothing and pending deliveries fail.
secretstring
Signing secret (whsec_…). Returned only on create and rotate.
created_attimestamp
ISO 8601.
The webhook_endpoint object
{  "id": "we_y2uBTZdXLUmV9dRRQ3Rh",  "object": "webhook_endpoint",  "livemode": true,  "url": "https://app.example.com/api/vitix/webhook",  "description": "Production",  "events": ["payment.succeeded", "payment.refunded"],  "status": "enabled",  "secret": "whsec_9fQm3…",  "created_at": "2026-10-14T06:32:46.000Z"}

Create a webhook endpoint

POST/v1/webhook_endpoints

Parameters

urlstringrequired
Absolute URL. Must be https in live mode.
descriptionstring
Up to 200 characters.
eventsstring[]
Event types to subscribe to. Default ["*"].

Returns

The endpoint including its secret. Store the secret now; it is not returned by later reads. HTTP 201.

curl -X POST https://api.vitix.net/v1/webhook_endpoints \  -H "Authorization: Bearer vx_live_••••••••" \  -H "Content-Type: application/json" \  -d '{ "url": "https://app.example.com/api/vitix/webhook", "description": "Production", "events": ["payment.succeeded", "payment.refunded"] }'
Response
{  "id": "we_y2uBTZdXLUmV9dRRQ3Rh",  "object": "webhook_endpoint",  "livemode": true,  "url": "https://app.example.com/api/vitix/webhook",  "description": "Production",  "events": ["payment.succeeded", "payment.refunded"],  "status": "enabled",  "secret": "whsec_9fQm3…",  "created_at": "2026-10-14T06:32:46.000Z"}

Retrieve a webhook endpoint

GET/v1/webhook_endpoints/:id

Returns

The endpoint object without its secret.

curl https://api.vitix.net/v1/webhook_endpoints/we_y2uBTZdXLUmV9dRRQ3Rh \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "we_y2uBTZdXLUmV9dRRQ3Rh",  "object": "webhook_endpoint",  "livemode": true,  "url": "https://app.example.com/api/vitix/webhook",  "description": "Production",  "events": ["payment.succeeded", "payment.refunded"],  "status": "enabled",  "created_at": "2026-10-14T06:32:46.000Z"}

List webhook endpoints

GET/v1/webhook_endpoints

Returns

A list object of the endpoints in the key's mode (secrets omitted).

curl https://api.vitix.net/v1/webhook_endpoints \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "object": "list",  "data": [    {      "id": "we_y2uBTZdXLUmV9dRRQ3Rh",      "object": "webhook_endpoint",      "livemode": true,      "url": "https://app.example.com/api/vitix/webhook",      "description": "Production",      "events": ["payment.succeeded", "payment.refunded"],      "status": "enabled",      "created_at": "2026-10-14T06:32:46.000Z"    }  ],  "has_more": false}

Update a webhook endpoint

PATCH/v1/webhook_endpoints/:id

Parameters

urlstring
New URL (https in live mode).
descriptionstring
New description.
eventsstring[]
Replace the subscription list.
statusenum
enabled or disabled.

Returns

The updated endpoint.

curl -X PATCH https://api.vitix.net/v1/webhook_endpoints/we_y2uBTZdXLUmV9dRRQ3Rh \  -H "Authorization: Bearer vx_live_••••••••" \  -H "Content-Type: application/json" \  -d '{ "status": "disabled" }'
Response
{  "id": "we_y2uBTZdXLUmV9dRRQ3Rh",  "object": "webhook_endpoint",  "livemode": true,  "url": "https://app.example.com/api/vitix/webhook",  "description": "Production",  "events": ["payment.succeeded", "payment.refunded"],  "status": "disabled",  "created_at": "2026-10-14T06:32:46.000Z"}

Delete a webhook endpoint

DELETE/v1/webhook_endpoints/:id

Returns

A confirmation object. Pending deliveries to the endpoint are dropped.

curl -X DELETE https://api.vitix.net/v1/webhook_endpoints/we_y2uBTZdXLUmV9dRRQ3Rh \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "we_y2uBTZdXLUmV9dRRQ3Rh",  "object": "webhook_endpoint",  "deleted": true}

Rotate the signing secret

POST/v1/webhook_endpoints/:id/rotate_secret

Returns

The endpoint with its new secret. Deliveries queued after this call are signed with the new secret; update your server before rotating in production.

curl -X POST https://api.vitix.net/v1/webhook_endpoints/we_y2uBTZdXLUmV9dRRQ3Rh/rotate_secret \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "we_y2uBTZdXLUmV9dRRQ3Rh",  "object": "webhook_endpoint",  "livemode": true,  "url": "https://app.example.com/api/vitix/webhook",  "description": "Production",  "events": ["payment.succeeded", "payment.refunded"],  "status": "enabled",  "secret": "whsec_Lk2p8…",  "created_at": "2026-10-14T06:32:46.000Z"}

Ping a webhook endpoint

POST/v1/webhook_endpoints/:id/ping

Sends a signed ping event to this endpoint only. Use it to verify your signature check end to end.

Returns

The ping event and the queued delivery. HTTP 201.

curl -X POST https://api.vitix.net/v1/webhook_endpoints/we_y2uBTZdXLUmV9dRRQ3Rh/ping \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "event": {    "id": "evt_test_cdQrBfJ6mQ5DCbP5ccQAmnTf",    "object": "event",    "livemode": false,    "type": "ping",    "created_at": "2026-10-14T06:40:11.000Z",    "data": { "object": { "object": "ping", "endpoint": "we_y2uBTZdXLUmV9dRRQ3Rh", "message": "Hello from Vitix Pay" } }  },  "deliveries": [ {      "id": "wd_UZVVfiXb1UChe8HUwzXN",      "object": "webhook_delivery",      "event": "evt_live_dBbRDc4vUYcwjyp93GkDKtyF",      "endpoint": "we_y2uBTZdXLUmV9dRRQ3Rh",      "attempt": 1,      "status": "pending",      "next_attempt_at": null,      "response_status": 200,      "response_body": "ok",      "error": null,      "duration_ms": 184,      "delivered_at": "2026-10-14T06:35:02.700Z",      "created_at": "2026-10-14T06:35:02.460Z"    } ]}

Retrieve your account

GET/v1/account

A cheap call to verify a key and read the limits you should validate against before creating checkouts.

Returns

Your partner account, its amount limits (USD cents) and allowed return domains. livemode reflects the key you used.

curl https://api.vitix.net/v1/account \  -H "Authorization: Bearer vx_live_••••••••"
Response
{  "id": "pt_IfF9npu7GIGDS6UJ",  "object": "account",  "livemode": true,  "name": "Acme SaaS",  "slug": "acme",  "limits": { "min_usd": 2000, "max_usd": 500000 },  "allowed_domains": ["app.example.com"],  "created_at": "2026-10-14T06:32:45.156Z"}

Questions or a missing feature? Email [email protected]