Billing & consent
Confirming a per-project charge.
If your organization is billed per project, creating a new project over the API requires explicitly acknowledging the charge — the API equivalent of the in-app cost-confirmation step.
Who this applies to
Only enterprise per-project organizations, and only when an upload creates a new billable project. It never applies to other plans, and never to saving a new version of an existing project (/versions) or re-uploading identical bytes — those add no billable unit.
Two responses to handle
| Error code (402) | Meaning & what to do |
|---|---|
billing_setup_required | Billing isn't set up yet (e.g. your first project). A charge can't be approved with no payment configured — set up billing in the PLCs desktop app first, then retry. |
billing_acknowledgement_required | Billing is set up but the charge wasn't acknowledged. The response carries a billing block with the projected cost; disclose it, then resend with acknowledge_billing: true. |
The cost block
json
{
"error": "billing_acknowledgement_required",
"message": "This project upload will incur a per-project charge that was not acknowledged.",
"userMessage": "This organization is billed per project. Uploading this project adds a new billable project (about $500.00 USD).",
"suggestedAction": "Resend the request with \"acknowledge_billing\": true to confirm the charge and create the project.",
"isRetryable": false,
"billing": {
"price_per_project_cents": 50000,
"currency": "usd",
"billed_count_after": 3
},
"request_id": "req_8f2a1c9d4e5b6a7c8d9e0f12"
}python
from plcsai import ApiError
try:
client.ingest_project(file_path="NewLine.L5X")
except ApiError as e:
if e.error == "billing_setup_required":
raise SystemExit("Set up billing in the PLCs desktop app first.")
if e.error == "billing_acknowledgement_required":
cents = e.billing["price_per_project_cents"]
print(f"This adds a billable project (~${cents/100:.2f}). Confirming…")
client.ingest_project(file_path="NewLine.L5X", acknowledge_billing=True)
else:
raisecsharp
try
{
await client.IngestProjectAsync(File.ReadAllBytes("NewLine.L5X"), "NewLine.L5X");
}
catch (PlcsApiException e) when (e.Error == "billing_setup_required")
{
Console.WriteLine("Set up billing in the PLCs desktop app first.");
}
catch (PlcsApiException e) when (e.Error == "billing_acknowledgement_required")
{
Console.WriteLine($"This adds a billable project (~${e.Billing!.PricePerProjectCents / 100.0:0.00}). Confirming…");
await client.IngestProjectAsync(File.ReadAllBytes("NewLine.L5X"), "NewLine.L5X", acknowledgeBilling: true);
}Acknowledgement is only consulted when a charge actually results. Sending acknowledge_billing: true on an upload that doesn't add a billable project (or for a non-per-project org) is harmless and ignored.