Skip to main content
The OEM Partner API lets an embedding partner provision and operate the VisIQ sub-tenant organizations inside their own product, entirely programmatically. It is the machine surface behind the OEM engagement model: create a governed tenant per end customer, read reconciliation-grade usage, manage keys / entitlement / branding, and offboard cleanly. Base URLhttps://api.visiqlabs.com/v1/partners/oem
Every response carries the header X-VisIQ-Partner-Api-Version: 2026-07-11. See versioning & deprecation for the compatibility contract. To exercise the whole flow without touching billing, use a test-mode key — see the sandbox guide.

Authentication

Authenticate every request with your partner provisioning key as a bearer token:
A provisioning key (vqp_…) is not a vendor API key and never authenticates the governance data plane. It is scoped to oem:provision, tied to your active OEM partner account, and carries a mode (live or test). Keys are stored hashed at rest and shown once at mint time. Failures are fail-closed and give no oracle: Rate-limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After) accompany throttled responses.

Provisioning

Create a sub-tenant

Returns 201 with the new tenant id and the sub-tenant’s operational harness API key once (apiKey, never retrievable again). externalRef is echoed back for your bookkeeping. A duplicate company name (per partner, per mode) returns 409 tenant_exists; the per-partner tenant cap returns 409 tenant_cap_reached.

List sub-tenants

Returns your sub-tenants (mode-scoped) with lifecycle status (active · suspended · closed).

Usage & reconciliation

Usage is counted with the same rules the royalty statement generator uses (governed action and retrieval audit events), valued at your current contract-year list snapshot when present, else the platform list rate.
period accepts YYYY-MM or YYYY-Qn, or pass an explicit start & end ISO pair (window bounded to 400 days). The aggregate response also reports your commit-pool drawdown state:

Statements

The JSON is the machine-readable contract. The CSV is a flat per-tenant export with the header row:
one row per sub-tenant plus a final TOTAL row (whose royalty_cents is the statement’s metered royalty). All statement money fields — in both the JSON and the CSV — are integer cents.

Lifecycle

suspend reversibly blocks the sub-tenant’s traffic; resume clears it. close is terminal (Twilio suspend → close → purge pattern): it stamps closedAt, sets a 30-day purgeAfter grace window, and suspends the tenant if it was not already. Any action on a closed tenant — and any create against it (keys, simulated usage) — returns 409 tenant_closed. After the grace window a nightly reaper hard-deletes the sub-tenant and its audit rows.

Offboarding export

Extract the governance evidence before purge:
Streams newline-delimited JSON (application/x-ndjson): a tenant metadata line (first page only), then allow_audit and recall_audit rows in stable id order. Follow the X-VisIQ-Export-Cursor response header until it is empty. Page cap is 10,000 rows.

Sub-tenant keys

Entitlement & branding

plan is applied to the sub-tenant’s subscription (is_unlimited only for enterprise). Caps are v1-informational — surfaced and enforced via the partner usage-threshold engine, not hard-blocked at ingest. Branding displayName is rendered on end-user-visible HITL approval prompts (Slack today; email/Teams white-labeling is on the roadmap). GET variants return the current object.

Webhooks

Subscribe an HTTPS endpoint to receive signed events. The subscribable event types are: sub_tenant.created · sub_tenant.suspended · sub_tenant.resumed · sub_tenant.closed · entitlement.changed · usage.threshold_crossed · royalty_statement.ready · wholesale_invoice.finalized · claim.accepted.

Configuring webhooks

Register an endpoint:
Returns 201 with the endpoint and its signing secret exactly once (secret, never retrievable again — store it now):
The url must be a public HTTPS endpoint. It is validated both structurally and by DNS resolution at registration and again at every delivery: a non-HTTPS URL, a private/loopback/link-local/metadata host, or a name that resolves to such an address is rejected (400) — an SSRF safeguard, and deliveries pin the connection to the vetted address. PATCH accepts status (active | disabled) and/or events; re-enabling clears the failure streak. Up to 5 endpoints per partner (409 endpoint_cap_reached beyond that). A ping is a system event (type ping, not subscribable) delivered on demand to one endpoint.

Verifying deliveries

Each delivery carries: The JSON body is the envelope { id, type, created, data }. Verify by recomputing the HMAC over the signed payload "<t>.<raw_body>" with your endpoint’s signing secret, in constant time, and rejecting timestamps outside a small tolerance:
Deliveries retry with exponential backoff (1m, 5m, 30m, 2h, 12h) and dead-letter after the schedule is exhausted. An endpoint that accumulates 20 consecutive delivery failures is auto-disabled (re-enable it with a PATCH).

Usage thresholds

Register usage triggers that fire a usage.threshold_crossed webhook the first time a metric crosses the threshold within a period (a fire-once-per-period latch — each period, e.g. 2026-07 or 2026-Q3, fires at most once and then re-arms for the next period).
A pinned vendorId must be one of your own (mode-scoped) sub-tenants, else 404. Up to 50 thresholds per partner (409 threshold_cap_reached beyond that). GET echoes each trigger’s lastFiredPeriod so you can see when it last latched.