VPN infrastructure
VPN subscriptions inside your product.
Create and manage subscriptions from your website, application, Telegram bot or internal service while AdaptGroup operates the VPN infrastructure.
- Base URL
- https://network-api.adaptgroup.app
- Authentication
- X-Api-Key
- Capabilities
- Plans, subscriptions, balance, webhooks
- Rate limit
- 100 requests / 60 seconds
Create a subscription
The plan price is deducted from the integration balance. Trial plans cannot be created through the API.
POST
/subs/createcURL
export ADAPTGROUP_API_KEY="YOUR_API_KEY"
curl --request POST \
--url https://network-api.adaptgroup.app/subs/create \
--header "Content-Type: application/json" \
--header "X-Api-Key: $ADAPTGROUP_API_KEY" \
--data '{
"api_key_id": 1,
"plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123"
}'Python
import os
import requests
response = requests.post(
"https://network-api.adaptgroup.app/subs/create",
headers={
"Content-Type": "application/json",
"X-Api-Key": os.environ["ADAPTGROUP_API_KEY"],
},
json={
"api_key_id": 1,
"plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123",
},
timeout=10,
)
response.raise_for_status()
subscription = response.json()Node.js
const response = await fetch("https://network-api.adaptgroup.app/subs/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.ADAPTGROUP_API_KEY,
},
body: JSON.stringify({
api_key_id: 1,
plan_uuid: "550e8400-e29b-41d4-a716-446655440000",
external_user_id: "user_123",
}),
});
if (!response.ok) {
throw new Error(`VPN API request failed: ${response.status}`);
}
const subscription = await response.json();PHP
<?php
$payload = json_encode([
'api_key_id' => 1,
'plan_uuid' => '550e8400-e29b-41d4-a716-446655440000',
'external_user_id' => 'user_123',
]);
$request = curl_init('https://network-api.adaptgroup.app/subs/create');
curl_setopt_array($request, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Api-Key: ' . getenv('ADAPTGROUP_API_KEY'),
],
CURLOPT_POSTFIELDS => $payload,
]);
$response = curl_exec($request);
if ($response === false) {
throw new RuntimeException(curl_error($request));
}
curl_close($request);
$subscription = json_decode($response, true, flags: JSON_THROW_ON_ERROR);Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
func main() {
payload, err := json.Marshal(map[string]any{
"api_key_id": 1,
"plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123",
})
if err != nil {
panic(err)
}
req, err := http.NewRequest(
http.MethodPost,
"https://network-api.adaptgroup.app/subs/create",
bytes.NewReader(payload),
)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Api-Key", os.Getenv("ADAPTGROUP_API_KEY"))
client := &http.Client{Timeout: 10 * time.Second}
response, err := client.Do(req)
if err != nil {
panic(err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
panic(fmt.Sprintf("VPN API request failed: %s", response.Status))
}
}Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("ADAPTGROUP_API_KEY");
String payload = """
{
"api_key_id": 1,
"plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://network-api.adaptgroup.app/subs/create"))
.header("Content-Type", "application/json")
.header("X-Api-Key", apiKey)
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new IllegalStateException(response.body());
}
String subscription = response.body();
System.out.println(subscription);
}
}C#
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add(
"X-Api-Key",
Environment.GetEnvironmentVariable("ADAPTGROUP_API_KEY")
);
var payload = JsonSerializer.Serialize(new
{
api_key_id = 1,
plan_uuid = "550e8400-e29b-41d4-a716-446655440000",
external_user_id = "user_123",
});
using var body = new StringContent(
payload,
Encoding.UTF8,
"application/json"
);
using var response = await client.PostAsync("https://network-api.adaptgroup.app/subs/create", body);
response.EnsureSuccessStatusCode();
var subscription = await response.Content.ReadFromJsonAsync<JsonElement>();Ruby
require "json"
require "net/http"
require "uri"
uri = URI("https://network-api.adaptgroup.app/subs/create")
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["X-Api-Key"] = ENV.fetch("ADAPTGROUP_API_KEY")
request.body = {
api_key_id: 1,
plan_uuid: "550e8400-e29b-41d4-a716-446655440000",
external_user_id: "user_123"
}.to_json
response = Net::HTTP.start(
uri.hostname,
uri.port,
use_ssl: true
) { |http| http.request(request) }
unless response.is_a?(Net::HTTPSuccess)
raise "VPN API request failed: #{response.code}"
end
subscription = JSON.parse(response.body)Rust
use reqwest::blocking::Client;
use serde_json::{json, Value};
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let subscription: Value = Client::new()
.post("https://network-api.adaptgroup.app/subs/create")
.header("Content-Type", "application/json")
.header("X-Api-Key", env::var("ADAPTGROUP_API_KEY")?)
.json(&json!({
"api_key_id": 1,
"plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123"
}))
.send()?
.error_for_status()?
.json()?;
println!("{subscription:#}");
Ok(())
}Keep X-Api-Key on the server. These examples do not send requests from the browser.
200 OKResponse
{
"success": true,
"subscription_uuid": "770fa622-a4bd-63f6-c938-668877662222",
"subscription_url": "https://network-api.adaptgroup.app/sub/770fa622-a4bd-63f6-c938-668877662222",
"plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123",
"end_date": "2026-06-01T12:00:00",
"devices": 3,
"days": 30,
"traffic_limit_bytes": null,
"balance": "96.50"
}The API returns a ready subscription URL.
Pass subscription_url directly to the user's VPN client. The response also includes the subscription ID, end date, device limit, traffic limit and remaining balance.
Manage the full subscription lifecycle
Use the same API key and integration ID for plans, subscription operations, device management and event delivery.