RECEIPTS AND INVOICES

Show each customer exactly what they used

Every amount names who used it. You decide whether your customers see one all-in amount or a cost breakdown, and every invoice carries a reference you can check against your own request records.

Who sees what

Modelvia charges your business for every routed request, including Jev routing and the platform fee. What your own customers see of those charges is your choice. The amounts are the same in every view; only how a customer’s amount is described changes.

ReaderWhat they see
Your customers (default)One “AI usage” amount per request and per invoice line. No routing unit, routing decision or service fee is shown or named.
Your customers, breakdown onThe same amount split into Model usage, Routing and Service fee, each at the customer’s own price. The parts add up to the amount they already pay.
Your businessThe full breakdown on your invoices from Modelvia: model usage, Jev routing and the platform fee, with every line attributed to the customer who used it or to your own internal use.
ModelviaThe full breakdown for operating and reconciling your account.

Your customers never see your wholesale cost from Modelvia or your markup, in either mode. Prices are GST-inclusive AUD. On your wholesale invoice, Jev routing is charged per routed request at A$0.00008 (80,000 nanoAUD) and the platform fee is 11%. Your customers see a routing or service-fee amount only when you turn on the cost breakdown, and then as parts of their own price.

Choose one amount or a cost breakdown

The client setting customerChargeDetail is all_in (the default) or itemized. An account that has never set it is all_in. As a client administrator, open Settings and use Show your customers a cost breakdown: off is all_in, on is itemized. Saving needs multi-factor sign-in.

OperationRequest and response
GET /v1/client/charge-detailReturns {clientId, version, customerChargeDetail} for your business.
POST /v1/client/charge-detailSend exactly clientId, version and customerChargeDetail. Returns the saved setting with the next version.
Read the current setting
curl --fail-with-body "https://api.modelvia.dev/v1/client/charge-detail" \
  -H "Authorization: Bearer $MODELVIA_CLIENT_KEY"

Charge-detail request body
// POST /v1/client/charge-detail from your trusted administration backend.
// Use clientId and version from a fresh GET. Example values are fictional.
{
  "clientId": "exampleco",
  "version": 12,
  "customerChargeDetail": "itemized"
}

Use your server-only client integration key. The client ID asserts which business you are editing; it never selects another one. A different client ID returns 409 charge_detail_scope_changed, a stale version returns 409 account_version_conflict, and any other value returns 400 invalid_customer_charge_detail. Read the setting again before retrying, and after a lost response confirm the saved version and value before reporting success.

Customer-facing responseall_initemized
Customer analyticsroutingSource, configuration and jev are omitted from each request; timing has no routingMs or candidateCount; summary.routing and latency.routing are absent and byRoutingSource is empty.Money adds customerModelUsageNanoAud, customerRoutingNanoAud and customerServiceFeeNanoAud, which sum to customerGrossNanoAud.
Customer billing rowsOne amount; units never include routing_calls.Each request adds modelUsageNanoAud, routingNanoAud and serviceFeeNanoAud, before credits.
Customer invoice JSON and documentOne amount per line.Sale lines add components with modelUsageCents, routingCents and serviceFeeCents, which sum to the line’s amountCents.
Model list for a customer’s project keyThe routing rate is included in the per-request rate; charge_detail is all_in.routing_calls is listed as its own unit; charge_detail is itemized.

Every response carries the mode it was built for: presentation.chargeDetail on analytics and chargeDetail on billing and invoices. Render the parts only when they are present; do not compute a breakdown yourself. Your own business-wide views keep the full breakdown in both modes.

Show who used each amount

Every money row carries usedBy, read from the request’s own recorded customer, project and key, never from anything a caller supplies. Show its displayName. Usage your business funds itself appears as your business’s name followed by “(internal use)” and is never invoiced to a customer.

The two kinds of usedBy
// A customer's request, and your business's own internal use. Fictional values.
{ "kind": "customer", "customerId": "exampleco-north", "displayName": "ExampleCo North", "projectId": "checkout-assistant" }
{ "kind": "client_internal", "clientId": "exampleco", "displayName": "ExampleCo (internal use)" }

  • Analytics: each recentRequests row and each byCustomer group.
  • Customer billing: the response and each requests row.
  • Customer invoices: the invoice and each line tied to a request.
  • Your invoices from Modelvia: each line, grouped by customer and then your internal use.
  • Project-key receipts from GET /v1/requests/{requestId}.

A response from an earlier gateway version may omit usedBy. Show a dash rather than guessing from a project or key ID.

Reconcile an invoice with your records

Each invoice issued with attribution carries an attestation: requestCount, requestIdsSha256, reference, totalNanoAud and totalCents. Your invoices from Modelvia also carry groups, one per customer and one for your internal use, each with its usedBy, requestCount and usageNanoAud. The hosted invoice shows the same value as Reconciliation reference, with its request count.

requestIdsSha256 is the SHA-256 of the invoice’s request IDs, sorted and joined with a newline. The reference is ATT- followed by the first 12 characters of that hash in capitals. Because the IDs are sorted, the same set of requests always gives the same reference.

Compute the reference from your own request records
// Server-side Node.js. requestIds are the request IDs YOUR records hold for this
// invoice: the receipts you stored for this customer and month.
import { createHash } from "node:crypto";

export function invoiceReference(requestIds) {
  const unique = [...new Set(requestIds)];
  if (unique.length !== requestIds.length) throw new Error("Duplicate request ID in your records");
  const sha256 = createHash("sha256").update([...unique].sort().join("\n")).digest("hex");
  return { requestCount: unique.length, requestIdsSha256: sha256, reference: "ATT-" + sha256.slice(0, 12).toUpperCase() };
}

  1. Collect the request IDs from the receipts you stored for that customer and month, or for your business’s own use.
  2. Compute the count and reference, and compare them with the invoice’s attestation.
  3. If they match, the invoice covers exactly those requests: none from another customer, none left out.
  4. If they differ, do not adjust the amount yourself. Contact Modelvia support with the invoice ID and the request IDs you hold.

Modelvia refuses to issue an invoice that would include a request not provably the payer’s. Invoices issued before attestations were added have attestation: null; their documents are unchanged.

Stopped and refused requests

  • A stopped request is billed only for what the model generated before it stopped. Closing the stream or the connection stops the request. The receipt shows unknown for a short while, from seconds to a few minutes, while the exact cost of the partial answer is confirmed with the model provider; it then shows the charge for that part and nothing more. Some model hosts cannot stop part-way; there the model finishes the answer on its own and the charge is for what it generated.
  • A request refused before generation costs nothing. Its receipt shows released and a charge of 0, and it appears on no invoice.
  • A request the model provider fails before any answer text reaches you is not charged, even if some of the model’s reasoning was already streamed.
  • Sending the same request again after Stop starts a new request. It is served and charged on its own, so a Regenerate button works without a new Idempotency-Key. A request you send again with the same Idempotency-Key is still the original, and returns its receipt instead.

Spending caps and the price each one uses

A customer’s monthly cap is enforced in the price that customer actually pays: your retail price, including your markup. Your business’s cap and each project’s cap stay in your own wholesale price from Modelvia. Set a customer’s cap from what you intend them to spend, not from your cost.

Next: let customers pay your business, or build their usage console.