59 endpoints at https://api.vaif.studio, generated from the API's OpenAPI document. The REST API page covers authentication, and All endpoints lists every group.
POST /billing/checkout
Request body (application/json, required)
{
orgId: string (uuid);
plan: "entry" | "entry_plus" | "starter" | "pro" | "agency" | "studio_plus";
interval?: "monthly" | "yearly";
promoCode?: string;
successUrl?: string (uri);
cancelUrl?: string (uri);
}
Response 200 (application/json)
{
url: string | null;
}
Errors: 400, 401, 403, 503, with the error body.
GET /billing/checkout/verify/{sessionId}
| Parameter | In | Type | Required |
|---|
sessionId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
type: string;
status: null | "complete" | "expired" | "open";
paymentStatus: "no_payment_required" | "paid" | "unpaid";
creditAmount: number;
packageId: string;
fulfilled: boolean;
} | {
ok: boolean;
type: string;
status: null | "complete" | "expired" | "open";
paymentStatus: "no_payment_required" | "paid" | "unpaid";
fulfilled: boolean;
} | {
ok: boolean;
status: null | "complete" | "expired" | "open";
paymentStatus: "no_payment_required" | "paid" | "unpaid";
plan: "agency" | "entry" | "entry_plus" | "pro" | "starter" | "studio_plus";
interval: string;
subscriptionId: null | string;
subscriptionStatus: null | "active" | "canceled" | "incomplete" | "incomplete_expired" | "past_due" | "paused" | "trialing" | "unpaid";
currentPeriodEnd: null | string (date-time);
taxStatus: null | "complete" | "failed" | "requires_location_inputs";
taxWarning: null | {
code: "TaxCalculationFailed" | "TaxLocationRequired";
message: string;
};
founder: null | {
status: string;
founderNumber?: null | number;
};
}
POST /billing/hosting/checkout
Request body (application/json, required)
{
orgId: string (uuid);
interval?: "monthly" | "yearly";
quantity?: number;
successUrl?: string (uri);
cancelUrl?: string (uri);
}
Response 200 (application/json)
{
url: string | null;
}
Errors: 400, 401, 403, with the error body.
GET /billing/org/{orgId}/hosting
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
packs: {
quantity: number;
interval: string;
status: string;
currentPeriodEnd: string | null;
} | null;
allowance: {
maxServices: number;
alwaysOnLimit: number;
alwaysOnInUse: number;
servicesInUse: number;
alwaysOnAllowed: boolean;
};
egress: {
usedBytes: number;
includedBytes: number;
};
pack: {
monthlyPriceCents: number;
yearlyPriceCents: number;
servicesPerPack: number;
egressGiBPerPack: number;
maxQuantityPerCheckout: number;
};
}
Errors: 401, 403, with the error body.
GET /billing/org/{orgId}/infrastructure
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
databases: {
id: string;
name: string;
projectId: string;
projectName: string;
kind: "primary" | "replica";
sizeLabel: string;
status: "running" | "provisioning" | "resizing" | "stopped" | "failed";
monthlyCents: number;
}[];
totalMonthlyCents: number;
}
Errors: 401, 403, with the error body.
POST /billing/portal
Request body (application/json, required)
{
orgId: string (uuid);
returnUrl?: string (uri);
}
Response 200 (application/json)
{
url: string | null;
}
Errors: 400, 401, 403, 404, with the error body.
POST /billing/org/{orgId}/portal
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json)
{
returnUrl?: string;
}
Response 200 (application/json)
{
url: string;
} | {
ok: boolean;
url: string;
}
GET /billing/org/{orgId}/summary
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
orgId: string;
managed: boolean;
plan: string;
status: string;
paymentStatus: any;
paymentFailedAt: any;
billingInterval: any;
currentPeriodEnd: null | string (date-time);
cancelAtPeriodEnd: boolean;
stripeCustomerIdPresent: boolean;
stripeSubscriptionIdPresent: boolean;
pauseStartedAt: any;
pauseExpiresAt: any;
pauseCooldownEndsAt: any;
pauseCount: any;
}
GET /billing/org/{orgId}/subscription
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
plan: string;
interval: "monthly" | "yearly";
priceCents: number | null;
currency: string;
founder: boolean;
managed: boolean;
period: {
start: string;
end: string;
} | null;
state: "free" | "active" | "trialing" | "canceling" | "past_due" | "frozen" | "paused" | "retention" | "cooldown" | "canceled";
trialEndsAt: string | null;
cancelAt: string | null;
pausedSince: string | null;
freePauseEndsAt: string | null;
retentionPriceCents: number | null;
cooldownEndsAt: string | null;
payBy: string | null;
upcomingInvoices: {
subscription: "plan" | "hosting";
date: string;
amountCents: number;
currency: string;
lines: {
kind: "plan" | "hosting_pack" | "addon" | "retention" | "other";
label: string;
quantity: number;
amountCents: number;
}[];
}[] | null;
unpaidInvoice: {
id: string;
number: string | null;
amountCents: number;
dueDate: string | null;
nextRetryAt: string | null;
hostedInvoiceUrl: string | null;
} | null;
paymentMethod: {
brand: string;
last4: string;
expMonth: number;
expYear: number;
} | null;
lastPaymentError: {
at: string | null;
message: string;
} | null;
billingEmail: string | null;
pausePolicy: {
freeDays: number;
retentionPercent: number;
cooldownDays: number;
};
partial: ("period" | "upcomingInvoices" | "unpaidInvoice" | "lastPaymentError" | "paymentMethod" | "billingEmail")[];
}
Errors: 401, 403, with the error body.
POST /billing/webhook
Response 200 (application/json)
{
received: boolean;
}
GET /billing/org/{orgId}/usage-alerts
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
plan: "agency" | "enterprise" | "free" | "pro" | "starter" | "studio_plus";
alerts: {
type: string;
severity: "critical" | "warning";
message: string;
usage: number;
limit: number;
}[];
usage: {
aiCredits: {
used: number;
limit: number;
remaining: number;
percentUsed: number;
};
};
}
POST /billing/org/{orgId}/usage-alerts
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
metric: "verament_credits" | "api_requests" | "function_invocations" | "file_storage" | "hosting_egress" | "database_rows" | "mau" | "realtime_peak" | "ai_credits" | "storage" | "storage_bytes" | "bandwidth" | "realtime_connections";
threshold: number;
notifyEmail?: boolean;
}
Response 200 (application/json)
{
ok: true;
alertId: string;
}
Errors: 401, 403, with the error body.
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: true;
alerts: {
id: string;
metric: string;
threshold: number;
enabled: boolean;
emailOn: boolean;
notifyEmail: boolean;
limitNow: number | null;
createdAt: string;
}[];
meters: {
metric: "verament_credits" | "api_requests" | "function_invocations" | "file_storage" | "hosting_egress" | "database_rows" | "mau" | "realtime_peak";
name: string;
unit: string;
limitNow: number | null;
}[];
}
Errors: 401, 403, with the error body.
PATCH /billing/org/{orgId}/usage-alerts/{alertId}
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
alertId | path | string | Yes |
Request body (application/json, required)
{
enabled?: boolean;
threshold?: number;
notifyEmail?: boolean;
}
Response 200 (application/json)
{
ok: true;
}
Errors: 401, 403, with the error body.
DELETE /billing/org/{orgId}/usage-alerts/{alertId}
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
alertId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
}
GET /billing/org/{orgId}/usage-alerts/history
| Parameter | In | Type | Required |
|---|
limit | query | number | No |
before | query | string | No |
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: true;
history: {
id: string;
alertId: string;
firedAt: string;
metric: string;
threshold: number;
usage: number;
limit: number;
emailStatus: "sent" | "not_sent" | "no_recipients";
meterName: string | null;
unit: string | null;
currentUsage: number;
limitValue: number;
notificationSent: boolean;
triggeredAt: string;
}[];
nextCursor: string | null;
}
Errors: 400, 401, 403, with the error body.
GET /billing/plans
Response 200 (application/json)
{
ok: boolean;
plans: {
name: string;
displayName: string;
description: string;
priceCents: null | number;
priceYearlyCents: null | number;
stripePriceId: null | string;
stripeYearlyPriceId: null | string;
popular: boolean;
features: string[];
limits: {
projectsMax: number;
environmentsMax: number;
teamMembersMax: number;
mauIncluded: number;
mauOveragePrice: number;
mauHardLimit: boolean;
apiRequestsMonthly: number;
storageGb: number;
databaseRowsMax: number;
realtimeEnabled: boolean;
realtimeMessagesMonthly: number;
realtimeConnectionsMax: number;
functionsEnabled: boolean;
functionInvocationsMonthly: number;
functionConcurrency: number;
aiEnabled: boolean;
aiPromptsEnabled: boolean;
aiCodeExportEnabled: boolean;
aiFunctionGenerationEnabled: boolean;
aiEndpointGenerationEnabled: boolean;
aiDocsGenerationEnabled: boolean;
aiCreditsMonthly: number;
aiMaxRequestTokens: number;
aiMaxOutputTokens: number;
aiOveragesEnabled: boolean;
aiOverageMultiplier: number;
aiSpendCapEnabled: boolean;
aiMaxConcurrentRequests: number;
aiCreditRolloverCap: number;
aiEnterpriseRoutingEnabled: boolean;
aiBringYourOwnKeysEnabled: boolean;
aiModelTier: "enterprise" | "free" | "paid";
aiMaxContextTokens: number;
aiMaxMonthlyTokens: number;
aiWorkspaceSessionsMax: number;
aiBackendGenerationEnabled: boolean;
aiClarificationEnabled: boolean;
aiReasoningDisplayEnabled: boolean;
teamRolesEnabled: boolean;
auditLogsEnabled: boolean;
auditLogRetentionDays: number;
ssoEnabled: boolean;
samlEnabled: boolean;
scimEnabled: boolean;
webhooksEnabled: boolean;
webhookDlqEnabled: boolean;
ciTokensEnabled: boolean;
customDomainsEnabled: boolean;
customDomainsMax: number;
templatesEnabled: boolean;
deploymentsEnabled: boolean;
branchDeploymentsEnabled: boolean;
branchDeploymentsMax: number;
observabilityHubEnabled: boolean;
advancedMetricsEnabled: boolean;
regionalRoutingEnabled: boolean;
dedicatedDbEnabled: boolean;
dedicatedDbTiers: any[];
dedicatedDbCustomSizing: boolean;
dedicatedDbMaxStorageGb: number;
dedicatedStackEnabled: boolean;
liveDeploymentsEnabled: boolean;
maxLiveDeployments: number;
liveDeploymentMemoryOptions: string[];
liveDeploymentCpuOptions: string[];
liveDeploymentMaxInstances: number;
includedAlwaysOn: number;
sitesMax: number;
staticSitesOnly: boolean;
dailyBuildsMax: number;
dedicatedDbFreeTier: null | "2xl" | "3xl" | "4xl" | "custom" | "high-memory-large" | "high-memory-medium" | "high-memory-xl" | "large" | "medium" | "micro" | "small" | "xl";
dedicatedDbFreeCount: number;
dedicatedDbIncludedTier: null | "2xl" | "3xl" | "4xl" | "custom" | "high-memory-large" | "high-memory-medium" | "high-memory-xl" | "large" | "medium" | "micro" | "small" | "xl";
haIncluded: boolean;
readReplicasPerDatabase: number;
oauthProvidersMax: number;
extensionsMax: number;
wrappersMax: number;
alertRulesMax: number;
slaSupportEnabled: boolean;
dedicatedSupportEnabled: boolean;
};
monthlyPriceCents: null | number;
annualPriceCents: null | number;
annualMonthlyCents: null | number;
annualSavingsCents: null | number;
}[];
}
GET /billing/credits/packages
Response 200 (application/json)
{
ok: boolean;
packages: {
id: string;
amount: number;
priceInCents: number;
label: string;
description: string;
bonus: string;
} | {
id: string;
amount: number;
priceInCents: number;
label: string;
description: string;
bonus?: any;
}[];
}
GET /billing/credits/rates
Response 200 (application/json)
{
tier: "lite" | "standard" | "max";
creditsPer1kTokens: number;
availableOn: string[];
}[]
POST /billing/org/{orgId}/change-plan
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
plan: "entry" | "entry_plus" | "starter" | "pro" | "agency" | "studio_plus";
interval?: "monthly" | "yearly";
prorationDate?: number;
}
Response 200 (application/json)
{
ok: true;
newPlan: string;
newInterval: string;
effectiveDate: string | string (date-time);
status: string;
}
Errors: 400, 401, 402, 403, 409, 500, 503, with the error body.
POST /billing/org/{orgId}/change-plan/preview
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
plan: "entry" | "entry_plus" | "starter" | "pro" | "agency" | "studio_plus";
interval?: "monthly" | "yearly";
}
Response 200 (application/json)
{
ok: true;
plan: string;
interval: "monthly" | "yearly";
currentInterval: "monthly" | "yearly";
intervalChange: boolean;
chargedNow: boolean;
currency: string;
amountDue: number;
changeAmount: number;
invoiceDate: string;
prorationCredit: number;
prorationCharge: number;
creditToBalance: number;
recurringAmount: number | null;
renewsAt: string | null;
tax: number | null;
discountEnds: boolean;
founderAnnualOffer: boolean;
discountAmount: number;
itemsMoved: number;
prorationDate: number;
}
Errors: 400, 401, 403, 409, 500, 503, with the error body.
POST /billing/org/{orgId}/cancel
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
cancelImmediately?: boolean;
}
Response 200 (application/json)
{
ok: true;
cancelAtPeriodEnd: boolean;
currentPeriodEnd: string | string (date-time);
}
Errors: 400, 401, 403, 500, with the error body.
POST /billing/org/{orgId}/reactivate
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
status: "active" | "canceled" | "incomplete" | "incomplete_expired" | "past_due" | "paused" | "trialing" | "unpaid";
currentPeriodEnd: string (date-time);
}
GET /billing/org/{orgId}/overages
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
summary: {
orgId: string;
periodStart: string (date-time);
periodEnd: string (date-time);
overages: {
metric: string;
metricName: string;
currentUsage: number;
limit: number;
overage: number;
unitSize: number;
overageUnits: number;
pricePerUnit: number;
totalChargeCents: number;
}[];
totalOverageCents: number;
creditsApplied: number;
netChargeCents: number;
};
pricing: {
[key: string]: {
unitSize: number;
priceCents: number;
};
};
}
GET /billing/org/{orgId}/overages/history
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
limit | query | string | No |
Response 200 (application/json)
{
ok: boolean;
overages: any[];
}
GET /billing/org/{orgId}/tax-info
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: true;
taxInfo: {
taxId: string | null;
taxIdType: string | null;
taxIdVerified: boolean;
taxIdVerification: "verified" | "pending" | "unverified" | "not_applicable";
businessName: string | null;
address: {
line1: string | null;
line2: string | null;
city: string | null;
state: string | null;
postalCode: string | null;
country: string | null;
};
};
taxIdTypes: {
code: string;
label: string;
}[];
}
Errors: 401, 403, with the error body.
PUT /billing/org/{orgId}/tax-info
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
taxId?: string | null;
taxIdType?: string | null;
businessName?: string | null;
address?: {
line1?: string | null;
line2?: string | null;
city?: string | null;
state?: string | null;
postalCode?: string | null;
country?: string | null;
};
}
Response 200 (application/json)
{
ok: true;
stripeSynced: boolean;
taxIdSubmitted: boolean;
taxIdVerified: boolean;
warning: string | null;
}
Errors: 401, 403, with the error body.
POST /billing/org/{orgId}/pause
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
status: string;
pauseStartedAt: string;
pauseExpiresAt: string;
}
POST /billing/org/{orgId}/resume
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
status: string;
resumedAt: string;
pauseCooldownEndsAt: string;
}
GET /billing/org/{orgId}/invoices
| Parameter | In | Type | Required |
|---|
q | query | string | No |
status | query | "paid" | "due" | "overdue" | "void" | ("paid" | "due" | "overdue" | "void")[] | No |
since | query | string (date-time) | No |
until | query | string (date-time) | No |
startingAfter | query | string | No |
limit | query | number | No |
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
canPay: boolean;
invoices: {
id: string;
number: string | null;
status: string | null;
displayStatus: "paid" | "due" | "overdue" | "void" | "draft";
description: string | null;
amountCents: number;
amountDue: number;
amountPaid: number;
currency: string;
createdAt: string;
dueDate: string | null;
paidAt: string | null;
hostedInvoiceUrl: string | null;
invoicePdf: string | null;
plan: string | null;
interval: string | null;
affectsPlan: boolean;
source: "stripe" | "contract";
}[];
hasMore: boolean;
nextCursor: string | null;
}
Errors: 400, 401, 403, 500, with the error body.
GET /billing/org/{orgId}/cost-breakdown
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
period: {
start: string;
end: string;
};
projects: {
sharePercent: number;
planAllocatedCents: number;
veramentCredits: number;
dedicatedDatabasesCents: number;
totalCents: number;
projectId: string;
name: string;
}[];
deletedProjects: null | {
sharePercent: number;
planAllocatedCents: number;
veramentCredits: number;
dedicatedDatabasesCents: number;
totalCents: number;
};
notTiedToProject: {
lines: {
label: string;
cents: number;
}[];
cents: number;
veramentCredits: number;
};
totals: {
planCents: number;
veramentCredits: number;
dedicatedDatabasesCents: number;
totalCents: number;
};
method: "metered_share";
}
GET /billing/org/{orgId}/usage/realtime
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
apiRequests: {
used: number;
limit: number;
percent: number;
};
storage: {
usedBytes: number;
limitBytes: number;
percent: number;
};
aiCredits: {
used: number;
limit: number;
percent: number;
daysUntilReset: number;
};
functions: {
invocations: number;
limit: number;
percent: number;
};
realtimeConnections: {
current: number;
limit: number;
percent: number;
};
databaseRows: {
current: number;
limit: number;
percent: number;
};
mau: {
current: number;
limit: number;
percent: number;
};
trend24h: {
apiRequests: number[];
aiCredits: number[];
};
}
GET /billing/org/{orgId}/invoices/{invoiceId}/pdf
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
invoiceId | path | string | Yes |
Response 200
No body.
GET /billing/org/{orgId}/credits/auto-topup
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: true;
settings: {
enabled: boolean;
packageId: string;
monthlyCapUsd: number;
updatedAt: string | null;
};
eligible: boolean;
ineligibleReason: string | null;
canEdit: boolean;
periodKey: string;
chargedThisPeriodCents: number;
usedThisMonthCents: number;
remainingCapCents: number;
notifyAtPercent: number;
paymentMethodOnFile: boolean | null;
lastTopUp: {
at: string;
credits: number;
amountCents: number;
status: "charged" | "requires_action" | "failed";
} | null;
packages: {
id: string;
label: string;
description: string;
priceInCents: number;
amount: number;
}[];
}
Errors: 401, 403, with the error body.
PUT /billing/org/{orgId}/credits/auto-topup
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
enabled: boolean;
packageId: "credits_10" | "credits_25" | "credits_50" | "credits_100";
monthlyCapUsd: number;
}
Response 200 (application/json)
{
ok: true;
settings: {
enabled: boolean;
packageId: string;
monthlyCapUsd: number;
updatedAt: string | null;
};
eligible: boolean;
ineligibleReason: string | null;
canEdit: boolean;
periodKey: string;
chargedThisPeriodCents: number;
usedThisMonthCents: number;
remainingCapCents: number;
notifyAtPercent: number;
paymentMethodOnFile: boolean | null;
lastTopUp: {
at: string;
credits: number;
amountCents: number;
status: "charged" | "requires_action" | "failed";
} | null;
packages: {
id: string;
label: string;
description: string;
priceInCents: number;
amount: number;
}[];
}
Errors: 400, 401, 403, with the error body.
POST /billing/org/{orgId}/credits/purchase
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
packageId: "credits_10" | "credits_25" | "credits_50" | "credits_100";
successUrl?: string (uri);
cancelUrl?: string (uri);
}
Response 200 (application/json)
{
ok: true;
checkoutUrl: string | null;
}
Errors: 400, 401, 403, 500, with the error body.
GET /billing/org/{orgId}/credits/transactions
| Parameter | In | Type | Required |
|---|
type | query | "usage" | "plan" | "purchase" | "auto_topup" | "adjustment" | No |
period | query | "current" | "previous" | "all" | No |
before | query | string | No |
limit | query | number | No |
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
rows: {
id: string;
date: string;
type: "usage" | "plan" | "purchase" | "auto_topup" | "adjustment";
description: string;
project: {
id: string;
name: string;
} | null;
tier: "lite" | "standard" | "max" | "verament";
credits: number;
amountCents: number | null;
actor: {
name: string;
} | null;
}[];
nextCursor: string | null;
}
Errors: 400, 401, 403, with the error body.
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
contacts: {
id: string;
name: string;
email: string;
phone: string | null;
isPrimary: boolean;
receiveInvoices: boolean;
receiveAlerts: boolean;
createdAt: string;
}[];
}
Errors: 401, 403, with the error body.
POST /billing/org/{orgId}/contacts
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json, required)
{
name: string;
email: string (email);
phone?: string;
receiveInvoices?: boolean;
receiveAlerts?: boolean;
}
Response 200 (application/json)
{
ok: true;
contactId: string;
isPrimary: boolean;
}
Errors: 401, 403, 409, with the error body.
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
contactId | path | string (uuid) | Yes |
Request body (application/json, required)
{
name?: string;
phone?: string | null;
receiveInvoices?: boolean;
receiveAlerts?: boolean;
isPrimary?: true;
}
Response 200 (application/json)
{
ok: true;
contact: {
id: string;
name: string;
email: string;
phone: string | null;
isPrimary: boolean;
receiveInvoices: boolean;
receiveAlerts: boolean;
createdAt: string;
};
}
Errors: 400, 401, 403, 404, with the error body.
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
contactId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
}
Errors: 401, 403, 404, with the error body.
POST /billing/enterprise/inquiry
Request body (application/json, required)
{
orgId: string (uuid);
name: string;
email: string (email);
company: string;
phone?: string;
teamSize?: "1-10" | "11-50" | "51-200" | "201-1000" | "1000+";
message?: string;
}
Response 200 (application/json)
{
ok: true;
sentAt: string;
}
Errors: 401, 403, 429, with the error body.
POST /billing/promo-codes/validate
Request body (application/json, required)
{
code: string;
plan?: "entry" | "entry_plus" | "starter" | "pro" | "agency" | "studio_plus";
interval?: "monthly" | "yearly";
}
Response 200 (application/json)
{
ok: true;
code: string;
discountType: string;
discountValue: number;
duration: string;
durationMonths: number | null;
applicablePlans: string[] | null;
expiresAt: string | string (date-time);
founder?: {
offer: "launch25" | "founder_annual";
summary: string;
otherIntervalSummary: string;
seatsRemaining: number;
seatsTotal: number;
foundingPriceForever: true;
};
}
Errors: 400, 404, 410, 429, 500, with the error body.
POST /billing/redeem-promo
Request body (application/json, required)
{
orgId: string (uuid);
code: string;
}
Response 200 (application/json)
{
ok: true;
code: string;
creditsAdded: number;
}
Errors: 401, 403, 404, 429, 500, with the error body.
GET /billing/org/{orgId}/founder
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
founder: {
number: number | null;
since: string;
offer: "launch25" | "founder_annual";
plan: string | null;
priceLock: "forever";
priceLockUntil: "null";
foundingPrices: {
plan: string;
interval: string;
unitAmountCents: number | null;
currency: string | null;
}[];
wall: {
optIn: boolean;
name: string | null;
url: string | null;
};
} | null;
pendingClaim: {
offer: "launch25" | "founder_annual";
reservedUntil: string;
} | null;
earlyAccess: {
hostedMcp: boolean;
websiteHosting: boolean;
};
availability: {
open: boolean;
seatsTotal: number;
seatsRemaining: number;
code: string;
offers: {
launch25: {
interval: "monthly" | "yearly";
percentOff: number;
durationMonths: number;
summary: string;
};
founder_annual: {
interval: "monthly" | "yearly";
percentOff: number;
durationMonths: number;
summary: string;
};
};
};
}
Errors: 401, 403, with the error body.
PUT /billing/org/{orgId}/founder/wall
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Request body (application/json, required)
{
optIn: boolean;
name?: string | null;
url?: string | null;
}
Response 200 (application/json)
{
ok: true;
wall: {
optIn: boolean;
name: string | null;
url: string | null;
};
}
Errors: 400, 401, 403, with the error body.
GET /billing/founders/wall
Response 200 (application/json)
{
availability: {
open: boolean;
seatsTotal: number;
seatsRemaining: number;
code: string;
offers: {
launch25: {
interval: "monthly" | "yearly";
percentOff: number;
durationMonths: number;
summary: string;
};
founder_annual: {
interval: "monthly" | "yearly";
percentOff: number;
durationMonths: number;
summary: string;
};
};
};
founders: {
number: number | null;
name: string;
url: string | null;
}[];
}
GET /billing/org/{orgId}/card-check
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Response 200 (application/json)
{
required: boolean;
verified: boolean;
verifiedAt: string | null;
card: {
brand: string | null;
last4: string | null;
} | null;
lastAttemptRefused: boolean;
}
Errors: 401, 403, with the error body.
POST /billing/org/{orgId}/card-check/session
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Request body (application/json, required)
{
successUrl?: string (uri);
cancelUrl?: string (uri);
}
Response 200 (application/json)
{
ok: true;
url: string;
sessionId: string;
}
Errors: 400, 401, 403, 409, 502, with the error body.
POST /billing/org/{orgId}/card-check/confirm
| Parameter | In | Type | Required |
|---|
orgId | path | string (uuid) | Yes |
Request body (application/json, required)
{
sessionId: string;
}
Response 200 (application/json)
{
ok: true;
verified: true;
card: {
brand: string | null;
last4: string | null;
};
}
Errors: 400, 401, 403, 409, 502, with the error body.
GET /billing/addons/catalog
| Parameter | In | Type | Required |
|---|
orgId | query | string | No |
Response 200 (application/json)
{
ok: boolean;
addons: {
type: "ai_credits" | "always_on" | "bandwidth" | "compute" | "database" | "storage";
name: string;
description: string;
unitLabel: string;
unitPriceCents: number;
minQuantity: number;
maxQuantity: number;
quantityStep: number;
availableOnPlans: ("agency" | "enterprise" | "entry" | "entry_plus" | "free" | "pro" | "starter" | "studio_plus")[];
retired?: true;
annualUnitPriceCents: number;
}[];
billingInterval: "monthly" | "yearly";
dedicatedDatabases: {
soldSeparately: boolean;
href: string;
message: string;
};
currentPlan: string;
}
GET /billing/org/{orgId}/addons
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
addons: {
id: string;
addonType: string;
name: string;
description: null | string;
quantity: number;
unitPriceCents: number;
totalPriceCents: number;
status: string;
effectiveAt: string;
createdAt: string;
}[];
totalMonthlyCents: number;
}
POST /billing/org/{orgId}/addons
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
ok: boolean;
addonId: string;
addonType: "ai_credits" | "always_on" | "bandwidth" | "compute" | "storage";
name: string;
quantity: number;
unitPriceCents: number;
totalPriceCents: number;
stripeItemId: string;
}
Response 201 (application/json)
{
ok: boolean;
addonId: string;
addonType: "ai_credits" | "always_on" | "bandwidth" | "compute" | "storage";
name: string;
quantity: number;
unitPriceCents: number;
totalPriceCents: number;
stripeItemId: string;
}
POST /billing/org/{orgId}/addons/preview
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Request body (application/json)
{
addonType: "ai_credits" | "always_on" | "bandwidth" | "compute" | "storage";
quantity: number;
}
Response 200 (application/json)
{
addonType: "ai_credits" | "always_on" | "bandwidth" | "compute" | "storage";
quantity: number;
newQuantity: number;
dueTodayCents: number;
nextInvoiceDeltaCents: number;
currency: string;
interval: "monthly" | "yearly";
paymentMethod: null | {
brand: string;
last4: string;
};
}
POST /billing/org/{orgId}/addons/{addonId}/preview
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
addonId | path | string | Yes |
Request body (application/json)
{
quantity: number;
}
Response 200 (application/json)
{
quantity: number;
wasQuantity: number;
monthlyCents: number;
wasMonthlyCents: number;
dueTodayCents: number;
creditCents: number;
nextInvoiceDeltaCents: number;
currency: string;
interval: "monthly" | "yearly";
paymentMethod: null;
effect: string;
} | {
quantity: number;
wasQuantity: number;
monthlyCents: number;
wasMonthlyCents: number;
dueTodayCents: number;
creditCents: number;
nextInvoiceDeltaCents: number;
currency: string;
interval: "monthly" | "yearly";
paymentMethod: null | {
brand: string;
last4: string;
};
effect: null | string;
}
PATCH /billing/org/{orgId}/addons/{addonId}
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
addonId | path | string | Yes |
Request body (application/json)
{
quantity: number;
}
Response 200 (application/json)
{
wasQuantity?: number;
monthlyCents?: number;
wasMonthlyCents?: number;
dueTodayCents?: number;
creditCents?: number;
nextInvoiceDeltaCents?: number;
currency?: string;
interval?: "monthly" | "yearly";
effect?: null | string;
ok: boolean;
addonId: string;
quantity: number;
totalPriceCents: number;
}
DELETE /billing/org/{orgId}/addons/{addonId}
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
addonId | path | string | Yes |
Response 200 (application/json)
{
quantity?: number;
wasQuantity?: number;
monthlyCents?: number;
wasMonthlyCents?: number;
dueTodayCents?: number;
creditCents?: number;
nextInvoiceDeltaCents?: number;
currency?: string;
interval?: "monthly" | "yearly";
effect?: null | string;
ok: boolean;
}
GET /billing/org/{orgId}/usage
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
Response 200 (application/json)
{
plan: "agency" | "enterprise" | "free" | "pro" | "starter" | "studio_plus";
period: {
start: string;
end: string;
source: "calendar";
};
projects: {
used: number;
max: number;
};
members: {
used: number;
max: number;
};
mau: {
current: number;
included: number;
hardLimit: boolean;
};
realtimePeak: {
peak: number;
max: number;
};
usage: {
storage: {
usedGb: number;
planLimitGb: number;
addonGb: number;
effectiveLimitGb: number;
};
aiCredits: {
used: number;
planLimit: number;
addonCredits: number;
effectiveLimit: number;
remaining: number;
balance: number;
percentUsed: number;
};
compute: {
invocations: number;
planLimit: number;
addonInvocations: number;
effectiveLimit: number;
};
apiRequests: {
used: number;
limit: number;
};
bandwidth: {
usedGb: number;
addonGb: number;
};
hostingEgress: {
usedBytes: number;
includedBytes: number;
};
databaseRows: {
used: number;
limit: number;
};
};
addons: {
active: number;
totalMonthlyCents: number;
byType: {
[key: string]: number;
};
};
ok: boolean;
}
GET /billing/org/{orgId}/usage/history
| Parameter | In | Type | Required |
|---|
orgId | path | string | Yes |
months | query | number | No |
Response 200 (application/json)
{
ok: boolean;
history: {
period: {
start: string;
end: string;
};
inProgress: boolean;
apiRequests: null | number;
functionInvocations: null | number;
veramentCredits: null | number;
storagePeakBytes: null | number;
egressBytes: null | number;
limits: null | {
apiRequests: number;
functionInvocations: number;
veramentCredits: number;
storagePeakBytes: number;
egressBytes: number;
};
}[];
}