Integration materials generated from this source version
Identity, customers and first activation
Nexus keeps login identities, billing customers and purchased entitlements separate. The default is AUTO: create a personal billing customer on first activation or purchase, not on every login or catalog view. Creating a customer grants no assets, credits or merchant permissions. Team purchases require an explicit authorized team customer; joining a team does not create a personal billing account.
Integration sequence
- Authenticate with the configured OIDC issuer (Casdoor by default). Backend SDK
calls use a tenant service key with customer.provision and the current user's signed JWT as subjectToken / subject_token. Also use entitlement.consume for purchase-context and access checks. Keep keys on the application server.
- Call
POST /v1/customers:ensurewithtenant_id,environment_id, and
purpose: OPEN | PURCHASE. Omit customer_account_id for the user's personal account; supply it only to select an existing authorized team/customer. A caller-supplied user ID, email, issuer or subject cannot claim an account.
- Persist the returned
customer_account_idmapping in your business system.
Repeating ensure (including concurrent calls) returns the same personal account for that tenant, environment and verified user. A suspended/closed account is not replaced by a new account to escape its restriction.
- Query purchase context and resource/capability access. Show purchase or resume
checkout when appropriate. Payment and fulfillment establish entitlements.
- Immediately before business execution, call the SDK user-access guard; then
use the durable consumption SDK for reserve, provider-start, actual settlement and release. Account creation and purchase-context UX are not access receipts.
// Server only. userJwt comes from the authenticated request, not a userId field.
const nexus = new NexusClient({baseUrl: apiOrigin, apiKey: serverKey,
subjectToken: userJwt, tenantId, environmentId});
const account = await nexus.ensureCustomer({tenantId, environmentId, purpose: "PURCHASE"});
const purchase = await nexus.deliveries.getPurchaseContext({
customerAccountId: account.customerAccountId, productId
});
// At the actual protected business boundary:
await nexus.deliveries.withUserAccess({customerAccountId: account.customerAccountId,
resourceId, action: "use"}, async decision => runAuthorizedBusiness(decision));Go: EnsureCustomer, GetCustomerProvisioningPolicy, UpdateCustomerProvisioningPolicy, ImportCustomers, SyncCustomerIdentity, ListCustomerIdentityBindings. Python: ensure_customer, get_customer_provisioning_policy, update_customer_provisioning_policy, import_customers, sync_customer_identity, list_customer_identity_bindings. Java and TypeScript expose the equivalent lower-camel-case methods. Python/Java/Go use snake_case request fields. TypeScript uses camelCase and performs wire conversion. Represent 64-bit event versions as decimal strings in TypeScript/JavaScript.
Console configuration and imports
Open Customers → Activation and identity bindings (/customers/provisioning). Choose the environment at the top. GET/PUT /v1/customer-provisioning/policy reads/updates that environment's AUTO/MANUAL policy and source mappings; updates require expected_version. MANUAL keeps existing customers usable but prevents new automatic accounts. Administrative changes require customer.import; customer-bound keys cannot administer provisioning, even with wildcard scopes.
Register exact provider/issuer mappings before imports. The mappings identify binding records; they do not add JWT trust or bypass audience/signature checks. The deployed OIDC verifier still owns trust. A deployment can name its configured issuer using auth.identity_provider (default casdoor), including an OIDC provider other than Casdoor. For multiple upstream login systems, federate them through the configured identity broker, preserving stable subjects. Independent issuers are not automatically trusted by registering them in a customer's configuration. Existing SCIM/directory ingress can populate external identities; use matching provider, exact issuer and stable subject. Never match ownership by display name. Cross-provider identity merges are deliberately not inferred from equal emails.
Upload a JSON array (1–100 customers per batch; Console maximum 1 MB):
[{
"external_ref": "crm/customer-42",
"name": "Existing customer",
"account_type": "PERSONAL",
"identities": [{
"provider": "casdoor",
"issuer": "https://identity.example.com",
"subject": "stable-id-from-signed-token",
"role": "OWNER"
}]
}]Use ENTERPRISE for teams; member roles are OWNER or VIEWER. A PERSONAL identity must be OWNER. Supply customer_account_id to attach a stable external reference to an existing manually entered account. An existing reference cannot be reassigned to another account; importing does not overwrite an existing account's name/type or migrate orders. Personal identity ownership conflicts require operator review.
Send {environment_id, rows, dry_run:true} to POST /v1/customers:import first. Preview executes validations inside a rolled-back transaction: no customer, membership, mapping, event or idempotency receipt persists. Preview IDs are not usable accounts and are omitted from the HTTP response. Then send the same rows with dry_run:false and a stable idempotency_key. A batch commits atomically; errors roll it all back. Reusing a key with different input conflicts. Reimporting an existing binding does not undo newer member lifecycle state.
A known active identity binds immediately. An imported subject that has never logged in remains pending and binds only when that exact verified identity logs in or activates its account. No email is required. Registration alone never creates IAM login users, merchant memberships or purchase grants.
Member lifecycle synchronization
Use an authorized server adapter, never a browser's claimed identity event:
POST /v1/customers/{customer_account_id}/identities:sync
{
"environment_id": "<environment-id>",
"identity": {"provider":"casdoor","issuer":"https://identity.example.com",
"subject":"stable-id-from-provider","role":"VIEWER"},
"status": "REVOKED",
"external_version": "42"
}Use ACTIVE, SUSPENDED or REVOKED and a positive, monotonically increasing version per customer/identity binding. Imports establish version 1. Deliver removals and suspensions promptly; repeated equal events are idempotent, equal versions with conflicting state are rejected, and older events never restore a member. A newer explicit ACTIVE event can restore membership. Unknown identities retain their lifecycle state until verified login; revocation does not require first login.
This API manages customer membership, not the identity provider account itself. It retains customers, payments, orders, usage and financial records. Existing IAM/SCIM user-disable processing continues to reject stale login tokens. Group changes in an external directory must be translated by your server adapter to these customer member events; SCIM groups do not silently become billing customers or customer teams. Maintain a source version and reconciliation job in the adapter, query /v1/customer-provisioning/bindings with stable environment/customer filters and after pagination, and surface failed delivery rather than assuming success.
Subsequent access/consumption checks use live member and entitlement facts, including Redis version invalidation. Expiry and refund revoke applicable purchase rights; member removal blocks that team relationship without deleting independent personal purchases. Already completed usage is retained. No client cache is authorization.
Deployment and validation
Apply migration 159, then deploy API and Console with the updated SDKs. Default Casdoor deployments need no new environment variable for customer provisioning; policies and imported bindings are in the shared database for all API nodes. Other OIDC deployments retain their verifier issuer/audience/JWKS configuration. Existing products, orders and verified-email invitations remain supported.
Acceptance: no-email first activation; concurrent replay; manual policy; preview rollback; existing-account import; forged/cross-tenant/cross-environment denial; pending exact-subject binding; suspension/removal and stale event ordering; no accidental entitlements; personal/team separation; SDK transport and buyer retry. These implementation checks are distinct from production deployment and payment provider end-to-end acceptance.