Billing and credits
The plan, checkout and billing portal sessions, plan changes and AI credits.
Set up the SDK client used in the examples
API key or Dashboard session:
import { UpVoiced } from '@upvoiced/sdk';
const apiKey = process.env['UPVOICED_API_KEY']; // uv_live_… (Settings → API keys)
const workspace = process.env['UPVOICED_WORKSPACE_ID']; // sent as X-Workspace
if (!apiKey || !workspace) throw new Error('Set UPVOICED_API_KEY and UPVOICED_WORKSPACE_ID.');
const upvoiced = new UpVoiced({ apiKey, workspace });curl examples read $UPVOICED_API_KEY and $UPVOICED_WORKSPACE_IDfrom your shell. MCP examples are the tools/call request an MCP client sends to the MCP server with the same API key.
GET/v1/billing
Plan, status, entitlements, usage and credits for upsell UI (any member)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
Response 200: 48 fields
| Name | Type | Required |
|---|---|---|
plan | "free" | "starter" | "growth" | "business" | Yes |
subscribed_plan | "free" | "starter" | "growth" | "business" | Yes |
interval | "month" | "year" | Yes |
status | "active" | "trialing" | "past_due" | "paused" | "canceled" | Yes |
current_period_end | string (date-time) | null | Yes |
cancel_at_period_end | boolean | Yes |
scheduled_change | object | null | Yes |
scheduled_change.plan | "free" | "starter" | "growth" | "business" | Yes |
scheduled_change.interval | "month" | "year" | Yes |
payment_failed | boolean | Yes |
has_billing_account | boolean | Yes |
entitlements | object | Yes |
entitlements.boards.max | integer | nullvalue 0–1000000000 | Yes |
entitlements.posts.active_max | integer | nullvalue 0–1000000000 | Yes |
entitlements.members.max | integer | nullvalue 0–1000000000 | Yes |
entitlements.surveys.active_max | integer | nullvalue 0–1000000000 | Yes |
entitlements.testimonials.max | integer | nullvalue 0–1000000000 | Yes |
entitlements.video_testimonials | boolean | Yes |
entitlements.walls.max | integer | nullvalue 0–1000000000 | Yes |
entitlements.powered_by.removable | boolean | Yes |
entitlements.custom_domain | boolean | Yes |
entitlements.custom_css | boolean | Yes |
entitlements.integrations.slack_discord | boolean | Yes |
entitlements.api.enabled | boolean | Yes |
entitlements.api.access | "read_only" | "read_write" | Yes |
entitlements.api.keys_max | integer | nullvalue 0–1000000000 | Yes |
entitlements.mcp.enabled | boolean | Yes |
entitlements.mcp.access | "read_only" | "read_write" | Yes |
entitlements.webhooks.max | integer | nullvalue 0–1000000000 | Yes |
entitlements.ai.credits_monthly | integervalue ≥ 0 | Yes |
entitlements.end_user_sso | boolean | Yes |
entitlements.audit_log | boolean | Yes |
entitlements.private_boards | boolean | Yes |
entitlements.email_recipients_monthly | integer | nullvalue 0–1000000000 | Yes |
entitlements.support | "community" | "email" | "priority_email" | "priority_onboarding" | Yes |
usage | object | Yes |
usage.members | integervalue ≥ 0 | Yes |
usage.boards | integervalue ≥ 0 | Yes |
usage.active_posts | integervalue ≥ 0 | Yes |
restrictions | object | Yes |
restrictions.read_only_board_ids | array of string (uuid) | Yes |
restrictions.board_selection | "default" | "operator" | Yes |
restrictions.new_posts_blocked | boolean | Yes |
credits | object | Yes |
credits.balance | integervalue ≥ 0 | Yes |
credits.expiring | integervalue ≥ 0 | Yes |
credits.expires_at | string (date-time) | null | Yes |
credits.low | boolean | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl 'https://api.upvoiced.com/v1/billing' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID"const data = await upvoiced.get('/v1/billing');{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_usage",
"arguments": {
"workspace": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
}
}
}Tool get_usage.
POST/v1/billing/checkout
Create a server-controlled Paddle transaction for a plan (owner)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
| Name | Type | Required |
|---|---|---|
plan | "starter" | "growth" | "business" | Yes |
interval | "month" | "year" | Yes |
Response 201: 1 fields
| Name | Type | Required |
|---|---|---|
transaction_id | stringpattern ^txn_[a-z\d]{26}$ | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/billing/checkout' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"plan": "starter",
"interval": "month"
}'const data = await upvoiced.post('/v1/billing/checkout', { body: { plan: 'starter', interval: 'month' } });No MCP tool for this operation. The MCP server covers the everyday reads and writes.
POST/v1/billing/portal
Paddle customer portal session URL (owner)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
Response 200: 2 fields
| Name | Type | Required |
|---|---|---|
url | string (uri) | Yes |
update_payment_method_url | string (uri) | null | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/billing/portal' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'const data = await upvoiced.post('/v1/billing/portal', { body: {} });No MCP tool for this operation. The MCP server covers the everyday reads and writes.
POST/v1/billing/change
Change plan/interval: upgrades prorated now, downgrades next period (owner)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
| Name | Type | Required |
|---|---|---|
plan | "starter" | "growth" | "business" | Yes |
interval | "month" | "year" | Yes |
Response 200: 3 fields
| Name | Type | Required |
|---|---|---|
effective | "immediately" | "next_billing_period" | Yes |
plan | "starter" | "growth" | "business" | Yes |
interval | "month" | "year" | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/billing/change' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"plan": "starter",
"interval": "month"
}'const data = await upvoiced.post('/v1/billing/change', { body: { plan: 'starter', interval: 'month' } });No MCP tool for this operation. The MCP server covers the everyday reads and writes.
POST/v1/billing/cancel
Cancel at the end of the billing period; data is kept (owner)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
Response 200: 2 fields
| Name | Type | Required |
|---|---|---|
cancel_at_period_end | boolean | Yes |
current_period_end | string (date-time) | null | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/billing/cancel' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'const data = await upvoiced.post('/v1/billing/cancel', { body: {} });No MCP tool for this operation. The MCP server covers the everyday reads and writes.
POST/v1/billing/resume
Remove a scheduled cancellation (owner)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
Response 200: 2 fields
| Name | Type | Required |
|---|---|---|
cancel_at_period_end | boolean | Yes |
current_period_end | string (date-time) | null | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/billing/resume' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'const data = await upvoiced.post('/v1/billing/resume', { body: {} });No MCP tool for this operation. The MCP server covers the everyday reads and writes.
GET/v1/billing/credits
AI credit balance and recent ledger entries (any member)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
Response 200: 10 fields
| Name | Type | Required |
|---|---|---|
credits | object | Yes |
credits.balance | integervalue ≥ 0 | Yes |
credits.expiring | integervalue ≥ 0 | Yes |
credits.expires_at | string (date-time) | null | Yes |
credits.low | boolean | Yes |
entries | array of object | Yes |
entries[].delta | integer | Yes |
entries[].reason | "plan_grant" | "purchase" | "consume" | "refund" | "adjust" | "expire" | Yes |
entries[].balance_after | integervalue ≥ 0 | Yes |
entries[].created_at | string (date-time) | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl 'https://api.upvoiced.com/v1/billing/credits' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID"const data = await upvoiced.get('/v1/billing/credits');No MCP tool for this operation. The MCP server covers the everyday reads and writes.
POST/v1/billing/credits/checkout
Create a Paddle transaction for an AI credit pack (owner/admin)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
| Name | Type | Required |
|---|---|---|
pack | 500 | 2500 | 10000 | Yes |
Response 201: 1 fields
| Name | Type | Required |
|---|---|---|
transaction_id | stringpattern ^txn_[a-z\d]{26}$ | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/billing/credits/checkout' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"pack": 500
}'const data = await upvoiced.post('/v1/billing/credits/checkout', { body: { pack: 500 } });No MCP tool for this operation. The MCP server covers the everyday reads and writes.