Skip to content
zublms
Documentation
Documentation/Developers
Setup requiredCompany owners, administrators and integration developers

Company API access & webhooks

Connect your company data and learning events to trusted automation with scoped tokens and signed delivery.

Download the Node.js signature verifier

Official provider references: n8n Webhook, n8n HTTP Request, Zapier webhook triggers. Generic recipes; no dedicated connector qualification.

Start in Company settings → Integrations

A service account is not a person and cannot sign into the workspace. Its authority remains bound to an active administrator. Owner suspension or permission changes stop its integrations; a current administrator must rotate the token or re-enable the webhook to renew authority. Read-only support sessions cannot change integrations.

  1. Sign in as an organisation-wide owner or administrator. Sensitive changes require a sign-in within the last five minutes.
  2. Create a named token for each trusted service. Select only required permissions and an expiry (30, 90, 180 or 365 days in the UI). Copy the credential once into the receiver’s secret store.
  3. For events, add a paused endpoint using an operator-approved public HTTPS host. Choose events, save the signing secret, send a synthetic test and inspect delivery history before enabling.
  4. Rotate or revoke tokens when needed. Rotation immediately stops the old token; update the receiver promptly. Pause webhooks to cancel pending deliveries.

Available scopes and datasets

The token grants company-wide access within those scopes. It cannot manage identities, SSO, credentials, AI secrets or platform settings. This is selected business data, not unrestricted database access or every possible export. Existing browser endpoints do not accept partner tokens.

  • people:read → people (ID, display name, suspension and learner kind; private email/profile fields excluded).
  • groups:read → teams and groups (definitions; membership export is not included).
  • catalogue:read → courses, course-versions, collections and pathways.
  • learning:read → enrolments, pathway-assignments, completions and certificates (records; PDF downloads and granular lesson/SCORM attempts are not included).
  • resources:read → resources, including resource body.
  • enrolments:write → POST enrolments to assign a published course version to an active company member.

Read company data

Choose a dataset from the list above. Default page size is 50; maximum 100. Follow nextCursor as the next cursor query parameter until absent. You can also filter by an exact UUID with id. Dataset fields use snake_case; page and assignment contracts use camelCase.

Cursors are company/dataset bound and expire after one hour. UUID ordering is stable, but pagination is not a historical snapshot: reconcile changing datasets by ID. The company is determined by the credential; an organisation query value cannot override it.

Rate limit: 120 successful requests per minute per token. On 429 wait at least 60 seconds with jitter. Usage shows successful committed requests and the last 30 UTC days, not rejected calls. Keep credentials out of URLs, public repositories and browser storage.

Integration example
GET /api/v1/partner/enrolments?limit=100
Authorization: Bearer <company-token>

{
  "items": [{"id":"enrolment-uuid","user_id":"user-uuid","state":"completed"}],
  "nextCursor": "opaque-signed-cursor"
}

Assign a course safely

Use real IDs from your company datasets and a new request UUID for a new command. Optional dueAt is an RFC3339 timestamp. Retry ambiguous failures with the same UUID and identical payload; changing the payload returns 409. An existing active assignment to a different version also conflicts. Repeated requests do not create duplicate enrolments.

401 means missing credentials; 403 means invalid/expired/revoked credentials, insufficient scope or changed owner authority; 409 is a conflict; 422 invalid input; 429 rate/cap limit; 503 unavailable service. Authentication errors require reauthorisation, not endless retries.

Integration example
POST /api/v1/partner/enrolments
Authorization: Bearer <company-token>
Content-Type: application/json

{
  "requestId": "11111111-1111-4111-8111-111111111111",
  "userId": "22222222-2222-4222-8222-222222222222",
  "courseId": "33333333-3333-4333-8333-333333333333",
  "versionId": "44444444-4444-4444-8444-444444444444"
}

Learning event catalogue

Events and subscribed deliveries are recorded in the same database transaction as the learning change. Rolled-back changes produce no delivery. Events carry IDs, not names, email or lesson text. Fetch permitted details through a scoped token. There is no automatic history backfill or ordering guarantee.

Integration example
{
  "id": "event-uuid",
  "type": "course.completed.v1",
  "organisationId": "company-uuid",
  "occurredAt": "2026-11-04T00:00:00Z",
  "data": {"resourceId": "enrolment-uuid", "userId": "user-uuid"}
}
  • enrolment.assigned.v1 — a new enrolment was inserted; resourceId identifies that enrolment.
  • course.completed.v1 — an enrolment transitioned to completed; resourceId identifies that enrolment.
  • certificate.issued.v1 — a certificate transitioned to ready; resourceId identifies the certificate.
  • integration.test.v1 — synthetic connection test; contains a message rather than real learning data.

Verify signatures before taking action

Use the exact raw body bytes and constant-time comparison. Reject timestamps more than five minutes in the past or future. After verifying, check the organisation ID and atomically deduplicate on the event ID before business effects. Never re-serialise JSON before verification.

Download the Node.js verification example at /docs-assets/integrations/verify-webhook.mjs. It validates signatures, timestamp and company; your receiver must add durable event-ID storage and processing. A duplicate should be acknowledged without repeating its action.

Rotating a signing secret adds X-ZubLMS-Previous-Signature for 24 hours so the old key can verify while receivers update. Repeated rotation replaces the previous key slot. Store secrets securely and do not log request headers or sensitive receiver URLs.

Integration example
X-ZubLMS-Event-Id: <event-uuid>
X-ZubLMS-Delivery-Id: <delivery-uuid>
X-ZubLMS-Timestamp: <unix-seconds>
X-ZubLMS-Signature: v1=<hex-hmac>

HMAC-SHA256(secret, timestamp + '.' + originalRawBody)

Delivery, retries and operational limits

Deliveries are at-least-once. A 2xx acknowledges receipt, not downstream workflow success. Requests time out after ten seconds. There are at most five attempts with 1, 2, 4 and 8-minute retry delays; queued deliveries expire after 24 hours. Most 4xx responses fail immediately; 408 and 429 retry. Redirects are not followed.

Manual redelivery creates a new delivery ID with the same event ID. Pausing cancels queued deliveries; an in-flight request may finish first. The latest 100 deliveries appear in the UI; terminal delivery/event history is retained for 30 days. History shows attempt count and latest response code, not raw response bodies.

To change a destination or event selection, create and test a replacement endpoint, then pause the old one. Pending deliveries never silently move to another URL. Limits are 100 named accounts and 50 endpoints per company; disabled records retain audit history and count toward these limits. Contact the operator for archival/capacity planning.

n8n and Zapier recipes

n8n documents HTTP Request and Webhook nodes, with distinct test/production webhook URLs. Zapier Catch Raw Hook includes the unparsed body and headers. Provider plans and runtime limits apply. These are generic HTTP recipes; dedicated connectors and real-account workflow compatibility are not yet qualified.

  1. For pulling data, use an HTTP Request/API action with the company token in a protected credential store. Follow nextCursor pagination.
  2. For inbound events, use a raw-body webhook receiver. Verify signature, age and company before actions, then persist event-ID deduplication. If your automation runtime cannot safely perform verification or protect secrets, place a controlled verification gateway ahead of it.
  3. Course-completed example: verify/deduplicate → GET enrolments?id=<resourceId> → update the matching learning status in your CRM. Certificate-issued: fetch the certificate record and update evidence status.
  4. Test duplicate events, tampering, stale timestamps, revoked credentials, rate limits and downtime before enabling customer data.

Installation setup and recovery

The operator supplies a private 0600 file containing 32 random bytes hex encoded, a working OpenBao Transit service and the ordinary worker. Keep the pepper stable across restarts/releases; replacing it invalidates every token and cursor. API and worker need the same approved destination host list. Container processes must mount the file and use its container path.

Destinations require HTTPS port 443 and exact approved hosts. URL credentials/fragments, private/loopback/link-local addresses, environment proxies and redirects are rejected. Local/private n8n URLs are not accepted. No new endpoint is automatically enabled or contacted by setup.

Restore invalidates existing tokens and owner authority epochs. Explicit administrator reauthorisation is needed before integrations resume. This does not complete the separately deferred auto-unseal or off-server backup work.

Integration example
INTEGRATION_TOKEN_PEPPER_FILE=/run/secrets/integration-token-pepper
INTEGRATION_WEBHOOK_HOSTS=hooks.zapier.com,automation.your-company.example

Documentation reviewed 4 November 2026 · Current implementation snapshot

Need account help? Contact your company administrator. Planning a rollout? Talk to us.