Skip to content

Hybrid and headless integration

A hybrid integration keeps the commercial control plane in your application and uses ProxyRequest as the proxy, provisioning, accounting, and analytics layer. The platform still needs mirrored users, packages, and orders because those resources are part of proxy authentication and every traffic record.

Your control plane ownsProxyRequest owns
Customer identity and lifecycleMirrored platform user and access state
Product catalog and customer-facing pricingPackage configuration used by routing and targeting
Billing, subscriptions, and entitlementsOrder, byte allowance, proxy password, and enforcement
Dashboard and customer workflowsProxy generation, traffic accounting, analytics, and webhooks

There is no native external_id passthrough that replaces platform IDs. Store the mapping in your database and use ProxyRequest IDs for every API request.

Keep three mappings instead of putting every identifier in one user row:

MappingRequired fieldsConstraint
CustomerLocal customer ID, ProxyRequest user_id, sync status, timestampsBoth IDs unique inside one deployment
ProductLocal product ID, ProxyRequest package_id, configuration versionLocal product ID unique; package can be reused by many customers
EntitlementLocal subscription/order ID, local customer/product IDs, ProxyRequest order_id, last reconciled timeOne active mapping per commercial entitlement

Persist the returned ProxyRequest ID immediately after each successful create operation. Do not derive it from a username, email address, or display label.

The optional user meta object can carry a non-sensitive correlation value, but it is not an indexed external-ID contract and must not replace the local mapping.

  1. Authenticate your backend with a static API key and keep it outside the browser.
  2. Configure package mirrors in the admin, read them through GET /packages, and persist each local-product mapping.
  3. On purchase or activation, create the mirrored sub-user with POST /users and the mapped package_id.
  4. Store the returned user_id, then read GET /users/{id}/orders and persist the created order_id.
  5. Load package-specific locations and call POST /proxies/generate with the mapped user_id and package_id.
  6. Return only the required gateway credentials to the customer-facing workflow.
  7. Process signed webhooks for prompt updates and reconcile closed reporting windows through analytics.

The public contract requires username and password. Allocation values are integer bytes, not an implicit GB value.

import { createHmac, randomBytes } from 'node:crypto';
const opaqueCustomer = createHmac('sha256', process.env.MAPPING_SECRET)
.update(localCustomer.id)
.digest('hex')
.slice(0, 24);
const response = await fetch('https://api.proxyrequest.com/api/v1/users', {
method: 'POST',
headers: {
Authorization: `Static ${process.env.PROXYREQUEST_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: `customer-${opaqueCustomer}`,
password: randomBytes(32).toString('base64url'),
package_id: packageMapping.proxyrequestPackageId,
data: 10 * 1024 ** 3,
meta: { correlation: opaqueCustomer },
}),
});
if (!response.ok) throw new Error(`Create mirrored user: ${response.status}`);
const proxyRequestUser = await response.json();
await mappings.insertCustomer(localCustomer.id, proxyRequestUser.id);

Use the exact request and response schemas in the API Reference. Do not copy a generated account password into logs or customer-visible analytics.

Resolve local IDs before the API call:

local customer ──> ProxyRequest user_id
local product ──> ProxyRequest package_id

Then call POST /proxies/generate with both platform identifiers and the requested targeting, connection, and session objects. The generator does not accept local IDs and does not infer a package from your product name.

{
"user_id": "550e8400-e29b-41d4-a716-446655440001",
"package_id": "550e8400-e29b-41d4-a716-446655440002",
"quantity": 1,
"targeting": { "country": "us" },
"connection": { "protocol": "http" },
"session": { "ttl": 3600 }
}

The session TTL requests sticky behavior in seconds and accepts 30 through 86400 in the current public contract. Omit session for rotating eligibility.

Analytics filters also use platform identifiers:

  • user_id scopes usage to the mirrored customer;
  • package_id scopes usage to the mapped product;
  • ledger_id or order_id-related records distinguish purchase and allocation context where supported.

Translate the result back to local customers and products through the mapping layer before rendering it. Do not expose platform-wide IDs as your customer-facing identity model.

Webhooks are the prompt notification path, not the billing source of truth. Verify signatures, deduplicate deliveries, and reconcile a closed start/end/timezone window through GET /analytics/overall. Use feed, logs, domains, and transactions to explain differences.

If a create or allocation call times out after the request was sent, do not immediately repeat it. Read the affected user or order, compare the observed state with the pending local operation, and escalate an ambiguous result. The public API does not promise universal idempotency for these writes.

Keep states such as pending, active, reconcile_required, and deprovisioning in the mapping record. Revoke access before deleting a mapping, and retain the accounting references required by your own audit policy.

For the complete direct reseller sequence, see reseller workflow. For API authentication and errors, see API fundamentals.