Billing & spend caps

When the API stops spending.

Model-backed calls are metered and attributed to the key that made them. They need an active plan, and an organization can also cap what its API keys are allowed to spend in a period. When either check fails, the calls that would spend are refused rather than silently billed.

Which calls spend

The ones that run a model or a pipeline: interpret, generate (both the plan call and the approve call), conversation messages, asking for an analyses run, saving a version, and requesting live tags (/hmi/request-tags). Reads (the project list, metadata, source, live values, an analysis read, export polls) cost nothing and are never gated by the spend cap.

The two responses to handle

Error code (402)Meaning & what to do
subscription_requiredThe org's plan is not active (trial ended, term expired, canceled, unpaid, or AI paused for the period). reason says which. Not retryable: an org owner has to subscribe or renew first.
api_spend_limit_reachedThe org paused API usage after reaching its spend limit for the period. Not retryable: surface it to a human rather than backing off, because nothing changes until someone acts.

When the plan is not active

An API key keeps working after the plan it was created under lapses, but only for reads. Every call that spends returns 402 subscription_required, and so do live values and history (/hmi/values, /hmi/history). Everything else stays open: the project list and metadata, source, analysis reads, device inventory, and exports. A lapsed org can still read and export its data.

The plan is checked first, so a lapsed org gets subscription_required even if it is also over its spend cap. A key that lacks the endpoint's scope still gets 403 forbidden, because permissions are checked before billing.

json
{
  "error": "subscription_required",
  "message": "This organization's subscription does not cover this request (TRIAL_EXPIRED).",
  "userMessage": "Your organization's plan is not active, so AI and live-data API requests are paused. Reading your projects and exports still works.",
  "suggestedAction": "An org owner can subscribe or renew in Settings → Billing, or contact your account team. Retry once the plan is active.",
  "isRetryable": false,
  "reason": "TRIAL_EXPIRED",
  "request_id": "req_8f2a1c9d4e5b6a7c8d9e0f12"
}

reason is a short code naming why the plan is not active. Branch on error, not on reason: treat reason as detail to log or quote to support.

When the spend cap is reached

json
{
  "error": "api_spend_limit_reached",
  "message": "This organization has reached its API spend limit for the period.",
  "userMessage": "Your organization paused API usage after reaching its monthly API spend limit.",
  "suggestedAction": "An org owner/admin can raise or remove the limit, or switch to \"Continue with overage billing\", in Settings → Spending Controls.",
  "isRetryable": false,
  "request_id": "req_8f2a1c9d4e5b6a7c8d9e0f12"
}
python
from plcsai import ApiError

try:
    result = client.interpret("prj_…", "Why is the filler stuck?")
except ApiError as e:
    if e.error in ("subscription_required", "api_spend_limit_reached"):
        # Do not retry. An owner has to renew the plan or raise the cap first.
        notify_operator(e.user_message, e.suggested_action)
    else:
        raise
csharp
try
{
    var result = await client.InterpretAsync("prj_…", "Why is the filler stuck?");
}
catch (PlcsApiException e) when (e.Error is "subscription_required" or "api_spend_limit_reached")
{
    // Do not retry. An owner has to renew the plan or raise the cap first.
    NotifyOperator(e.UserMessage, e.SuggestedAction);
}

Usage is reported, not billed, on the call itself. Every model-backed response carries a usage block summing the token counts across every model call that turn made — informational, so you can attribute cost per integration. It is not an invoice.

Per-project charges

Organizations billed per project confirm that charge when a machine is onboarded — which happens in the app or through a version-source connector, never over this API. There is no create-a-project verb here, so an API key cannot add a billable project and no acknowledgement handshake applies to it.

Saving a new version of an existing project (/versions) adds no billable project, on any plan.