Partner API
Server-to-server API for partners: issue a key, read your storefront config and locations, create clients, grant plans, and manage subscription links from your own site or Telegram bot.
The Partner API is the smallest set of endpoints that lets you build your own site, your own dashboard, or a Telegram bot on top of CreateYourVPN — without touching anything infrastructural.
It speaks one language: partner → clients → subscriptions → plans. Servers, nodes, panels and SSH are ours to run; they never appear in a response.
The key is server-to-server only. A request that looks like it came from a browser is rejected with 403 browser_forbidden. This is not a formality: a key placed in front-end code is already in your visitors' hands — it ships inside your JavaScript bundle. Keep it on your server.
Getting a key
Open the dashboard → Account menu → Settings → API and integrations.
Give the key a name (Telegram bot, landing page) and pick only the permissions it needs.
Press Issue key and copy the full key. It is shown once — we store only a hash and physically cannot show it again.
Up to 5 active keys per partner. Rotation is: issue a new one, switch your integration over, revoke the old one.
Authentication
Send the key as a bearer token:
curl https://api.createyourvpn.com/api/v1/partner-api/me \
-H "Authorization: Bearer cyv_live_<key_id>_<secret>"X-API-Key: cyv_live_… works too, for clients where Authorization is taken by a proxy.
A key looks like cyv_live_<key_id>_<secret>. The first half (key_id) is public — it is what you see in the dashboard and what you can safely quote to support. The second half is the secret.
Permissions (scopes)
| Scope | What it allows |
|---|---|
config:read | Read your storefront config, plans, locations, and /me. |
users:read | Read clients, their subscriptions and traffic. |
users:write | Create clients, grant plans, reset subscription links, delete clients. |
A key without the required scope gets 403 forbidden_scope. Give the landing page config:read and nothing else — it cannot then be used to touch a single client.
API contract and examples
The complete, runnable contract lives in the public Postman collection. It contains every endpoint, scope, parameter, request body, response example and stable error code. The collection is generated from the backend contract, so Academy does not keep a second handwritten copy that can drift out of date.
Rate limits
Limits are counted per key, not per IP — your bot runs from one address, and an IP limit would either miss it or punish your neighbours behind the same NAT.
- 120 requests/minute per key overall.
- 10 requests/minute for
GET /usersspecifically.
That second limit is not arbitrary. GET /users is the single most expensive endpoint we have: it reads the full client list from your panel on every call. Polling it in a loop does not slow us down — it slows your service down.
Do not poll the list. Address clients directly with GET /users/{id}. Keep the mapping between your own user identifiers and ours by passing externalId when you create a client — then you never need the list at all.
Idempotency
Three operations require an Idempotency-Key header: granting a plan, resetting a subscription link, and deleting a client.
curl -X POST .../users/u_9f3a…/grant \
-H "Authorization: Bearer $CYV_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"tariffId":"monthly"}'Repeating a request with the same key replays the stored result for 24 hours instead of running the operation again. Without it, a bot that retries on timeout extends the same subscription twice for one payment — and you find out from your balance, not from an error.
Use one key per business event (one payment, one click), not per HTTP attempt. Retries must reuse the same key.
If a retry arrives while the first attempt is still running — or while its outcome is genuinely unknown, because our process died between applying the change and recording the result — you get 409 conflict instead of a second execution. Check the client's state and decide: refusing is cheaper than charging twice.
For request and response schemas, use the public Postman collection above as the source of truth.