Subscription
One endpoint. Read-only — plan changes happen in the dashboard.
The subscription ties your plan to your workspaces. Read it before any write: plan.ip_count tells you how many slots POST /workspaces expects, open_seats tells you whether adding a workspace will cost anything, and pending_change tells you whether a write will be refused.
Get subscription
GET
/subscription Read the live subscription, or null when there is none.
Returns the organization's live subscription with its plan, every IP slot, and the workspaces on it. An organization with no plan gets {"subscription": null} and success: true — no subscription is a normal state, not an error.
Example request
cURL
curl https://api.proxycharm.com/api/v1/public/subscription \
-H "Authorization: Bearer $PROXYCHARM_API_KEY" Python
import os
import requests
API_KEY = os.environ["PROXYCHARM_API_KEY"]
response = requests.get(
"https://api.proxycharm.com/api/v1/public/subscription",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
)
payload = response.json()
if not payload["success"]:
raise RuntimeError(payload["error"]["message"])
print(payload["data"]) Node.js
const apiKey = process.env.PROXYCHARM_API_KEY;
const response = await fetch("https://api.proxycharm.com/api/v1/public/subscription", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
},
});
const payload = await response.json();
if (!payload.success) {
throw new Error(payload.error.message);
}
console.log(payload.data); Go
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
type envelope struct {
Success bool `json:"success"`
Data json.RawMessage `json:"data"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
func main() {
req, err := http.NewRequest("GET", "https://api.proxycharm.com/api/v1/public/subscription", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("PROXYCHARM_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var payload envelope
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
panic(err)
}
if !payload.Success {
panic(payload.Error.Message)
}
fmt.Println(string(payload.Data))
} PHP
<?php
$apiKey = getenv("PROXYCHARM_API_KEY");
$ch = curl_init("https://api.proxycharm.com/api/v1/public/subscription");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . $apiKey,
],
]);
$payload = json_decode(curl_exec($ch), true);
curl_close($ch);
if (!$payload["success"]) {
throw new RuntimeException($payload["error"]["message"]);
}
print_r($payload["data"]); Example response
200 OK
{
"success": true,
"data": {
"subscription": {
"id": "7a2e4c19-3d5b-4f8a-9e6c-1b0d2f4a6c8e",
"status": "active",
"plan": {
"id": "1f3a5c79-2b4d-4e6f-8a0c-3d5e7f9a1b2c",
"name": "Starter",
"ip_count": 1,
"interval": "month",
"amount_cents": 1200,
"currency": "usd",
"amount_display": "12.00 USD",
"active": true,
"popular": true
},
"slots": [
{
"slot_index": 0,
"country": "US",
"status": "assigned",
"assignment_id": "9c1f7a2e-4b5d-4c3a-8e11-2d7b6f0a91c4",
"account_id": "3b7d2c48-6e19-4a5f-8b0c-9d1e2f3a4b5c"
}
],
"current_period_end": "2026-03-18T09:00:00Z",
"cancel_at_period_end": false,
"payment_action_required": false,
"pending_change": null,
"paid_seat_count": 1,
"open_seats": 0,
"accounts": [
{
"account_id": "3b7d2c48-6e19-4a5f-8b0c-9d1e2f3a4b5c",
"name": "Scraper US",
"status": "active",
"slots": [
{
"slot_index": 0,
"country": "US",
"status": "assigned",
"assignment_id": "9c1f7a2e-4b5d-4c3a-8e11-2d7b6f0a91c4",
"account_id": "3b7d2c48-6e19-4a5f-8b0c-9d1e2f3a4b5c"
}
]
}
]
}
},
"error": null,
"request_id": null,
"timestamp": "2026-02-18T09:31:04.512Z"
} Response fields
| Name | Type | Description |
|---|---|---|
subscription | object | null | The live subscription, or null when the organization has none. |
id | string | Subscription id. |
status | string | One of incomplete, active, past_due, canceling, canceled, unpaid. Only active accepts workspace changes. |
plan | object | The plan this subscription is on. |
id | string | Plan id. |
name | string | Plan name as shown on the pricing page. |
ip_count | integer | IPs included per workspace. POST /workspaces must send exactly this many slots. |
interval | string | Billing interval: month or year. |
amount_cents | integer | Price per interval in minor units. |
currency | string | Lowercase ISO 4217 currency code. |
amount_display | string | Pre-formatted price, e.g. 12.00 USD. |
active | boolean | False when the plan is archived from new checkouts. |
popular | boolean | True for the featured plan at this interval. |
slots | array<object> | Every IP slot across the subscription, flattened. |
slot_index | integer | Zero-based index of the IP slot within the subscription. |
country | string | null | Requested ISO 3166-1 alpha-2 country, or null for any country. |
status | string | pending while awaiting an IP, assigned once filled, dropped when released. |
assignment_id | string | null | Assignment holding this slot, once one is assigned. |
account_id | string | null | Workspace this slot belongs to. |
current_period_end | string | null | ISO timestamp when the current period ends. |
cancel_at_period_end | boolean | True when cancellation is scheduled for the period boundary. |
payment_action_required | boolean | True when the cardholder must complete an authentication step. |
pending_change | object | null | A plan change awaiting payment. While this is non-null, POST /workspaces returns ADD_ACCOUNT_PENDING. |
plan_id | string | Plan the subscription is moving to. |
add_slots | array<object> | Slot countries being added. |
drop_slot_indexes | array<integer> | Slot indexes being released. |
accounts | array<object> | Per-workspace add and drop intent. |
paid_seat_count | integer | Number of workspaces you are paying for. |
open_seats | integer | Paid seats with no workspace attached. While this is above zero, POST /workspaces fills a seat you already pay for instead of charging you again. |
accounts | array<object> | Billed workspaces on this subscription, each with its own slots. |
account_id | string | Workspace id. |
name | string | Workspace display name. |
status | string | Workspace lifecycle state. |
slots | array<object> | Slots belonging to this workspace. |
slot_index | integer | Zero-based index of the IP slot within the subscription. |
country | string | null | Requested ISO 3166-1 alpha-2 country, or null for any country. |
status | string | pending while awaiting an IP, assigned once filled, dropped when released. |
assignment_id | string | null | Assignment holding this slot, once one is assigned. |
account_id | string | null | Workspace this slot belongs to. |
Errors
| Code | HTTP | What it means |
|---|---|---|
PLAN_NOT_FOUND | 200 | The plan behind the live subscription could not be loaded. |
PROFILE_NOT_FOUND | 200 | The profile that created the key no longer exists. |
PROFILE_SUSPENDED | 200 | The profile that created the key is suspended. |
API_KEY_INVALID | 401 | The Authorization header is missing the key prefix, the key does not exist, or its organization has been deleted. |
API_KEY_REVOKED | 401 | The key was revoked in the dashboard. |
API_KEY_EXPIRED | 401 | The key passed the expiry date it was created with. |
RATE_LIMIT_EXCEEDED | 429 | The key exceeded its request budget for the current window. |