Adjust reseller billing

Apply a signed delta to a reseller's balance. The endpoint targets the right column automatically: in credits mode it moves credits, in users mode it moves max_users. You never pass the mode explicitly.

The update runs as a single atomic relative SQL statement (credits = credits + delta, or the max_users equivalent with a cast to SIGNED). Two concurrent adjustments sum instead of racing. The read path never goes through the 60-second cache used by other reseller endpoints, so a burst of top-ups from a monthly job cannot silently overwrite each other. Every successful adjustment is written to reg_userlog with the type panel_api_billing_adjust, so it appears in the same audit trail as CMS-driven changes.

Endpoint

POST https://<your-panel-domain>/panel-api/v1/resellers/{id}/billing/adjust

Authentication

Send the API key in the Authorization: Bearer <your-api-key> header. Only admin keys can call this endpoint.

Required scope

resellers:write

Idempotency

Every POST must include an Idempotency-Key header. Reusing the same key with the same body replays the cached response; reusing it with a different body returns 409 idempotency_conflict. For a monthly billing job, use the invoice ID as the key so that a retry after a timeout never stacks a second charge on top.

Path parameters

Name Type Description
id int The reg-user ID of the reseller.

Request body

Field Type Required Default Description
delta float yes Signed change. Positive to top up, negative to claw back. In users mode the value is cast to int on the server.
reason string no "" Free-form label written to the audit log. Truncated to 100 characters.
{
  "delta": 1,
  "reason": "docs sample adjust +1"
}

Response

The response is the billing snapshot after the adjustment, in the same shape as GET /resellers/{id}/billing.

{
  "mode": "credits",
  "credits": 11,
  "max_users": null,
  "active_users": null,
  "billing_expires": null
}

Fractional credits are preserved. Adding 0.10 to a balance of 0.25 produces 0.35, not 0. Do not floor or round in your own code before sending the delta.

Examples

cURL

curl -X POST https://<your-panel-domain>/panel-api/v1/resellers/262260/billing/adjust \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: invoice-INV-2026-00814" \
  -d '{"delta":1,"reason":"docs sample adjust +1"}'

PHP SDK

require __DIR__ . '/api-panel-php-sdk-1.0.0/autoload.php';
use XtreamAI\PanelApi\PanelApiClient;

$client = new PanelApiClient(baseUrl: 'https://<your-panel-domain>', token: '<your-api-key>');
$billing = $client->resellers->adjustBilling(
    id:             262260,
    delta:          1,
    reason:         'docs sample adjust +1',
    idempotencyKey: 'invoice-INV-2026-00814',
);
echo $billing->credits, PHP_EOL;

Python SDK

from xtream_ai_panel_api import PanelApiClient

client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")
billing = client.resellers.adjust_billing(
    262260,
    delta=1,
    reason="docs sample adjust +1",
    idempotency_key="invoice-INV-2026-00814",
)
print(billing.credits)

Errors

HTTP Error slug When it happens How to fix
400 missing_idempotency_key The Idempotency-Key header was not sent. Add the header on every POST.
400 invalid_body The delta field is missing from the body. Include delta as a signed number.
401 invalid_key Missing, malformed, or unknown API key. Send a live key in Authorization: Bearer <token>.
403 admin_only_endpoint A reseller key called this endpoint. Use an admin key.
403 insufficient_scope The key does not carry resellers:write. Rotate the key with the correct scopes.
404 not_found No reseller exists with that ID. Verify the ID with GET /resellers/{id} first.
409 idempotency_conflict The Idempotency-Key was reused with a different body. Generate a new key or resend the original body.
422 negative_balance_not_allowed A negative delta in credits mode is larger than the current balance. The balance is untouched; no partial deduction happens. Lower the delta or top up first.
422 cap_below_active_users A negative delta in users mode would drop max_users below the currently used slot count. No lines are auto-disabled to make room. Free the slots first (disable or delete lines), then retry.
422 negative_cap_not_allowed A negative delta in users mode would take max_users below zero. Lower the delta.
422 mismatched_mode The reseller is stored in a billing mode this endpoint does not recognize (should not happen on a healthy panel). Contact support.
429 rate_limited The per-key request budget for this minute is spent. Back off and retry after the minute rolls over.

See also