Orders
3 endpoints · base URL https://papaproxy.net/account_new · authentication
Place an order
/api/v1/billing/composite/orderservices:writeBuy a proxy package (datacenter or ISP proxies) built from one or more segments ([{country, count}]): at least 100 IPs in total and at least 10 per country. Availability and price are re-checked at order time, and a single service is created with all segments. For dedicated proxies, use POST /api/v1/billing/dedicated/order.
whitelist_ipsmust contain at least one IPv4 address. Without it the response is422withdetail.error = "WHITELIST_REQUIRED".- With
use_balance=true, your wallet balance is applied first. If it covers the total, the order is paid right away. Otherwise the service is created withstatus: "pending"andpayment_required: true:balance_applied_centsis the part covered by your balance, andamount_due_centsis the remainder. Pay it in the Dashboard under Pending payments; the IPs are issued after payment. - With
use_balance=false(the default), the whole amount is due the same way. - Pass
idempotency_key: a retry with the same key returns the original order and doesn't charge again. Without a key, every request creates a new order, even with identical segments.
Request body
| Field | Type | Description |
|---|---|---|
product_id | string (uuid), nullable | Optional catalog product to base the order on. When omitted, the product is selected by product_kind. |
segments required | array of object | One or more segments forming the mixMin items: 1 |
segments[].country required | integer or string | ISO 3166-1 alpha-2 country code ("DE", "GB"). A numeric country ID from GET /api/v1/billing/countries is also accepted. |
segments[].count required | integer | Number of IPs in this country. At least 10; the order total must be at least 100.Minimum: 1Maximum: 100000 |
product_kind | string | Product: proxy_datacenter or proxy_isp. Dedicated proxies are priced and ordered through /api/v1/billing/dedicated/*.Default: "proxy_datacenter" |
period_months | integer | Term length in months (1, 3, 6, or 12). Longer terms get a discount. Default: 1. |
whitelist_ips | array of string | IPv4 addresses to whitelist at order time. Proxy orders need at least one; without it the request fails with HTTP 422 and nothing is charged. |
auto_renew | boolean | Renew the service automatically when the term ends. Default: true. |
use_balance | boolean | Apply your wallet balance first. Default: false — the full amount is due through a payment processor and the service stays pending until it's paid. |
geo_source | string | Geo source for country lookups: maxmind (geolocation) or ripe (RIR allocation). Default maxmind.One of: maxmind, ripe |
idempotency_key | string, nullable | Idempotency key. A retry with the same key returns the original order without charging again. Without a key, every request creates a new order. |
promo_code | string, nullable | Optional promo code. The discount applies to the first term only; renewals are charged at the regular price.Max length: 64 |
trial | boolean | Order the paid 48-hour trial instead of a full term.Default: false |
extra_whitelist_count | integer | Paid whitelist IPs beyond the free allowance. Included in the charge.Minimum: 0Maximum: 10000Default: 0 |
udp_unlock | boolean | Add the UDP add-on. Included in the charge.Default: false |
extra_connections_count | integer | Paid concurrent connections beyond those included. Included in the charge. For an existing service, buy the extra_connections add-on instead.Minimum: 0Maximum: 10000Default: 0 |
Request example Try it in the Dashboard
curl -X POST "https://papaproxy.net/account_new/api/v1/billing/composite/order" \
-H "Authorization: Bearer $PAPAPROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"segments": [{"country": "US", "count": 100}], "period_months": 1, "whitelist_ips": ["203.0.113.10"], "use_balance": true, "idempotency_key": "order-2026-001"}'import os
import requests
resp = requests.post(
"https://papaproxy.net/account_new/api/v1/billing/composite/order",
headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
json={
"segments": [
{
"country": "US",
"count": 100
}
],
"period_months": 1,
"whitelist_ips": [
"203.0.113.10"
],
"use_balance": True,
"idempotency_key": "order-2026-001"
},
timeout=30,
)
resp.raise_for_status()
print(resp.json())const resp = await fetch("https://papaproxy.net/account_new/api/v1/billing/composite/order", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"segments": [
{
"country": "US",
"count": 100
}
],
"period_months": 1,
"whitelist_ips": [
"203.0.113.10"
],
"use_balance": true,
"idempotency_key": "order-2026-001"
}),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/billing/composite/order');
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([
'segments' => [[
'country' => 'US',
'count' => 100
]],
'period_months' => 1,
'whitelist_ips' => ['203.0.113.10'],
'use_balance' => true,
'idempotency_key' => 'order-2026-001'
]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
req, err := http.NewRequest("POST", "https://papaproxy.net/account_new/api/v1/billing/composite/order", strings.NewReader(`{"segments": [{"country": "US", "count": 100}], "period_months": 1, "whitelist_ips": ["203.0.113.10"], "use_balance": true, "idempotency_key": "order-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
201The order was created. Checkpayment_requiredandamount_due_cents. · 27 fieldsExample response · JSON{ "service_id": "dea53a24-1760-501d-a60a-d438bd176599", "status": "pending", "segments": [ { "country": 197148, "country_code": "US", "count": 100, "unit_base_cents": 19, "type_multiplier": 1.0, "geo_multiplier": 1.0, "segment_price_cents": 1900, "available": true } ], "total_ip": 100, "total_price_cents": 1900, "period_months": 1, "discount_pct": 0, "monthly_price_cents": 1900, "balance_applied_cents": 1777, "amount_due_cents": 123, "invoice_url": null, "payment_required": true, "intent_id": "2dbb7b45-5fb8-5bc9-834f-32aeaa569d72", "promo_code_applied": null, "promo_discount_cents": 0, "total_before_promo_cents": null, "trial": false, "trial_period_days": null, "addon_monthly_cents": 0 }Field Type Description service_idrequiredstring (uuid) Created service ID statusrequiredstring activewhen the order is paid,pendingwhileamount_due_centsis unpaid.segmentsarray of object Per-segment breakdown as ordered segments[].countryrequiredinteger Numeric country ID. The ISO code is in country_code.segments[].country_codestring, nullable ISO 3166-1 alpha-2 country code (e.g. "DE"). segments[].countrequiredinteger segments[].unit_base_centsrequiredinteger Volume-tier base unit price in integer cents per IP segments[].type_multiplierrequirednumber Product multiplier applied to the base rate. segments[].geo_multiplierrequirednumber Country multiplier (default 1.0). segments[].segment_price_centsrequiredinteger Segment price: count × base rate × product multiplier × country multiplier, rounded up to whole cents. segments[].availablerequiredboolean Whether enough IPs are available for this segment. total_iprequiredinteger Total number of IPs. total_price_centsrequiredinteger Discounted total charged for the full period in integer cents period_monthsinteger Billing period length in months (1/3/6/12)Default: 1discount_pctinteger Applied period discount as a whole percentage (0/10/15/20)Default: 0monthly_price_centsinteger Undiscounted monthly total (sum of segment prices) in integer centsDefault: 0balance_applied_centsinteger Amount paid from your wallet balance, in cents. Zero when use_balanceis false.Default:0amount_due_centsinteger Amount still due through a payment processor, in cents. Zero when the balance covers the order.Default: 0invoice_urlstring, nullable Link to the invoice, if one was issued. payment_requiredboolean truewhenamount_due_centsmust still be paid. Pay it in the Dashboard under Pending payments.Default:falseintent_idstring (uuid), nullable ID of the pending payment when payment_requiredistrue.promo_code_appliedstring, nullable Promo code applied to the order, if any. promo_discount_centsinteger Promo discount applied to the order, in cents.Minimum: 0Default: 0total_before_promo_centsinteger, nullable Pre-promo total when a promo was applied; null otherwise. trialboolean True when the service is a paid trial.Default: falsetrial_period_daysinteger, nullable Trial length in days; null for regular orders. addon_monthly_centsinteger Monthly cost of add-ons bought with the order, in cents.Minimum: 0Default: 0401The API key is missing, malformed, revoked, or expired, or the account is inactive.Example · JSON{ "detail": "Invalid or revoked API key." }403The API key lacks scopeservices:write.Example · JSON{ "detail": "API key is missing required scope: services:write" }422Validation error, fewer than 100 IPs in total, or no whitelisted IP.Example · JSON{ "detail": { "error": "WHITELIST_REQUIRED", "message": "A proxy service requires at least one whitelisted IP at order time. …" } }429Too 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" }
Quote additional IPs
/api/v1/billing/services/{service_id}/add-ips/quotePreview adding IPs to an active service: the prorated charge for the rest of the current term and the new renewal price. No charge and no changes to the service. Works with any valid API key.
- Proxy packages: at least 100 IPs per request and at least 10 per country, as with new orders. A country below 10 IPs is listed in
errors. - Dedicated proxies: from 1 IP.
Parameters
| Field | Type | Description |
|---|---|---|
service_id (path) required | string (uuid) | ID of the service. |
Request body
| Field | Type | Description |
|---|---|---|
segments required | array of object | One or more segments to addMin items: 1 |
segments[].country required | integer or string | ISO 3166-1 alpha-2 country code ("DE", "GB"). A numeric country ID from GET /api/v1/billing/countries is also accepted. |
segments[].count required | integer | Number of IPs to add in this country. Proxy packages: at least 10 per country and 100 per request. Dedicated proxies: from 1.Minimum: 1Maximum: 10000 |
Request example Try it in the Dashboard
curl -X POST "https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips/quote" \
-H "Authorization: Bearer $PAPAPROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"segments": [{"country": "US", "count": 100}]}'import os
import requests
resp = requests.post(
"https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips/quote",
headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
json={
"segments": [
{
"country": "US",
"count": 100
}
]
},
timeout=30,
)
resp.raise_for_status()
print(resp.json())const resp = await fetch("https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips/quote", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"segments": [
{
"country": "US",
"count": 100
}
]
}),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips/quote');
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([
'segments' => [[
'country' => 'US',
'count' => 100
]]
]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
req, err := http.NewRequest("POST", "https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips/quote", strings.NewReader(`{"segments": [{"country": "US", "count": 100}]}`))
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
200Non-binding preview of an add-ips top-up. · 20 fieldsExample response · JSON{ "service_id": "cb532178-5b03-506a-84ea-0230ff28576b", "segments": [ { "country": 197148, "country_code": "US", "count": 100, "unit_base_cents": 19, "type_multiplier": 1.0, "geo_multiplier": 1.0, "segment_price_cents": 1900, "available": true } ], "errors": [], "added_ip_count": 100, "monthly_price_added_cents": 1900, "days_remaining": 60, "days_per_month": 30, "prorated_charge_cents": 3798, "current_price_cents": 9500, "new_renewal_price_cents": 11400 }Field Type Description service_idrequiredstring (uuid) ID of the service. segmentsarray of object Per-segment pricing breakdown for the added IPs segments[].countryrequiredinteger Numeric country ID. The ISO code is in country_code.segments[].country_codestring, nullable ISO 3166-1 alpha-2 country code (e.g. "DE"). segments[].countrequiredinteger segments[].unit_base_centsrequiredinteger Volume-tier base unit price in integer cents per IP segments[].type_multiplierrequirednumber Product multiplier applied to the base rate. segments[].geo_multiplierrequirednumber Country multiplier (default 1.0). segments[].segment_price_centsrequiredinteger Segment price: count × base rate × product multiplier × country multiplier, rounded up to whole cents. segments[].availablerequiredboolean Whether enough IPs are available for this segment. errorsarray of object Segments that can't be fulfilled; ordering them would fail with HTTP 409. errors[].countryrequiredinteger Numeric country ID of the segment that was left out. errors[].messagerequiredstring added_ip_countrequiredinteger Total IPs across the added segments monthly_price_added_centsrequiredinteger Undiscounted full-monthly cost of the added segments days_remainingrequiredinteger Days left in the current term. days_per_monthinteger Days per month used for proration.Default: 30prorated_charge_centsrequiredinteger Amount charged now for the remainder of the current period current_price_centsrequiredinteger Service's current full-period renewal price new_renewal_price_centsrequiredinteger Renewal price after this top-up (current + added segments' full-period cost) 401The API key is missing, malformed, revoked, or expired, or the account is inactive.Example · JSON{ "detail": "Invalid or revoked API key." }404Service not found, or it doesn't belong to your account.Example · JSON{ "detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found." }422Validation error, or fewer than 100 IPs in a proxy-package request.Example · JSON{ "detail": "Validation error" }429Too 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 IPs to a service
/api/v1/billing/services/{service_id}/add-ipsservices:writeAdd IPs to an active service — in the same country or new ones. You're charged the prorated amount for the rest of the current term, and the renewal price increases accordingly. Get the exact amount from POST …/add-ips/quote first.
- Proxy packages: at least 100 IPs per request and at least 10 per country. Dedicated proxies: from 1 IP.
idempotency_keyis required. A retry with the same key returns the original result and doesn't charge again.- Insufficient balance returns
402withdetail.detail = "insufficient_funds",required_cents,balance_cents, anddeficit_cents. Nothing is charged.
Parameters
| Field | Type | Description |
|---|---|---|
service_id (path) required | string (uuid) | ID of the service. |
Request body
| Field | Type | Description |
|---|---|---|
segments required | array of object | One or more segments to addMin items: 1 |
segments[].country required | integer or string | ISO 3166-1 alpha-2 country code ("DE", "GB"). A numeric country ID from GET /api/v1/billing/countries is also accepted. |
segments[].count required | integer | Number of IPs to add in this country. Proxy packages: at least 10 per country and 100 per request. Dedicated proxies: from 1.Minimum: 1Maximum: 10000 |
idempotency_key required | string | Client-supplied idempotency key. Must be unique per intent.Min length: 1 |
Request example Try it in the Dashboard
curl -X POST "https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips" \
-H "Authorization: Bearer $PAPAPROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"segments": [{"country": "US", "count": 100}], "idempotency_key": "add-ips-2026-001"}'import os
import requests
resp = requests.post(
"https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips",
headers={"Authorization": f"Bearer {os.environ['PAPAPROXY_API_KEY']}"},
json={
"segments": [
{
"country": "US",
"count": 100
}
],
"idempotency_key": "add-ips-2026-001"
},
timeout=30,
)
resp.raise_for_status()
print(resp.json())const resp = await fetch("https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAPAPROXY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"segments": [
{
"country": "US",
"count": 100
}
],
"idempotency_key": "add-ips-2026-001"
}),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());<?php
$ch = curl_init('https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips');
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([
'segments' => [[
'country' => 'US',
'count' => 100
]],
'idempotency_key' => 'add-ips-2026-001'
]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
var_dump($status, json_decode($response, true));package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
req, err := http.NewRequest("POST", "https://papaproxy.net/account_new/api/v1/billing/services/3fa85f64-5717-4562-b3fc-2c963f66afa6/add-ips", strings.NewReader(`{"segments": [{"country": "US", "count": 100}], "idempotency_key": "add-ips-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
200Result of a successful add-ips top-up. · 7 fieldsExample response · JSON{ "service_id": "cb532178-5b03-506a-84ea-0230ff28576b", "added_ip_count": 100, "charged_cents": 3799, "ledger_entry_id": "18e0387a-1131-5ccd-a3f7-2d406d4cf5b3", "new_total_ip": 500, "new_price_cents": 9500, "segments": [ { "count": 500, "country": 197148 } ] }Field Type Description service_idrequiredstring (uuid) ID of the service. added_ip_countrequiredinteger Number of IPs added. charged_centsrequiredinteger Prorated amount charged to the wallet ledger_entry_idstring (uuid), nullable Wallet transaction for the charge; null when nothing was charged. new_total_iprequiredinteger Total IP count on the service after the top-up new_price_centsrequiredinteger Service's new full-period renewal price segmentsarray of object All segments of the service after the top-up. 401The API key is missing, malformed, revoked, or expired, or the account is inactive.Example · JSON{ "detail": "Invalid or revoked API key." }402Insufficient wallet balance. Nothing is charged.Example · JSON{ "detail": { "detail": "insufficient_funds", "required_cents": 3799, "balance_cents": 1777, "deficit_cents": 2022 } }403The API key lacks scopeservices:write.Example · JSON{ "detail": "API key is missing required scope: services:write" }404Service not found, or it doesn't belong to your account.Example · JSON{ "detail": "Service 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found." }422Validation error (for example, a missingidempotency_key), or fewer than 100 IPs in a proxy-package request.Example · JSON{ "detail": "Validation error" }429Too 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" }
Last updated: November 9, 2026. Generated from the OpenAPI 3.1 specification (API version 0.1.0). Markdown version for AI agents.