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
curl 'https://claw.zhenhuiai.com/api/v1/open/balance' \
--header 'Authorization: Bearer <personal-access-token>'{
"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
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"}'{
"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
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"
}'{
"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
curl 'https://claw.zhenhuiai.com/api/v1/open/usage' \
--header 'Authorization: Bearer <personal-access-token>'{
"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:
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
curl 'https://claw.zhenhuiai.com/api/v1/open/teams/team_01/balance' \
--header 'Authorization: Bearer <team-access-token>'{
"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:
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"}'{
"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"
}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"}'{
"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:
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.
