# How v2rayN Exposes APIs for External Control and Integration

> Understand how v2rayN exposes APIs for external control and integration. Query metrics and manage proxies locally without SDK dependencies.

- Repository: [2dust/v2rayN](https://github.com/2dust/v2rayN)
- Tags: api-reference
- Published: 2026-02-27

---

**v2rayN exposes two local HTTP APIs on dynamically allocated ports—one for V2Ray statistics via a dokodemo-door inbound and another for Clash/Sing-Box REST operations—allowing external tools to query metrics and manage proxies without SDK dependencies.**

The open-source proxy client v2rayN (repository `2dust/v2rayN`) does not rely on a custom binary protocol for external integration. Instead, it automatically spawns local HTTP listeners that expose standard REST endpoints and Prometheus-style metrics, making it trivial for scripts, third-party GUIs, or automation tools to control a running instance.

## Architectural Overview of v2rayN APIs

v2rayN utilizes two distinct TCP ports allocated at runtime to separate core statistics from proxy management operations. Both listeners bind strictly to the loopback interface (`127.0.0.1`), ensuring that external network entities cannot access these control surfaces directly.

### Port Allocation and Management

The `AppManager` singleton generates free ports during application startup and persists them for the session lifetime.

```csharp
// v2rayN/ServiceLib/Manager/AppManager.cs
public int StatePort  => _statePort;   // V2Ray stats (e.g., 10085)
public int StatePort2 => _statePort2;  // Clash / Sing-Box API (e.g., 10086)

```

These values are referenced throughout the service layer to construct endpoint URLs dynamically.

### V2Ray Statistics API

To expose V2Ray’s internal metrics, v2rayN injects a **dokodemo-door** inbound into the generated core configuration. This is implemented in [`V2rayStatisticService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayStatisticService.cs).

```csharp
// v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs
Inboundsettings4Ray apiInboundSettings = new();
apiInbound.tag = tag;
apiInbound.listen = Global.Loopback;            // 127.0.0.1
apiInbound.port = AppManager.Instance.StatePort;
apiInbound.protocol = Global.InboundAPIProtocol; // "dokodemo-door"
apiInboundSettings.address = Global.Loopback;
apiInbound.settings = apiInboundSettings;
_coreConfig.inbounds.Add(apiInbound);

```

Once the core starts, the endpoint `http://127.0.0.1:{StatePort}/debug/vars` returns Prometheus-style JSON containing uplink and downlink counters. The `StatisticsXrayService` consumes this data.

```csharp
// v2rayN/ServiceLib/Services/Statistics/StatisticsXrayService.cs
private string Url => $"{Global.HttpProtocol}{Global.Loopback}:{AppManager.Instance.StatePort}/debug/vars";

var result = await HttpClientHelper.Instance.TryGetAsync(Url);

```

### Clash and Sing-Box Integration API

The second port (`StatePort2`) hosts a REST-like interface compatible with the Clash external-controller specification, enabling proxy provider manipulation and real-time traffic monitoring.

**ClashApiManager** constructs the base URL as follows:

```csharp
// v2rayN/ServiceLib/Manager/ClashApiManager.cs
private string GetApiUrl()
    => $"{Global.HttpProtocol}{Global.Loopback}:{AppManager.Instance.StatePort2}";

```

Supported operations include:

- **GET /proxies** – Retrieve the full proxy list and latency tests.
- **PATCH /proxies/{name}** – Switch the active proxy for a selector.
- **GET /configs** – Export the current running configuration.
- **PUT /configs?force=true** – Hot-reload a new YAML configuration.
- **GET /connections** – Inspect active connections.
- **DELETE /connections/{id}** – Terminate a specific connection.

For Sing-Box cores, `StatisticsSingboxService` opens a WebSocket connection to the same port to stream traffic statistics:

```csharp
// Conceptual usage within StatisticsSingboxService
var wsUrl = $"ws://{Global.Loopback}:{AppManager.Instance.StatePort2}/traffic";

```

The `CoreConfigClashService` ensures the generated Clash configuration contains the `external-controller` directive pointing to `127.0.0.1:{StatePort2}`, binding the core’s native API to the port managed by v2rayN.

## Practical Code Examples for External Integration

Because v2rayN uses standard HTTP, any language with an HTTP client can control the application. Below are minimal C# demonstrations.

### Querying V2Ray Statistics

```csharp
using System.Net.Http;
using System.Text.Json;

// Obtain the actual port from v2rayN logs or settings
int statePort = 10085; 
string url = $"http://127.0.0.1:{statePort}/debug/vars";

using var http = new HttpClient();
var json = await http.GetStringAsync(url);
var stats = JsonSerializer.Deserialize<JsonElement>(json);

Console.WriteLine($"Uplink: {stats.GetProperty("uplink").GetInt64()} bytes");
Console.WriteLine($"Downlink: {stats.GetProperty("downlink").GetInt64()} bytes");

```

### Managing Clash Proxies via REST

```csharp
using System.Net.Http;
using System.Text;
using System.Text.Json;

int apiPort = 10086; // StatePort2
string baseUrl = $"http://127.0.0.1:{apiPort}";

using var client = new HttpClient();

// List all proxies
var proxies = await client.GetStringAsync($"{baseUrl}/proxies");
Console.WriteLine(proxies);

// Switch active proxy to "🇯🇵 Japan"
var payload = new { type = "select", name = "🇯🇵 Japan" };
var content = new StringContent(JsonSerializer.Serialize(payload), 
                                Encoding.UTF8, "application/json");
await client.PatchAsync($"{baseUrl}/proxies", content);

```

### Pushing Configuration Updates

```csharp
string newConfig = await File.ReadAllTextAsync("custom-config.yaml");
var yamlContent = new StringContent(newConfig, Encoding.UTF8, "application/x-yaml");

// force=true hot-reloads without restarting the core
await client.PutAsync($"{baseUrl}/configs?force=true", yamlContent);

```

## Key Source Files and Implementation Details

| File | Role | Location |
|------|------|----------|
| [`Global.cs`](https://github.com/2dust/v2rayN/blob/main/Global.cs) | Defines constants (`Loopback`, `HttpProtocol`, `InboundAPIProtocol`) | [`v2rayN/ServiceLib/Global.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Global.cs) |
| [`AppManager.cs`](https://github.com/2dust/v2rayN/blob/main/AppManager.cs) | Allocates and exposes `StatePort` and `StatePort2` | [`v2rayN/ServiceLib/Manager/AppManager.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Manager/AppManager.cs) |
| [`V2rayStatisticService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayStatisticService.cs) | Injects the dokodemo-door inbound for V2Ray metrics | [`v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs) |
| [`StatisticsXrayService.cs`](https://github.com/2dust/v2rayN/blob/main/StatisticsXrayService.cs) | Polls `/debug/vars` and parses Prometheus-style JSON | [`v2rayN/ServiceLib/Services/Statistics/StatisticsXrayService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/Statistics/StatisticsXrayService.cs) |
| [`ClashApiManager.cs`](https://github.com/2dust/v2rayN/blob/main/ClashApiManager.cs) | Implements REST client for Clash external-controller endpoints | [`v2rayN/ServiceLib/Manager/ClashApiManager.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Manager/ClashApiManager.cs) |
| [`StatisticsSingboxService.cs`](https://github.com/2dust/v2rayN/blob/main/StatisticsSingboxService.cs) | Consumes WebSocket traffic stream on `StatePort2` | [`v2rayN/ServiceLib/Services/Statistics/StatisticsSingboxService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/Statistics/StatisticsSingboxService.cs) |
| [`CoreConfigClashService.cs`](https://github.com/2dust/v2rayN/blob/main/CoreConfigClashService.cs) | Writes `external-controller` directive into generated Clash YAML | [`v2rayN/ServiceLib/Services/CoreConfig/CoreConfigClashService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigClashService.cs) |
| [`HttpClientHelper.cs`](https://github.com/2dust/v2rayN/blob/main/HttpClientHelper.cs) | Internal wrapper for HTTP requests (redirects, TLS, timeouts) | [`v2rayN/ServiceLib/Helper/HttpClientHelper.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Helper/HttpClientHelper.cs) |

## Summary

- **v2rayN exposes APIs for external control and integration** through two local HTTP listeners bound to `127.0.0.1`, eliminating the need for custom SDKs or binary protocols.
- The **V2Ray statistics API** runs on a dynamically allocated port (`StatePort`) via a `dokodemo-door` inbound, exposing Prometheus-style metrics at `/debug/vars`.
- The **Clash/Sing-Box integration API** operates on a second port (`StatePort2`), implementing the standard Clash external-controller REST specification for proxy management and configuration hot-reloading.
- **Sing-Box specific traffic statistics** are streamed via WebSocket on the same `StatePort2`, providing real-time byte counters.
- All endpoints are private by default (localhost-only), making them safe for local automation while preventing remote exposure.

## Frequently Asked Questions

### How do I discover the current API port for a running v2rayN instance?

v2rayN assigns random free ports at startup to avoid conflicts. You can find the active ports by checking the application logs or by inspecting the [`guiNConfig.json`](https://github.com/2dust/v2rayN/blob/main/guiNConfig.json) settings file in the v2rayN directory. The values are stored as `statePort` (for V2Ray statistics) and `statePort2` (for Clash/Sing-Box API).

### Is the v2rayN API accessible from remote machines?

No. By design, both the V2Ray statistics endpoint and the Clash integration API bind exclusively to `127.0.0.1` (localhost). This is hardcoded in `Global.Loopback` and enforced during inbound configuration. If you need remote management, you must set up a reverse proxy or tunnel, as v2rayN does not expose these APIs on external interfaces for security reasons.

### Can I use the Clash API to switch proxies without restarting the core?

Yes. The Clash integration API supports hot-reloading via the `PATCH /proxies` endpoint. When you send a PATCH request to switch the active proxy, v2rayN communicates with the running Clash core through the `external-controller` interface on `StatePort2`. This operation does not require restarting the v2rayN application or the underlying core process.

### What is the difference between StatePort and StatePort2?

`StatePort` (accessed via `AppManager.Instance.StatePort`) is dedicated to the V2Ray/Xray core statistics API. It serves Prometheus-style metrics through a `dokodemo-door` inbound at `/debug/vars`. `StatePort2` (accessed via `AppManager.Instance.StatePort2`) is reserved for Clash and Sing-Box integration, exposing REST endpoints for proxy management and WebSocket streams for real-time traffic data.