# API reference | Vitix Pay

> Complete reference for the Vitix Pay REST API: authentication, idempotency, pagination, checkouts, payments, refunds, events and webhook endpoints.

Canonical: https://vitix.net/developers/api
Markdown: https://vitix.net/developers/api.md


Documentation menu

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": "ana@example.com", "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).

| Currency | amount means | Example |
| --- | --- | --- |
| usd | US cents | 2000 → $20.00 |
| vnd | Vietnamese đồng | 600000 → 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](https://vitix.net/developers/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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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](https://vitix.net/developers/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](https://vitix.net/developers/webhooks#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": "ana@example.com", "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": "ana@example.com", "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": "ana@example.com", "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" } ]}
```

## Account

### 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"}
```

[← Errors](https://vitix.net/developers/errors)
Questions or a missing feature? Email [support@vitix.net](mailto:support@vitix.net)
