Products
Datacenter proxies from $19/mo Rotating proxies from $25/mo ISP proxies from $33/mo Dedicated proxies from $3.50/mo UDP proxies from $5/mo Try proxies
Use cases
Data & scraping AI services Social media & messaging E-commerce & finance Media & entertainment Marketing & ads Automation & tools All use cases →
Pricing
Full pricing table All locations Money-back guarantee
Resources
Dashboard guide API reference API and MCP Setup guides FAQ Blog For business About us Affiliate program
New dashboard
English
English Русский

Orders

3 endpoints · base URL https://papaproxy.net/account_new · authentication

Place an order

POST/api/v1/billing/composite/order
API key required scope services:write

Buy 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_ips must contain at least one IPv4 address. Without it the response is 422 with detail.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 with status: "pending" and payment_required: true: balance_applied_cents is the part covered by your balance, and amount_due_cents is 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

FieldTypeDescription
product_idstring (uuid), nullableOptional catalog product to base the order on. When omitted, the product is selected by product_kind.
segments requiredarray of objectOne or more segments forming the mixMin items: 1
segments[].country requiredinteger or stringISO 3166-1 alpha-2 country code ("DE", "GB"). A numeric country ID from GET /api/v1/billing/countries is also accepted.
segments[].count requiredintegerNumber of IPs in this country. At least 10; the order total must be at least 100.Minimum: 1Maximum: 100000
product_kindstringProduct: proxy_datacenter or proxy_isp. Dedicated proxies are priced and ordered through /api/v1/billing/dedicated/*.Default: "proxy_datacenter"
period_monthsintegerTerm length in months (1, 3, 6, or 12). Longer terms get a discount. Default: 1.
whitelist_ipsarray of stringIPv4 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_renewbooleanRenew the service automatically when the term ends. Default: true.
use_balancebooleanApply 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_sourcestringGeo source for country lookups: maxmind (geolocation) or ripe (RIR allocation). Default maxmind.One of: maxmind, ripe
idempotency_keystring, nullableIdempotency key. A retry with the same key returns the original order without charging again. Without a key, every request creates a new order.
promo_codestring, nullableOptional promo code. The discount applies to the first term only; renewals are charged at the regular price.Max length: 64
trialbooleanOrder the paid 48-hour trial instead of a full term.Default: false
extra_whitelist_countintegerPaid whitelist IPs beyond the free allowance. Included in the charge.Minimum: 0Maximum: 10000Default: 0
udp_unlockbooleanAdd the UDP add-on. Included in the charge.Default: false
extra_connections_countintegerPaid 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
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"}'
Python
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())
Node.js
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
<?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));
Go
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

  • 201 The order was created. Check payment_required and amount_due_cents. · 27 fields
    Example 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
    }
    FieldTypeDescription
    service_id requiredstring (uuid)Created service ID
    status requiredstringactive when the order is paid, pending while amount_due_cents is unpaid.
    segmentsarray of objectPer-segment breakdown as ordered
    segments[].country requiredintegerNumeric country ID. The ISO code is in country_code.
    segments[].country_codestring, nullableISO 3166-1 alpha-2 country code (e.g. "DE").
    segments[].count requiredinteger
    segments[].unit_base_cents requiredintegerVolume-tier base unit price in integer cents per IP
    segments[].type_multiplier requirednumberProduct multiplier applied to the base rate.
    segments[].geo_multiplier requirednumberCountry multiplier (default 1.0).
    segments[].segment_price_cents requiredintegerSegment price: count × base rate × product multiplier × country multiplier, rounded up to whole cents.
    segments[].available requiredbooleanWhether enough IPs are available for this segment.
    total_ip requiredintegerTotal number of IPs.
    total_price_cents requiredintegerDiscounted total charged for the full period in integer cents
    period_monthsintegerBilling period length in months (1/3/6/12)Default: 1
    discount_pctintegerApplied period discount as a whole percentage (0/10/15/20)Default: 0
    monthly_price_centsintegerUndiscounted monthly total (sum of segment prices) in integer centsDefault: 0
    balance_applied_centsintegerAmount paid from your wallet balance, in cents. Zero when use_balance is false.Default: 0
    amount_due_centsintegerAmount still due through a payment processor, in cents. Zero when the balance covers the order.Default: 0
    invoice_urlstring, nullableLink to the invoice, if one was issued.
    payment_requiredbooleantrue when amount_due_cents must still be paid. Pay it in the Dashboard under Pending payments.Default: false
    intent_idstring (uuid), nullableID of the pending payment when payment_required is true.
    promo_code_appliedstring, nullablePromo code applied to the order, if any.
    promo_discount_centsintegerPromo discount applied to the order, in cents.Minimum: 0Default: 0
    total_before_promo_centsinteger, nullablePre-promo total when a promo was applied; null otherwise.
    trialbooleanTrue when the service is a paid trial.Default: false
    trial_period_daysinteger, nullableTrial length in days; null for regular orders.
    addon_monthly_centsintegerMonthly cost of add-ons bought with the order, in cents.Minimum: 0Default: 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"
    }
  • 422 Validation 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. …"
      }
    }
  • 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"
    }

Quote additional IPs

POST/api/v1/billing/services/{service_id}/add-ips/quote
API key required

Preview 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

FieldTypeDescription
service_id (path) requiredstring (uuid)ID of the service.

Request body

FieldTypeDescription
segments requiredarray of objectOne or more segments to addMin items: 1
segments[].country requiredinteger or stringISO 3166-1 alpha-2 country code ("DE", "GB"). A numeric country ID from GET /api/v1/billing/countries is also accepted.
segments[].count requiredintegerNumber 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
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}]}'
Python
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())
Node.js
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
<?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));
Go
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

  • 200 Non-binding preview of an add-ips top-up. · 20 fields
    Example 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
    }
    FieldTypeDescription
    service_id requiredstring (uuid)ID of the service.
    segmentsarray of objectPer-segment pricing breakdown for the added IPs
    segments[].country requiredintegerNumeric country ID. The ISO code is in country_code.
    segments[].country_codestring, nullableISO 3166-1 alpha-2 country code (e.g. "DE").
    segments[].count requiredinteger
    segments[].unit_base_cents requiredintegerVolume-tier base unit price in integer cents per IP
    segments[].type_multiplier requirednumberProduct multiplier applied to the base rate.
    segments[].geo_multiplier requirednumberCountry multiplier (default 1.0).
    segments[].segment_price_cents requiredintegerSegment price: count × base rate × product multiplier × country multiplier, rounded up to whole cents.
    segments[].available requiredbooleanWhether enough IPs are available for this segment.
    errorsarray of objectSegments that can't be fulfilled; ordering them would fail with HTTP 409.
    errors[].country requiredintegerNumeric country ID of the segment that was left out.
    errors[].message requiredstring
    added_ip_count requiredintegerTotal IPs across the added segments
    monthly_price_added_cents requiredintegerUndiscounted full-monthly cost of the added segments
    days_remaining requiredintegerDays left in the current term.
    days_per_monthintegerDays per month used for proration.Default: 30
    prorated_charge_cents requiredintegerAmount charged now for the remainder of the current period
    current_price_cents requiredintegerService's current full-period renewal price
    new_renewal_price_cents requiredintegerRenewal price after this top-up (current + added segments' full-period cost)
  • 401 The API key is missing, malformed, revoked, or expired, or the account is inactive.
    Example · JSON
    {
      "detail": "Invalid or revoked API key."
    }
  • 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 fewer than 100 IPs in a proxy-package request.
    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 IPs to a service

POST/api/v1/billing/services/{service_id}/add-ips
API key required scope services:write

Add 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_key is required. A retry with the same key returns the original result and doesn't charge again.
  • Insufficient balance returns 402 with detail.detail = "insufficient_funds", required_cents, balance_cents, and deficit_cents. Nothing is charged.

Parameters

FieldTypeDescription
service_id (path) requiredstring (uuid)ID of the service.

Request body

FieldTypeDescription
segments requiredarray of objectOne or more segments to addMin items: 1
segments[].country requiredinteger or stringISO 3166-1 alpha-2 country code ("DE", "GB"). A numeric country ID from GET /api/v1/billing/countries is also accepted.
segments[].count requiredintegerNumber 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 requiredstringClient-supplied idempotency key. Must be unique per intent.Min length: 1

Request example Try it in the Dashboard

cURL
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"}'
Python
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())
Node.js
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
<?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));
Go
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

  • 200 Result of a successful add-ips top-up. · 7 fields
    Example 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
        }
      ]
    }
    FieldTypeDescription
    service_id requiredstring (uuid)ID of the service.
    added_ip_count requiredintegerNumber of IPs added.
    charged_cents requiredintegerProrated amount charged to the wallet
    ledger_entry_idstring (uuid), nullableWallet transaction for the charge; null when nothing was charged.
    new_total_ip requiredintegerTotal IP count on the service after the top-up
    new_price_cents requiredintegerService's new full-period renewal price
    segmentsarray of objectAll segments of the service after the top-up.
  • 401 The API key is missing, malformed, revoked, or expired, or the account is inactive.
    Example · JSON
    {
      "detail": "Invalid or revoked API key."
    }
  • 402 Insufficient wallet balance. Nothing is charged.
    Example · JSON
    {
      "detail": {
        "detail": "insufficient_funds",
        "required_cents": 3799,
        "balance_cents": 1777,
        "deficit_cents": 2022
      }
    }
  • 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 (for example, a missing idempotency_key), or fewer than 100 IPs in a proxy-package request.
    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"
    }

Last updated: November 9, 2026. Generated from the OpenAPI 3.1 specification (API version 0.1.0). Markdown version for AI agents.