https://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: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
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
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
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: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
201 with the endpoint and its signing secret exactly once (secret,
never retrievable again — store it now):
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:
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 ausage.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).
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.