Download OpenAPI specification:
REST API for the wgua.eu WireGuard VPN subscription platform.
STB (set-top box) clients use this API to provision customers and manage
subscriptions. The payment form endpoints (/pay/*) are browser-facing and
are not called by the STB directly.
All endpoints except /pay/* require an X-API-Key header. Keys are issued
per operator through the admin portal. A key is scoped to a single operator —
customers created with a key belong to that operator and are only visible
through the same key.
A customer record is created once per device using POST /customers and
persists indefinitely. When a subscription expires the STB must call
POST /customers/{customerId}/payment to prompt the user to renew.
Never create a new customer to replace an expired one. Creating a new
customer allocates a new IP address and generates new WireGuard keys,
permanently breaking the user's VPN identity.
Returns all customers belonging to the authenticated operator.
Returns 404 when the operator has no customers yet (not an auth error).
[- {
- "customer_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
- "endpoint": "01ARZ3NDEKTSV4RRFFQ69G5FAV.wgua.eu",
- "ip_address": "100.80.4.17",
- "peer_public_key": "base64encodedServerPublicKey=",
- "private_key": "base64encodedPrivateKey=",
- "public_key": "base64encodedPublicKey=",
- "created": "2026-03-01T12:00:00Z",
- "expires": "2026-04-01T12:00:00Z",
- "active": true
}
]Provisions a new WireGuard peer. Call this endpoint exactly once per
device, at first boot, after confirming that GET /customers returns
no existing customers.
The server:
Do not call this endpoint again when a subscription expires. Use
POST /customers/{customerId}/payment to renew the existing customer.
Creating a second customer permanently discards the previous IP and keys.
Store customer_id and private_key on the device immediately. The
private_key is also retrievable later via GET /customers/{customerId},
which makes credential recovery possible after data loss.
{- "customer_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
- "endpoint": "01ARZ3NDEKTSV4RRFFQ69G5FAV.wgua.eu",
- "ip_address": "100.80.4.17/32",
- "peer_public_key": "base64encodedServerPublicKey=",
- "private_key": "base64encodedPrivateKey=",
- "public_key": "base64encodedPublicKey=",
- "created": "2026-03-27T10:00:00Z",
- "expires": "2026-04-10T10:00:00Z",
- "active": true
}Returns the current state of a customer, including subscription status and WireGuard credentials.
Poll this endpoint to detect subscription changes (e.g. after presenting a
payment link). Use active to determine whether VPN access is currently
granted. Use expires to decide when to proactively offer renewal before
the subscription lapses.
This endpoint returns the private_key, which allows full WireGuard
configuration to be restored from just the customer_id (see
POST /customers/recover for the recovery flow).
Returns 404 if the customer does not exist or belongs to a different
operator.
| customerId required | string Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV Unique customer identifier (ULID). |
{- "customer_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
- "endpoint": "01ARZ3NDEKTSV4RRFFQ69G5FAV.wgua.eu",
- "ip_address": "100.80.4.17",
- "peer_public_key": "base64encodedServerPublicKey=",
- "private_key": "base64encodedPrivateKey=",
- "public_key": "base64encodedPublicKey=",
- "created": "2026-03-01T12:00:00Z",
- "expires": "2026-04-01T12:00:00Z",
- "active": true
}Permanently removes a customer. All stored fields (keys, IP assignment, subscription dates) are cleared and the IP address is returned to the allocation pool. This operation is irreversible through the API.
Use this only to fully deprovision a device. Do not delete and recreate a
customer to renew a subscription — use
POST /customers/{customerId}/payment instead.
Returns 404 if the customer does not exist or belongs to a different
operator.
| customerId required | string Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV Unique customer identifier (ULID). |
{- "error": "Unauthorized"
}Returns the recovery code for a customer. The code is generated on the first call and persists indefinitely — subsequent calls return the same code.
Store the recovery code alongside the customer credentials. If the device
loses its local database, the code can be used with POST /customers/recover
to look up the customer_id, after which GET /customers/{customerId}
returns the full credentials including private_key.
The code uses an alphabet that excludes visually ambiguous characters (I, O, S, Z) to reduce transcription errors when users enter codes manually.
Returns 404 if the customer does not exist or belongs to a different
operator.
| customerId required | string Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV Unique customer identifier (ULID). |
{- "recovery_code": "A1-2B3C"
}Looks up a customer_id by its recovery code. Use this when an STB has
lost its local database and needs to recover its VPN credentials.
Recovery flow:
customer_id.GET /customers/{customerId} to retrieve full credentials including
private_key.The recovery code must belong to a customer owned by the authenticating
operator. Returns 404 if no matching customer is found.
| recovery_code required | string The recovery code previously obtained from
|
{- "recovery_code": "A1-2B3C"
}{- "customer_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV"
}Creates a hosted payment form URL for the customer to renew their subscription. The link is valid for 24 hours.
The STB presents the url to the end user as a link or QR code. The user
opens it in a browser, selects a subscription plan, and is redirected to
the payment gateway. The STB is not involved further in the payment flow.
After a successful payment:
expires is extended by the purchased plan's duration.The STB can detect that renewal completed by polling GET /customers/{customerId}
and checking that active is true or that expires has advanced.
Multiple payment links can exist simultaneously for the same customer. Any one of them completing a payment will extend the subscription.
Call this endpoint when active is false or expires is approaching.
Do not create a new customer.
| customerId required | string Example: 01ARZ3NDEKTSV4RRFFQ69G5FAV Unique customer identifier (ULID). |
{- "expires": "2026-03-28T10:00:00Z"
}Browser-facing endpoint. Returns an HTML page listing available subscription plans with prices in UAH, USD, and EUR.
Not called by the STB — the URL is obtained from
POST /customers/{customerId}/payment and opened by the end user.
If the payment link has expired the page displays an expiry notice rather than the plan selection form; both cases return HTTP 200.
| paymentReference required | string Example: 01BX5ZZKBKACTAV9WEVGEMMVS0 Unique payment reference (ULID) returned by
|
Browser-facing endpoint. Accepts the plan chosen by the user, creates the payment transaction at the payment gateway (iPay.ua), and redirects the browser to the checkout page.
Not called by the STB directly.
| paymentReference required | string Example: 01BX5ZZKBKACTAV9WEVGEMMVS0 Unique payment reference (ULID) returned by
|
| rate required | string Name of the selected subscription plan. |
| nonce required | string CSRF token issued with the payment form page. Must match the value stored in the session; the request is rejected if it does not. |
Browser-facing endpoint. The payment gateway redirects the user here after checkout completes or is cancelled. Not called by the STB directly.
{result} is ok when the user completed the checkout flow, or nok
when they cancelled or the checkout failed. In both cases the server
queries the payment gateway for the authoritative status and renders a
result page.
When the gateway confirms a successful payment:
expires is extended by the purchased plan's duration.If the browser redirect is missed (e.g. the user closes the tab), a background process polls the payment gateway every 10 seconds and applies the same subscription update automatically for up to 24 hours after the payment link was created.
| paymentReference required | string Example: 01BX5ZZKBKACTAV9WEVGEMMVS0 Unique payment reference (ULID) returned by
|
| result required | string Enum: "ok" "nok" Outcome indicator from the payment gateway redirect.
|