# Proxy access — PapaProxy.net API reference

Page: https://papaproxy.net/developers/reference/proxy-access.php
Last updated: November 9, 2026
Base URL: `https://papaproxy.net/account_new`. Authentication and conventions: https://papaproxy.net/developers/reference/

### List proxy IPs

`GET /api/v1/customer/services/{service_id}/proxy/ips`

- Access: API key required · scope `services:read`

List the proxy IP endpoints of one of your services.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |

Request examples:

cURL:

```bash
curl -X GET "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/ips" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY"
```

Python:

```python
import os

import requests

resp = requests.get(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/ips",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/ips", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
  },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/ips');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
    ],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/ips", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — List of proxy IPs for a service.

Example response:

```json
{
  "service_id": "cb532178-5b03-506a-84ea-0230ff28576b",
  "ips": [
    {
      "ip": "192.0.2.10",
      "country": "US",
      "type": "socks5"
    },
    {
      "ip": "192.0.2.11",
      "country": "US",
      "type": "socks5"
    }
  ],
  "format_hints": {},
  "geo_source": "maxmind"
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id` | string (uuid) | yes | ID of the service. |
| `ips` | array of object | yes |  |
| `ips[].ip` | string | yes | IPv4 or IPv6 address |
| `ips[].port` | integer, nullable | no | Minimum: 1 · Maximum: 65535 |
| `ips[].country` | string, nullable | no | ISO 3166-1 alpha-2 country code of the IP. |
| `ips[].type` | string, nullable | no |  |
| `format_hints` | object, nullable | no | Display hints for proxy IP list rendering. |
| `format_hints.host_port` | string, nullable | no |  |
| `format_hints.auth_url` | string, nullable | no |  |
| `geo_source` | string, nullable | no |  |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:read`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:read"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### Get proxy credentials

`GET /api/v1/customer/services/{service_id}/proxy/auth`

- Access: API key required · scope `services:read`

Get the proxy connection credentials for one of your services.

The password is masked by default; pass `reveal=true` to receive it
in plain text.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |
| `reveal (query)` | boolean | no | Default: `false` |

Request examples:

cURL:

```bash
curl -X GET "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY"
```

Python:

```python
import os

import requests

resp = requests.get(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
  },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
    ],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Current proxy auth status.

Example response:

```json
{
  "username": "pp_user_3fa85f64",
  "protocols": [
    "socks5",
    "http",
    "https"
  ],
  "endpoints": [
    {
      "protocol": "socks5",
      "label": "SOCKS5",
      "scheme": "socks5",
      "port": 1080,
      "port_whitelist": 1085,
      "http2": false,
      "udp": true,
      "noauth_only": false
    },
    {
      "protocol": "http",
      "label": "HTTP",
      "scheme": "http",
      "port": 8080,
      "port_whitelist": 8085,
      "http2": false,
      "udp": false,
      "noauth_only": false
    }
  ],
  "whitelist_ips": [
    "203.0.113.11"
  ],
  "password_set": true,
  "udp_enabled": false
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `username` | string | yes | Proxy username. |
| `password` | string, nullable | no |  |
| `protocols` | array of string | no |  |
| `endpoints` | array of object | no |  |
| `endpoints[].protocol` | string | yes |  |
| `endpoints[].label` | string | yes |  |
| `endpoints[].scheme` | string | yes |  |
| `endpoints[].port` | integer, nullable | no |  |
| `endpoints[].port_whitelist` | integer, nullable | no |  |
| `endpoints[].http2` | boolean | no | Default: `false` |
| `endpoints[].udp` | boolean | no | Default: `false` |
| `endpoints[].noauth_only` | boolean | no | Default: `false` |
| `endpoints[].hostname_template` | string, nullable | no |  |
| `whitelist_ips` | array of string | no | Whitelisted IPv4 addresses. |
| `password_set` | boolean | no | Default: `false` |
| `udp_enabled` | boolean | no | Whether UDP is enabled. · Default: `false` |
| `conn_cap` | integer, nullable | no | Concurrent connection limit of the service. |
| `whitelist_conn_limits` | object, nullable | no |  |
| `rotating_gateway` | object, nullable | no | Rotating gateway hostnames and ports for this service. The list fields are authoritative; `entry_host` and `https_host` are the first entries. Lists are empty when a gateway type isn't available for the service. |
| `rotating_gateway.entry_hosts` | array of string | no |  |
| `rotating_gateway.https_hosts` | array of string | no |  |
| `rotating_gateway.sticky_hosts` | array of string | no |  |
| `rotating_gateway.entry_host` | string, nullable | no |  |
| `rotating_gateway.https_host` | string, nullable | no |  |
| `rotating_gateway.http_ports` | array of integer | no | HTTP ports. |
| `rotating_gateway.socks_ports` | array of integer | no | SOCKS5 ports. |
| `rotating_gateway.sticky_http` | integer | no | Default: `5080` |
| `rotating_gateway.sticky_socks5` | integer | no | Default: `4080` |
| `rotating_gateway.sticky_https` | integer | no | Default: `4443` |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:read`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:read"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### Change proxy credentials

`PUT /api/v1/customer/services/{service_id}/proxy/auth`

- Access: API key required · scope `services:write`

Update proxy credentials — rotate the password or change the login.

Idempotent: a repeated identical payload produces the same state.
When rotating, the new password is returned exactly once in the
response body.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |

Request body (JSON):

| Field | Type | Required | Description |
|---|---|---|---|
| `rotate_password` | boolean | no | Default: `false` |
| `udp_enabled` | boolean, nullable | no | Whether UDP is enabled. |
| `new_username` | string, nullable | no | New proxy login. Must not be taken by another account. · Min length: 3 · Max length: 32 |
| `whitelist_ips` | array of string, nullable | no | Whitelisted IPv4 addresses. |

Request examples:

cURL:

```bash
curl -X PUT "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"whitelist_ips": ["203.0.113.10"]}'
```

Python:

```python
import os

import requests

resp = requests.put(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    json={
        "whitelist_ips": [
            "203.0.113.10"
        ]
    },
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "whitelist_ips": [
      "203.0.113.10"
    ]
  }),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'whitelist_ips' => ['203.0.113.10']
    ]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	req, err := http.NewRequest("PUT", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/auth", strings.NewReader(`{"whitelist_ips": ["203.0.113.10"]}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Current proxy auth status.

Example response:

```json
{
  "username": "pp_user_3fa85f64",
  "protocols": [
    "socks5",
    "http",
    "https"
  ],
  "endpoints": [
    {
      "protocol": "socks5",
      "label": "SOCKS5",
      "scheme": "socks5",
      "port": 1080,
      "port_whitelist": 1085,
      "http2": false,
      "udp": true,
      "noauth_only": false
    },
    {
      "protocol": "http",
      "label": "HTTP",
      "scheme": "http",
      "port": 8080,
      "port_whitelist": 8085,
      "http2": false,
      "udp": false,
      "noauth_only": false
    }
  ],
  "whitelist_ips": [
    "203.0.113.11"
  ],
  "password_set": true,
  "udp_enabled": false
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `username` | string | yes | Proxy username. |
| `password` | string, nullable | no |  |
| `protocols` | array of string | no |  |
| `endpoints` | array of object | no |  |
| `endpoints[].protocol` | string | yes |  |
| `endpoints[].label` | string | yes |  |
| `endpoints[].scheme` | string | yes |  |
| `endpoints[].port` | integer, nullable | no |  |
| `endpoints[].port_whitelist` | integer, nullable | no |  |
| `endpoints[].http2` | boolean | no | Default: `false` |
| `endpoints[].udp` | boolean | no | Default: `false` |
| `endpoints[].noauth_only` | boolean | no | Default: `false` |
| `endpoints[].hostname_template` | string, nullable | no |  |
| `whitelist_ips` | array of string | no | Whitelisted IPv4 addresses. |
| `password_set` | boolean | no | Default: `false` |
| `udp_enabled` | boolean | no | Whether UDP is enabled. · Default: `false` |
| `conn_cap` | integer, nullable | no | Concurrent connection limit of the service. |
| `whitelist_conn_limits` | object, nullable | no |  |
| `rotating_gateway` | object, nullable | no | Rotating gateway hostnames and ports for this service. The list fields are authoritative; `entry_host` and `https_host` are the first entries. Lists are empty when a gateway type isn't available for the service. |
| `rotating_gateway.entry_hosts` | array of string | no |  |
| `rotating_gateway.https_hosts` | array of string | no |  |
| `rotating_gateway.sticky_hosts` | array of string | no |  |
| `rotating_gateway.entry_host` | string, nullable | no |  |
| `rotating_gateway.https_host` | string, nullable | no |  |
| `rotating_gateway.http_ports` | array of integer | no | HTTP ports. |
| `rotating_gateway.socks_ports` | array of integer | no | SOCKS5 ports. |
| `rotating_gateway.sticky_http` | integer | no | Default: `5080` |
| `rotating_gateway.sticky_socks5` | integer | no | Default: `4080` |
| `rotating_gateway.sticky_https` | integer | no | Default: `4443` |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:write`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:write"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### List whitelisted IPs

`GET /api/v1/customer/services/{service_id}/proxy/whitelist`

- Access: API key required · scope `services:read`

List the IP whitelist entries of one of your proxy services.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |

Request examples:

cURL:

```bash
curl -X GET "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY"
```

Python:

```python
import os

import requests

resp = requests.get(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
  },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
    ],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Whitelisted IPs and the service's concurrent connection limit.

Example response:

```json
{
  "service_id": "cb532178-5b03-506a-84ea-0230ff28576b",
  "entries": [
    {
      "ip_or_cidr": "203.0.113.11",
      "conn_limit": 1500,
      "is_paid": false
    }
  ],
  "conn_cap": 1500,
  "capacity": 5,
  "free_quota": 5,
  "used": 1,
  "paid_slots": 0
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id` | string (uuid) | yes | ID of the service. |
| `entries` | array of object | yes |  |
| `entries[].ip_or_cidr` | string | yes |  |
| `entries[].label` | string, nullable | no |  |
| `entries[].conn_limit` | integer, nullable | no | Concurrent connections allowed from this IP. |
| `entries[].is_paid` | boolean | no | Default: `false` |
| `conn_cap` | integer | yes | Concurrent connection limit of the service. |
| `capacity` | integer | no | Default: `0` |
| `free_quota` | integer | no | Default: `0` |
| `used` | integer | no | Default: `0` |
| `paid_slots` | integer | no | Default: `0` |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:read`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:read"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### Add a whitelisted IP

`POST /api/v1/customer/services/{service_id}/proxy/whitelist`

- Access: API key required · scope `services:write`

Add a single IPv4 address to the service's IP whitelist.

Only single addresses are accepted (no CIDR subnets).

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |

Request body (JSON):

| Field | Type | Required | Description |
|---|---|---|---|
| `ip_or_cidr` | string | yes | Single IPv4 address (CIDR subnets are not supported) |
| `label` | string, nullable | no |  |
| `conn_limit` | integer, nullable | no | Concurrent connections allowed from this IP. · Minimum: 0 |

Request examples:

cURL:

```bash
curl -X POST "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ip_or_cidr": "203.0.113.10"}'
```

Python:

```python
import os

import requests

resp = requests.post(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    json={
        "ip_or_cidr": "203.0.113.10"
    },
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "ip_or_cidr": "203.0.113.10"
  }),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'ip_or_cidr' => '203.0.113.10'
    ]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	req, err := http.NewRequest("POST", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist", strings.NewReader(`{"ip_or_cidr": "203.0.113.10"}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Whitelisted IPs and the service's concurrent connection limit.

Example response:

```json
{
  "service_id": "cb532178-5b03-506a-84ea-0230ff28576b",
  "entries": [
    {
      "ip_or_cidr": "203.0.113.11",
      "conn_limit": 750,
      "is_paid": false
    },
    {
      "ip_or_cidr": "203.0.113.77",
      "conn_limit": 750,
      "is_paid": false
    }
  ],
  "conn_cap": 1500,
  "capacity": 5,
  "free_quota": 5,
  "used": 2,
  "paid_slots": 0
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id` | string (uuid) | yes | ID of the service. |
| `entries` | array of object | yes |  |
| `entries[].ip_or_cidr` | string | yes |  |
| `entries[].label` | string, nullable | no |  |
| `entries[].conn_limit` | integer, nullable | no | Concurrent connections allowed from this IP. |
| `entries[].is_paid` | boolean | no | Default: `false` |
| `conn_cap` | integer | yes | Concurrent connection limit of the service. |
| `capacity` | integer | no | Default: `0` |
| `free_quota` | integer | no | Default: `0` |
| `used` | integer | no | Default: `0` |
| `paid_slots` | integer | no | Default: `0` |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:write`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:write"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### Remove a whitelisted IP

`DELETE /api/v1/customer/services/{service_id}/proxy/whitelist`

- Access: API key required · scope `services:write`

Remove an IP address from the service's IP whitelist.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |
| `ip_or_cidr (query)` | string | yes | IP address to remove from the whitelist |

Request examples:

cURL:

```bash
curl -X DELETE "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist?ip_or_cidr=203.0.113.10" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY"
```

Python:

```python
import os

import requests

resp = requests.delete(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist?ip_or_cidr=203.0.113.10",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist?ip_or_cidr=203.0.113.10", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
  },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist?ip_or_cidr=203.0.113.10');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
    ],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/whitelist?ip_or_cidr=203.0.113.10", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Whitelisted IPs and the service's concurrent connection limit.

Example response:

```json
{
  "service_id": "cb532178-5b03-506a-84ea-0230ff28576b",
  "entries": [
    {
      "ip_or_cidr": "203.0.113.11",
      "conn_limit": 1500,
      "is_paid": false
    }
  ],
  "conn_cap": 1500,
  "capacity": 5,
  "free_quota": 5,
  "used": 1,
  "paid_slots": 0
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id` | string (uuid) | yes | ID of the service. |
| `entries` | array of object | yes |  |
| `entries[].ip_or_cidr` | string | yes |  |
| `entries[].label` | string, nullable | no |  |
| `entries[].conn_limit` | integer, nullable | no | Concurrent connections allowed from this IP. |
| `entries[].is_paid` | boolean | no | Default: `false` |
| `conn_cap` | integer | yes | Concurrent connection limit of the service. |
| `capacity` | integer | no | Default: `0` |
| `free_quota` | integer | no | Default: `0` |
| `used` | integer | no | Default: `0` |
| `paid_slots` | integer | no | Default: `0` |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:write`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:write"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### Check IP refresh cost

`GET /api/v1/customer/services/{service_id}/proxy/refresh-status`

- Access: API key required · scope `services:read`

Check whether the next IP refresh for this service is free or paid.

Read-only.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |

Request examples:

cURL:

```bash
curl -X GET "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh-status" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY"
```

Python:

```python
import os

import requests

resp = requests.get(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh-status",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh-status", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
  },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh-status');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
    ],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh-status", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Status of the next IP reallocation for a service.

Example response:

```json
{
  "service_id": "cb532178-5b03-506a-84ea-0230ff28576b",
  "is_free": false,
  "free_window_days": 8,
  "days_since_start": 0,
  "next_free_refresh_at": "2026-11-15T14:26:50.787259Z",
  "price_cents": 1000,
  "is_pool_service": true
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id` | string (uuid) | yes | ID of the service. |
| `is_free` | boolean | yes |  |
| `free_window_days` | integer | yes |  |
| `days_since_start` | integer, nullable | yes |  |
| `next_free_refresh_at` | string (date-time), nullable | no |  |
| `price_cents` | integer | yes | Price in cents. |
| `is_pool_service` | boolean | yes | Whether the service uses a shared IP pool. |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:read`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:read"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error: a field is missing or has the wrong type or value.

  Example:

  ```json
  {"detail": "Validation error"}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```


### Refresh proxy IPs

`POST /api/v1/customer/services/{service_id}/proxy/refresh`

- Access: API key required · scope `services:write`

Replace the IPs of a proxy service. Pass `target_ips` to replace only specific addresses, or omit it to refresh the whole list. For dedicated proxies, `target_ips` is required; without it the response is `422` with `detail.code = "dedicated_refresh_target_required"`. Scheduled refreshes are free; an off-cycle refresh is charged to your wallet — check `GET …/proxy/refresh-status` first. Pass `idempotency_key` so a retried call can't charge twice.

Parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id (path)` | string (uuid) | yes | ID of the service. |

Request body (JSON):

| Field | Type | Required | Description |
|---|---|---|---|
| `idempotency_key` | string | yes | Unique key for this refresh intent; retries with the same key return the original result and never charge twice. |
| `target_ips` | array of string, nullable | no | Specific currently-allocated IPs to replace. Omit to refresh the entire allocation. |

Request examples:

cURL:

```bash
curl -X POST "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh" \
  -H "Authorization: Bearer $PAPAPROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"idempotency_key": "refresh-2026-001"}'
```

Python:

```python
import os

import requests

resp = requests.post(
    "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh",
    headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
    json={
        "idempotency_key": "refresh-2026-001"
    },
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
```

Node.js:

```javascript
const resp = await fetch("https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "idempotency_key": "refresh-2026-001"
  }),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());
```

PHP:

```php
<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAPAPROXY_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'idempotency_key' => 'refresh-2026-001'
    ]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));
```

Go:

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	req, err := http.NewRequest("POST", "https://papaproxy.net/account_new/api/v1/customer/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/proxy/refresh", strings.NewReader(`{"idempotency_key": "refresh-2026-001"}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PAPAPROXY_API_KEY"))
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	data, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Status, string(data))
}
```

Responses:

- `200` — Result of a successful IP reallocation.

| Field | Type | Required | Description |
|---|---|---|---|
| `service_id` | string (uuid) | yes | ID of the service. |
| `ip_count` | integer | yes | Number of IPs. |
| `charged_cents` | integer | yes | Amount charged to your wallet, in cents. |
| `ledger_entry_id` | string (uuid), nullable | yes |  |
| `new_ips` | array of string | no |  |

- `401` — The API key is missing, malformed, revoked, or expired, or the account is inactive.

  Example:

  ```json
  {"detail": "Invalid or revoked API key."}
  ```

- `403` — The API key lacks scope `services:write`.

  Example:

  ```json
  {"detail": "API key is missing required scope: services:write"}
  ```

- `404` — Service not found, or it doesn't belong to your account.

  Example:

  ```json
  {"detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found."}
  ```

- `422` — Validation error, or `target_ips` is missing for a dedicated service.

  Example:

  ```json
  {"detail": {"code": "dedicated_refresh_target_required", "message": "…"}}
  ```

- `429` — Too many requests: the per-account limit is 60 requests per minute, shared by all keys and the MCP server. Retry with exponential backoff.

  Example:

  ```json
  {"detail": "Too Many Requests"}
  ```

