CUSTOMER SETUP

Customers, projects and keys

Give each customer its own usage boundary. Your server creates the directory records; Modelvia establishes the billing relationship and accepted terms.

1. Confirm your business setup

This flow is available after operator-assisted onboarding, not public self-service signup. Ask Modelvia to confirm your billing identity, active client and billing service, who pays, approved models and caps, accepted rate card, and dedicated mgt_ client integration key. First complete the read-only business binding check; a key for the wrong client must stop setup.

Creating customers and projects is closed by default, even with a valid client integration key: only the Modelvia operator can open it for your client. Until Modelvia confirms it has, the creates below are refused with onboarding_operator_only (403). This does not affect an existing customer, project or key.

The examples assume your business pays Modelvia for its customers (billingMode: client). For mixed billing, only the client-paid branch can create projects or mint/rotate keys here. A customer billed directly by Modelvia needs a separately established billing account and the appropriate customer or operator workflow.

Backend environment
# Your backend or trusted CLI environment. Inject the secret securely.
export MODELVIA_API_URL=https://api.modelvia.dev
export MODELVIA_CUSTOMER_ID=exampleco-customer-001
export MODELVIA_PROJECT_ID=exampleco-project-001
# MODELVIA_CLIENT_KEY is the mgt_ integration key supplied by Modelvia.
# It is different from the project key used for inference.

Keep the client key on your server. It can manage your business subtree and authorized billing operations; it is not a customer login or a read-only token. Your application must bind its signed-in user to an allowed customer before calling it.

2. Create the customer

Save this as customer.json. Replace the fictional model and caps with your agreed values before submitting. These example limits are A$50 per month and two concurrent requests; they do not authorize spend.

customer.json
{
  "id": "exampleco-customer-001",
  "name": "ExampleCo sample customer",
  "active": true,
  "monthlyCapNanoAud": "50000000000",
  "maxConcurrent": 2,
  "allowedModels": [
    "example-vendor/example-model"
  ]
}

Create customer
curl --fail-with-body "$MODELVIA_API_URL/v1/client/customers" \
  -H "Authorization: Bearer $MODELVIA_CLIENT_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @customer.json

A successful create returns HTTP 200, your record, the key’s clientId and server-managed version. Omit version and billingCompanyId. Prefix IDs with your business namespace, using letters, numbers, underscores, periods or hyphens. Avoid slashes and colons: these client routes cannot address them. The platform does not add a prefix.

3. Create a project inside that customer

Save this as project.json. The example narrows the ceiling to A$10 per month, A$0.10 per request and one concurrent request. Every child’s models, monthly cap and concurrency must stay inside its parent; the project request cap cannot exceed its monthly cap.

project.json
{
  "id": "exampleco-project-001",
  "name": "ExampleCo sample project",
  "active": true,
  "monthlyCapNanoAud": "10000000000",
  "maxConcurrent": 1,
  "allowedModels": [
    "example-vendor/example-model"
  ],
  "environments": [
    "development"
  ],
  "requestCapNanoAud": "100000000"
}

Create project
curl --fail-with-body \
  "$MODELVIA_API_URL/v1/client/customers/$MODELVIA_CUSTOMER_ID/projects" \
  -H "Authorization: Bearer $MODELVIA_CLIENT_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @project.json

Keep the returned IDs in your server-side customer mapping. Caller-supplied IDs never grant access to another customer. These creation routes do not update existing records.

Save the exact customer binding

After the create responses succeed, store your own stable customer or company ID with the Modelvia clientId, customerId and projectId. Verify the returned parent IDs against your expected business and customer before saving. A display name, email address or project key ID is not a stable payer or access binding; keys can rotate.

Illustrative server-side customer binding
// ExampleCo's private application database, not a request body to Modelvia.
{
  "localCustomerId": "customer-001",
  "modelviaClientId": "exampleco",
  "modelviaCustomerId": "exampleco-customer-001",
  "modelviaProjectId": "exampleco-project-001",
  "active": true
}

On sign-in, your backend checks current membership in the local customer, loads this active binding and asks Modelvia only for that customerId. Keep one binding per intended customer scope; if an organization can switch offices or accounts, verify the selected local membership again before each read or payment action. See the authenticated console handler.

4. Confirm pricing before the first request

Creating a customer or project does not accept commercial terms. Modelvia records the customer’s accepted policy and effective time through an assisted process. Confirm whether usage is resold or explicitly client_funded; client-funded usage must not create a retail invoice.

For the client-paid customer flow here, missing, draft or future-only terms return customer_terms_required (409) before admission or provider dispatch. Agree and verify the effective accepted policy before enabling the workflow. Historical usage may still have an unknown customer price: null is unknown, never free.

Caps limit exposure; they are not quotes or invoices. 1 AUD = 1,000,000,000 nano-AUD. Keep these integer strings exact.

5. Issue one project key securely

List the project’s keys first. A record is metadata only: the secret cannot be recovered. Inspect environment, revokedAt and expiresAt, and serialize issuance per project/environment; a list followed by a mint is not an atomic lock.

Inspect existing key records
curl --fail-with-body \
  "$MODELVIA_API_URL/v1/client/customers/$MODELVIA_CUSTOMER_ID/projects/$MODELVIA_PROJECT_ID/keys" \
  -H "Authorization: Bearer $MODELVIA_CLIENT_KEY"

The customer, project and billing service must be active; the service must be unexpired and the environment permitted. Then mint once and move the returned key into your protected server or trusted CLI environment. Never return it to a consumer browser or application logs.

Mint once into a protected response file
set -eu
# Requires curl + jq. Use a private directory outside your repository.
# Run only after checking there is no unresolved mint for this project.
umask 077
KEY_RESPONSE=$(mktemp)
curl --fail-with-body \
  "$MODELVIA_API_URL/v1/client/customers/$MODELVIA_CUSTOMER_ID/projects/$MODELVIA_PROJECT_ID/keys" \
  -H "Authorization: Bearer $MODELVIA_CLIENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"environment":"development","label":"ExampleCo server"}' \
  -o "$KEY_RESPONSE"
# On HTTP/network error, stop and inspect key metadata. Do not rerun this POST.
# On success, move .key directly into your secret store; never print the secret.
jq '{keyId: .record.id, project: .record.project, environment: .record.environment}' "$KEY_RESPONSE"
# Treat KEY_RESPONSE as a secret file until removed after secure storage.

If a response is lost, list and reconcile the issued keys before another mutation. Minting again creates another valid secret; rotation also issues a new secret. Revocation is repeatable. See the key lifecycle reference.

6. Verify a request and its customer view

Use the separate rbk_ project key as MODELVIA_KEY for one bounded inference call and receipt. Then read customer-scoped usage and billing from your backend, checking the same signed-in customer binding and the response’s client/customer IDs where present. Configure invoice payment methods only once the seller and collection process are ready.

When setup stops

Recover without duplicating credentials or changing scope.
StateNext action
No customers yetAn empty customers array is a valid first-run state. Create one after business setup is confirmed.
Create response lostRepeat the identical customer/project body. The existing record returns 200 without a second write.
account_version_conflictThe ID already exists in your scope with different content. Compare the original request; these routes cannot edit it.
account_id_unavailableThe requested global ID is unavailable. Pick another namespaced ID; no owner details are returned.
onboarding_operator_onlyProvisioning is still closed for your client. Ask Modelvia to open it; do not retry against a different customer or project ID.
Forbidden or inactiveResolve billing ownership, active ancestry or service entitlement with Modelvia. Do not swap customer IDs to bypass the refusal.
Mint/rotation response lostPause credential issuance, list metadata, revoke or reconcile the unknown credential, then issue a replacement deliberately.

Full request fields, methods and error reference →