External wallets
Connect a dedicated Nodaro Cloud deployment to your own shared wallet, which reserves, settles and reports each customer's credits across all your products.
Available on Nodaro Cloud
An external wallet is a service you run that holds each customer's shared budget, and that a dedicated Nodaro Cloud deployment consults before it spends. Nodaro asks the wallet to reserve credits before each generation, settles the exact amount afterwards, and reads the balance to show it to the customer. The deployment's billing account still pays for platform usage from its prepaid pool; the wallet decides how much of that each customer may use, across all your products.
How it fits together
- A billing account pays. The deployment names one billing account (
billing.payerAccountin its surface profile), whose prepaid pool pays for every action on the deployment. See Editions and surface profiles. - SSO identifies the customer. Customers sign in through the deployment's SSO provider. The provider's subject for a customer, sent as
sso_subject, is how your wallet recognizes the customer. - The wallet decides. For every single-node request and every workflow node, Nodaro checks the billing account's prepaid pool, then asks your wallet to reserve against the customer's shared budget. The customer's local Nodaro credit balance plays no part.
An empty prepaid pool can stop a request before the wallet is asked. Once asked, the wallet's decision is final for the customer's shared budget.
Reserve
A customer starts a generation. Nodaro sends reserve with an operation_id and an amount, and your wallet holds that amount atomically and answers allow or deny.
Run
On allow, the model runs. On anything else, nothing is sent to the model.
Settle
When the work ends, Nodaro sends settle with the actual amount. Your wallet charges exactly that amount and releases the rest of the hold.
Show the balance
The studio asks your wallet for the customer's balance, and shows it in the deployment's display unit.
Configure the deployment
Set these variables on the API and on the workers:
| Variable | What it sets |
|---|---|
DEPLOYMENT_WALLET_URL | The wallet's endpoint. It must use HTTPS. |
DEPLOYMENT_WALLET_TOKEN | A dedicated server secret that Nodaro sends as a bearer token. |
DEPLOYMENT_WALLET_SSO_PROVIDER | The id of the SSO provider whose subjects identify customers. |
DEPLOYMENT_WALLET_TIMEOUT_MS | The time limit of each wallet call, from 1000 to 30000 milliseconds. The default is 10000. |
- Set the first three together. Leave all three unset to keep the deployment's existing billing.
- Turn off local allowances. The per-user allowance enforcement,
billing.allowances: "enforce", must be off. A configuration that combines the two is refused at activation. - Agree on the unit first. Before you activate the wallet, agree on the conversion between Nodaro credits and your product's budget. Set
billing.unitRateandbilling.unitLabelin the surface profile to match, so both products show the same figure.
The request contract
Nodaro sends every call as a POST with a JSON body that carries contract: 1 and unit: "nodaro_credit", and the header Authorization: Bearer <token>. The amounts are Nodaro credits. Never read them as your own product's units without an explicit conversion that your wallet owns.
Reserve
{
"contract": 1,
"unit": "nodaro_credit",
"action": "reserve",
"operation_id": "a3354131-4e5e-43a6-8f61-3914f09c658e",
"job_id": null,
"user_id": "5bf0d884-47b1-468e-a7b2-2433f957b267",
"sso_provider": "partner",
"sso_subject": "customer-123",
"model_identifier": "example-model",
"reserved_credits": 30
}| Field | Meaning |
|---|---|
operation_id | One usage record. A job or a workflow can contain several. |
sso_subject | The customer. It comes from trusted sign-in data that Nodaro's server manages, so use it to identify the customer. |
sso_provider, user_id | The SSO provider and the Nodaro user behind the request. |
model_identifier | The model being billed. |
reserved_credits | The whole number of credits to hold. |
Reserve the amount atomically against the customer's shared available budget before you answer. To allow the request:
{"contract":1,"unit":"nodaro_credit","operation_id":"a3354131-4e5e-43a6-8f61-3914f09c658e","decision":"allow","reserved_credits":30}For insufficient funds or an account that may not spend, answer HTTP 200 with the same envelope and "decision": "deny"; no amount is needed. Answer a service error with a status outside the 2xx range.
Nothing reaches the model unless your wallet allows it. A timeout, a malformed answer, a mismatched amount or id, a missing identity and a denial all stop the request. The request's Idempotency-Key header is <operation_id>:reserve.
Settle or release
When the work ends, Nodaro sends the same operation fields with "action": "settle" and actual_credits. Charge exactly that amount and release the rest of the hold. A settle of 0 releases everything.
{"contract":1,"unit":"nodaro_credit","operation_id":"a3354131-4e5e-43a6-8f61-3914f09c658e","settled":true,"actual_credits":12}- The key is
<operation_id>:settle. Delivery is at least once. A retry must return the original result without charging again. - Refuse conflicts. Reject a request for the same operation with a different identity, reservation ceiling or final amount.
- A settle can arrive before a delayed reserve. A settle of
0must create a permanent final record, even for an operation you do not know yet. A later reserve must never reopen it. - Holds never expire. A generation, and a human review of its result, can outlive any HTTP request. Keep each hold until it is settled, and keep your idempotency records. Never release an active hold because a callback is late.
Balance
{"contract":1,"unit":"nodaro_credit","action":"balance","user_id":"5bf0d884-47b1-468e-a7b2-2433f957b267","sso_provider":"partner","sso_subject":"customer-123"}{"contract":1,"unit":"nodaro_credit","sso_subject":"customer-123","available_credits":250}- Available means after holds.
available_creditsexcludes every outstanding hold, across all your products. - Fractions are allowed here. The balance may be fractional, so a remainder smaller than one billable credit can still be shown. Reserve and settle amounts are always whole credits.
- One figure in the studio. The studio converts the balance once into the deployment's display unit and hides its own per-user allowance display. An unavailable balance appears as unknown.
- Reserve decides races. When requests arrive at the same moment, the reserve call, not the balance, is authoritative.
Delivery and recovery
- Nodaro tries to deliver each settlement at once. If that fails, a worker that runs every minute retries it, with a backoff of up to one hour. Unacknowledged settlements are kept until they are delivered.
- Nodaro cancels on its own only the reservations that were never authorized. Authorized jobs that are running follow the normal job recovery.
- Never remove the wallet configuration, or point it to another wallet, while operations remain open. To rotate the token, rotate it on the same wallet.
The billing account's tools
The billing account manages the deployment's pool on its own page, /billing-admin, signed in with its own session.
Auto top-up of the pool
The /billing-admin page can turn on auto top-up. When the pool drops below a threshold, in raw credits, the card saved by the billing account's last card purchase is charged automatically.
- The usual limits apply. Each charge is from $5 to $1,000. There are at most 3 charges a day, 10 minutes apart, and auto top-up stops after 3 failed charges.
- Only work started in the product itself can trigger a charge. Personal API tokens, OAuth apps, connected instances, webhook, schedule and Telegram triggers spend the pool, but never charge the card. A pool they drain below the threshold is topped up on the next generation started in the app.
- A customer's own card is never charged. Auto top-up is for the billing account's pool only.
- Read the status.
GET /v1/deployment-billing/balanceincludesautoRecharge: whether it is enabled and active, the threshold, the amount, the failures and the last attempt.autoRechargeisnullwhen the status cannot be read.
Auto top-up needs a deployment that takes card payments. Without one, the deployment's operator tops up the pool instead.
Billing integration keys
The /billing-admin page also creates billing integration keys, for another system such as your back office. A key reaches only /v1/deployment-billing/*. Its kind is fixed when it is created:
| Key | Prefix | What it may do |
|---|---|---|
| Full | ndr_bill_… | Read the pool, the usage and the prices, and manage allowances. |
| Read-only | ndr_bill_ro_… | Read only. Any request other than GET answers 403 billing_key_read_only, before the route runs. |
Use a read-only key wherever only monitoring is needed.
Price discovery
GET /v1/deployment-billing/pricing returns the deployment's price list for your wallet's own display and planning. It needs the billing account's session or one of its billing integration keys.
| Field | Meaning |
|---|---|
creditCost | The base tariff of a model. |
creditIdentifier | The identifier that is billed. |
pricingBasis | What the base tariff assumes. |
pricing | For text models, the model's price key for each operation, such as describe-to-picker:<model>. |
estimate | true on a text model's row and on each such pricing entry: the figure is an estimate. |
denomination | The credit unit and the display conversion. |
purchaseOptions | The standard top-ups in USD, with their effective price per credit. Separate commercial terms may apply. |
- Text models are billed per model. A text model's
creditIdentifieris its Generate Text price key,llm-chat:<model>, with:directwhen the default call runs on the model maker's own API. ItscreditCostis an estimate: a typical call, charged its actual usage per token. Show it as approximate,≈N. Workflow Copilot, Content Recipe and Content Ideas still bill a tier row, and carry noestimate. - A text model with no price on its lane is listed in
missing. A text model'sisEnabledandcategorycome from thellm-chatrow. - Media variants resolve through the prices in effect. A variant without a configured price stays
null, with an error code. - Settings, quantity, duration and measured usage can change the final charge. Account with the reserve and settle amounts, never with a base tariff from this list.
- To detect changes, prefer a full request with
If-None-Match. Thesinceparameter follows the timestamps of price rows, and cannot see every change of runtime configuration.
Frequently asked questions
What is an external wallet in Nodaro?
A service you run that holds each customer's shared budget across your products. A dedicated Nodaro Cloud deployment asks it to reserve credits before a generation runs, settles the actual amount afterwards, and reads the balance to show it.
Which Nodaro deployments can use an external wallet?
A dedicated Nodaro Cloud deployment with a billing account, the one account that pays for every action on the deployment. Its customers sign in through the deployment's SSO provider, which identifies them to the wallet.
What happens if the wallet does not answer in time?
Nothing is generated. A timeout, a malformed answer, a mismatched amount or id, a missing identity and a denial all stop the request before any model runs.
Can the same settle request arrive twice?
Yes. Delivery is at least once, so your wallet must return the original result for a repeated settle without charging again. The Idempotency-Key header identifies repeats.
Do reservations expire?
No. A generation and a human review can take longer than any HTTP request, so a hold stays until Nodaro settles it. Never release an active hold because a callback is late.
Can a billing integration key be read-only?
Yes. The billing account creates full keys (ndr_bill_…) and read-only keys (ndr_bill_ro_…) on its /billing-admin page. A read-only key may only send GET requests; any other request answers 403 billing_key_read_only.
Related
External sign-in (SSO)
Credits
Editions and surface profiles
Credits
Last updated on
3D scene format
How a Nodaro 3D scene plan is built, from version 1 primitives and keyframes to version 2 GLB assets, semantic entities, camera tracks, shots and edit overlays.
Agent skills
Ready-made instruction files that teach coding agents to build on Nodaro with the SDK and OAuth, plus the Claude Code plugin, the SDK primer and Markdown docs.