Billing
The Billing OpenAPI tag covers the plan catalog and, per organization, the current plan and quota usage. Shapes include PlansResponse, BillingPlanResponse, and QuotaReport — see the API reference.
Changing plans, the customer billing portal, and over-capacity remediation are done in the dashboard (Settings → Billing). Those operations are not part of the public API, and an API key gets 403 api_surface_not_available on them.
Org context: Org-scoped billing routes encode the organization id in the path (/orgs/{id}/billing/...); they do not use X-Org.
Operations vs wire routes
Section titled “Operations vs wire routes”| Concern | HTTP | operationId | Notes |
|---|---|---|---|
| Plan catalog | GET /plans | get_plans | PlansResponse. |
| Current plan | GET /orgs/{id}/billing/plan | get_org_billing_plan | BillingPlanResponse. |
| Usage / quotas | GET /orgs/{id}/billing/usage | get_org_billing_usage | QuotaReport. Each QuotaUsage carries a machine-readable unit (count or seconds); the response also includes an optional degradation block when the org is over capacity. |
SDK coverage
Section titled “SDK coverage”| Surface | Python / Rust (openapp_sdk) | Go | TypeScript (AsyncClient) |
|---|---|---|---|
| Billing sub-client | client.billing.plan(org_id), client.billing.usage(org_id) | BillingAPIService | client.billing.plan(orgId), client.billing.usage(orgId) |
Typical errors
Section titled “Typical errors”401 / 403 when the caller lacks billing or org permissions. Errors follow ApiErrorResponse — see Errors & retries.
Examples
Section titled “Examples”List public plans (GET /plans)
Section titled “List public plans (GET /plans)”There is no client.billing yet — use the internal JSON dispatcher on AsyncClient (same transport as sub-clients):
plans = await client._request("GET", "/plans")GetPlans returns PlansResponse.
import ( "context"
openapiclient "github.com/tomers/openapp-sdk/go")
plans, httpResp, err := client.BillingAPI.GetPlans(context.Background()).Execute()if err != nil { return err}defer httpResp.Body.Close()_ = plansuse openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;use serde_json::Value;
let client = Client::builder() .api_key("https://openapp.house_openapp_YOUR_SECRET") .build()?;
let plans: Value = client .transport() .request_json(RequestSpec { method: Method::GET, path: "/plans", ..Default::default() }) .await?;const plans = await fetch("https://openapp.house/api/v1/plans", { headers: { "x-api-key": "https://openapp.house_openapp_YOUR_SECRET" },}).then((r) => r.json());/plans is the public catalog — the bundle omits a security block, but include the API key when the gateway requires authentication. Replace with AsyncClient.getPlans once the Node façade exposes it.
Get an organization’s billing plan
Section titled “Get an organization’s billing plan”plan = await client._request("GET", f"/orgs/{org_id}/billing/plan")plan, httpResp, err := client.BillingAPI.GetOrgBillingPlan(context.Background(), orgId).Execute()if err != nil { return err}defer httpResp.Body.Close()_ = planuse openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;use serde_json::Value;
let path = format!("/orgs/{org_id}/billing/plan");let plan: Value = client .transport() .request_json(RequestSpec { method: Method::GET, path: &path, ..Default::default() }) .await?;const plan = await fetch( `https://openapp.house/api/v1/orgs/${orgId}/billing/plan`, { headers: { "x-api-key": "https://openapp.house_openapp_YOUR_SECRET" } },).then((r) => r.json() as Promise<{ tier_slug: string; status: string }>);The org id rides in the path — billing routes do not consume X-Org in the canonical bundle. Replace with AsyncClient.getOrgBillingPlan once the Node façade exposes it.
Org billing usage (GET /orgs/{id}/billing/usage)
Section titled “Org billing usage (GET /orgs/{id}/billing/usage)”Returns a QuotaReport (per-key usage vs limits for the org).
usage = await client._request("GET", f"/orgs/{org_id}/billing/usage")GetOrgBillingUsage returns QuotaReport.
import ( "context"
openapiclient "github.com/tomers/openapp-sdk/go")
usage, httpResp, err := client.BillingAPI.GetOrgBillingUsage(context.Background(), orgId).Execute()if err != nil { return err}defer httpResp.Body.Close()_ = usageuse openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;use serde_json::Value;
let client = Client::builder() .api_key("https://openapp.house_openapp_YOUR_SECRET") .build()?;
let path = format!("/orgs/{org_id}/billing/usage");let usage: Value = client .transport() .request_json(RequestSpec { method: Method::GET, path: &path, ..Default::default() }) .await?;const usage = await fetch( `https://openapp.house/api/v1/orgs/${orgId}/billing/usage`, { headers: { "x-api-key": "https://openapp.house_openapp_YOUR_SECRET" } },).then((r) => r.json());Body matches QuotaReport — keys are QuotaKey values (e.g. scripting_executions). Replace with AsyncClient.getOrgBillingUsage once the Node façade exposes it.
Related
Section titled “Related”Org CRUD and membership are documented under Organizations. For quota keys referenced in usage reports, see QuotaKey in OpenAPI (for example scripting_executions on Scripting).