Skip to content

Points and billing ​

A web agent may charge Xiaoya points from its trusted server after the user confirms a specific purchase. If the business operation ultimately fails after a confirmed charge, refund against that order. An MCP tool with reviewed xiaoya/pricePoints is billed and refunded by the platform and must not call /charge again.

Personal balance requires balance; charge/refund require charge; usage requires usage. Team operations require a Team-bound token for the exact path team_id. Keep the token on a trusted server. points is an integer from 1 through 1,000,000,000,000 and idempotency keys contain 8–64 characters.

Personal balance ​

bash
curl 'https://claw.zhenhuiai.com/api/v1/open/balance' \
  --header 'Authorization: Bearer <personal-access-token>'
json
{
  "success": true,
  "data": { "subscription": 80, "gift_card": 20, "recharge": 100, "total": 200 },
  "request_id": "req_balance_01"
}

The balance is display-only; only the atomic /charge response is authoritative.

Personal charge ​

bash
curl --request POST 'https://claw.zhenhuiai.com/api/v1/open/charge' \
  --header 'Authorization: Bearer <personal-access-token>' \
  --header 'Content-Type: application/json' \
  --data '{"points":20,"reason":"Generate one landing page","idempotencyKey":"order_20260830_000001"}'
json
{
  "success": true,
  "data": {
    "chargedPoints": 20,
    "balance": { "subscription": 60, "gift_card": 20, "recharge": 100, "total": 180 }
  },
  "request_id": "req_charge_01"
}

The trusted server generates points and the stable order key. reason contains 1–100 characters. Reusing a key with different parameters returns BALANCE_IDEMPOTENCY_CONFLICT.

Personal refund ​

bash
curl --request POST 'https://claw.zhenhuiai.com/api/v1/open/refund' \
  --header 'Authorization: Bearer <personal-access-token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "points":20,
    "reason":"Refund failed generation",
    "chargeIdempotencyKey":"order_20260830_000001",
    "idempotencyKey":"refund_20260830_000001"
  }'
json
{
  "success": true,
  "data": {
    "refundedPoints": 20,
    "balance": { "subscription": 80, "gift_card": 20, "recharge": 100, "total": 200 }
  },
  "request_id": "req_refund_01"
}

Never refund across a user, agent, or original order, and never exceed the original charge.

Personal usage ​

bash
curl 'https://claw.zhenhuiai.com/api/v1/open/usage' \
  --header 'Authorization: Bearer <personal-access-token>'
json
{
  "success": true,
  "data": {
    "chargedPoints": 100,
    "refundedPoints": 20,
    "netPoints": 80,
    "modelUsage": {
      "requestCount": 3,
      "inputTokens": 1200,
      "outputTokens": 360,
      "cacheReadTokens": 0,
      "cacheWriteTokens": 0,
      "imageCount": 0,
      "chargedPoints": 12
    }
  },
  "request_id": "req_usage_01"
}

This endpoint accepts only a Personal token.

Creator-sponsored public sessions ​

The creator of a published agent may use a model-scoped Personal-bound token to issue a short-lived sponsored session for at most one hour. A Team-bound token is rejected rather than silently charging the creator's Personal balance:

bash
curl --request POST 'https://claw.zhenhuiai.com/api/v1/open/public-billing-sessions' \
  --header 'Authorization: Bearer <personal-creator-access-token>' \
  --header 'Content-Type: application/json' \
  --data '{"expires_in_seconds":900,"max_points":1000,"max_calls":100}'

Keep the returned short-lived accessToken only in the application server session and use it for model or TTS gateway calls; never send it to browser code. max_points and max_calls are shared across both gateways and reserved atomically before an upstream call. Expiry, revocation, or either exhausted budget blocks new calls. Revoke the session with DELETE /api/v1/open/public-billing-sessions/{id} when it is no longer needed. Never log the creator token, sponsored token, or complete user input.

Team balance, charge, and refund ​

bash
curl 'https://claw.zhenhuiai.com/api/v1/open/teams/team_01/balance' \
  --header 'Authorization: Bearer <team-access-token>'
json
{
  "success": true,
  "data": {
    "teamId": "team_01",
    "memberId": "member_01",
    "role": "member",
    "balancePoints": 860,
    "balancePointsDecimal": "860",
    "walletBalancePoints": 12500,
    "quotaLimit": 1000,
    "quotaUsed": 140,
    "quotaRemaining": 860
  },
  "request_id": "req_team_balance_01"
}

Team charge has no reason field:

bash
curl --request POST 'https://claw.zhenhuiai.com/api/v1/open/teams/team_01/charge' \
  --header 'Authorization: Bearer <team-access-token>' \
  --header 'Content-Type: application/json' \
  --data '{"points":20,"idempotencyKey":"team_order_20260830_0001"}'
json
{
  "success": true,
  "data": {
    "teamId": "team_01",
    "chargeLedgerId": "ledger_01",
    "chargedPoints": 20,
    "chargedPointsDecimal": "20",
    "balancePoints": 840,
    "balancePointsDecimal": "840",
    "walletBalancePoints": 12480,
    "quotaUsed": 160
  },
  "request_id": "req_team_charge_01"
}
bash
curl --request POST 'https://claw.zhenhuiai.com/api/v1/open/teams/team_01/refund' \
  --header 'Authorization: Bearer <team-access-token>' \
  --header 'Content-Type: application/json' \
  --data '{"points":20,"chargeIdempotencyKey":"team_order_20260830_0001","idempotencyKey":"team_refund_20260830_0001"}'
json
{
  "success": true,
  "data": {
    "teamId": "team_01",
    "refundLedgerId": "ledger_02",
    "requestedPoints": 20,
    "requestedPointsDecimal": "20",
    "refundedPoints": 20,
    "refundedPointsDecimal": "20",
    "unrecoveredPoints": 0,
    "unrecoveredPointsDecimal": "0",
    "balancePoints": 860,
    "balancePointsDecimal": "860",
    "walletBalancePoints": 12500,
    "quotaUsed": 140
  },
  "request_id": "req_team_refund_01"
}

Use refundedPoints as the amount actually restored; unrecoveredPoints reports points that could not be recovered.

Node.js server example ​

The downloaded Skill contains assets/example-mcp/src/xiaoya-open-api.mjs:

js
import { XiaoyaOpenApiClient } from './xiaoya-open-api.mjs';

const client = new XiaoyaOpenApiClient({
  platformBaseUrl: process.env.XIAOYA_BASE_URL,
  accessToken: process.env.XIAOYA_ACCESS_TOKEN
});

await client.balance();
await client.charge({ points: 20, reason: 'Generate one landing page', idempotencyKey: 'order_20260830_000001' });
await client.refund({
  points: 20,
  reason: 'Refund failed generation',
  chargeIdempotencyKey: 'order_20260830_000001',
  idempotencyKey: 'refund_20260830_000001'
});
await client.teamBalance('team_01');
await client.teamCharge('team_01', { points: 20, idempotencyKey: 'team_order_20260830_0001' });
await client.teamRefund('team_01', {
  points: 20,
  chargeIdempotencyKey: 'team_order_20260830_0001',
  idempotencyKey: 'team_refund_20260830_0001'
});

Errors and retries ​

Common codes include INSUFFICIENT_POINTS, OPEN_AGENT_SCOPE_REQUIRED, TEAM_CONTEXT_MISMATCH, BALANCE_IDEMPOTENCY_CONFLICT, TEAM_CREDIT_IDEMPOTENCY_CONFLICT, OPEN_AGENT_CHARGE_LIMIT_EXCEEDED, OPEN_AGENT_CHARGE_NOT_FOUND, OPEN_AGENT_TEAM_CHARGE_NOT_FOUND, OPEN_AGENT_REFUND_EXCEEDS_CHARGE, and TEAM_CREDIT_REFUND_EXCEEDS_CHARGE.

A timeout or 5xx may have an unknown result. Retry a charge with the original charge key and a refund with the original refund key. Never generate a new key or hold a database transaction across the HTTP call. Log only the stable error code and request_id.

See the complete API reference for authoritative schemas.

OAuth credentials and model-provider secrets must remain on trusted servers.