OnComply

We use cookies to improve your experience and analyze site usage. Privacy Policy

Knowledge Base

Build a reliable OnComply integration

Use the supported public API surface and signed webhooks to keep vendor eligibility in sync with your systems.

Base URL

https://api.oncomply.biz

Public API

3 supported endpoints

Format

JSON, UTF-8

Timestamps

RFC 3339, UTC

Authentication

API keys for server-to-server access

An owner or admin can create a key from the API Keys page when public integration access is enabled. Keys begin with ocpk_ and are shown once. Store the value in a secrets manager and never embed it in browser or mobile code.

Send the key as X-API-Key or Authorization: Bearer <api_key>. A missing required scope is returned as 401. Revoking a key takes effect immediately.

Example request
curl "https://api.oncomply.biz/api/v1/vendors/{vendor_id}/eligibility" \
  -H "X-API-Key: $ONCOMPLY_API_KEY"

Supported scopes

eligibility:read
Read one vendor's current eligibility snapshot.
eligibility:read:bulk
Read eligibility snapshots for multiple vendor IDs.
integrations:vendors:write
Resolve, link, or start onboarding a vendor from an external system.
Eligibility API

Ask whether a vendor can work and be paid

Eligibility is a live snapshot of the same compliance state shown in OnComply. Use can_work and can_pay as explicit gates in work-order and payment workflows.

Status is pending, compliant, blocked_payment, or blocked_work. Blocking scope is none, audit, payment, or work.

next_expiration_at is the next known date-based expiration. Documents and other events can change the snapshot sooner, so use webhooks when you need prompt updates.

Where to get the vendor ID

vendor_id identifies the OnComply vendor record; it is not a user ID or your external system's vendor ID. For a matched, linked, or created resolution response, store vendor.id alongside your provider and external_id. Vendor-event webhooks include the same value as vendor_id. For vendors created in OnComply, open the vendor record in the admin app and use Copy ID beside the OnComply Vendor ID.

GET/api/v1/vendors/{vendor_id}/eligibility
Response
{
  "status": "compliant",
  "can_work": true,
  "can_pay": true,
  "blocking_scope": "none",
  "blocking_reasons": [],
  "next_expiration_at": "2026-11-02T00:00:00Z"
}
POST/api/v1/vendors/bulk-eligibility
Request
curl -X POST "https://api.oncomply.biz/api/v1/vendors/bulk-eligibility" \
  -H "X-API-Key: $ONCOMPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vendor_ids":["8f14e45f-ceea-4f31-9c70-6f1f2a2b9e01","6512bd43-d9ca-4e58-8b6f-4d1b5c7a2f88"]}'
Response
{
  "items": [
    {
      "vendor_id": "8f14e45f-ceea-4f31-9c70-6f1f2a2b9e01",
      "status": "compliant",
      "can_work": true,
      "can_pay": true,
      "blocking_scope": "none",
      "blocking_reasons": [],
      "next_expiration_at": "2026-11-02T00:00:00Z"
    },
    {
      "vendor_id": "6512bd43-d9ca-4e58-8b6f-4d1b5c7a2f88",
      "status": "blocked_payment",
      "can_work": true,
      "can_pay": false,
      "blocking_scope": "payment",
      "blocking_reasons": [
        {
          "requirement_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
          "type": "ach",
          "status": "pending",
          "scope": "payment"
        }
      ],
      "next_expiration_at": null
    }
  ]
}

Results preserve the submitted order. Unknown or out-of-workspace vendor IDs are omitted from items.

Vendor Resolution

Sync a vendor from an external system

Resolve uses a provider-qualified external ID as the durable identity. It first reuses an existing external link; when appropriate, it can link a unique existing vendor or create a new vendor and start onboarding.

Every successful match includes the current eligibility snapshot, so the same response can update your local mapping and gate the next action. Use the integrations:vendors:write scope.

POST/api/v1/integrations/vendors/resolve
Request
{
  "provider": "erp",
  "external_id": "184",
  "email": "ap@acmefabrication.com",
  "name": "Acme Fabrication",
  "legal_name": "Acme Fabrication LLC",
  "onboarding_group_id": "d2f0a7c4-9b3e-4f6a-8c1d-5e7b9a0c2d4f",
  "track_1099": true,
  "start_onboarding": true
}
Response
{
  "status": "created",
  "vendor": {
    "id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
    "email": "ap@acmefabrication.com",
    "name": "Acme Fabrication",
    "legal_name": "Acme Fabrication LLC",
    "onboarding_group_id": "d2f0a7c4-9b3e-4f6a-8c1d-5e7b9a0c2d4f",
    "status": "pending",
    "can_work": false,
    "can_pay": false,
    "external_refs": [
      { "provider": "erp", "external_id": "184" }
    ]
  },
  "eligibility": {
    "status": "pending",
    "can_work": false,
    "can_pay": false,
    "blocking_scope": "work",
    "blocking_reasons": ["..."],
    "next_expiration_at": null
  },
  "onboarding_started": true,
  "email_queued": true,
  "invite_expires_at": "2026-08-11T16:20:00Z"
}

Request guidance

provider
Required. Normalized to lowercase; use 2–32 characters beginning with a letter or number, followed by letters, numbers, underscores, or hyphens.
external_id
Required, with a maximum of 200 characters. Together with provider, this is the durable identity used on future syncs.
email, name, legal_name
Optional profile data used to find a unique existing vendor or populate a newly created vendor.
onboarding_group_id
Required when an unmatched vendor should be created and onboarding should start.
start_onboarding
When true, an unmatched vendor can be created. When false, an unmatched vendor returns 404. Vendors already invited or submitted are not automatically re-invited.
track_1099
When false, an unmatched vendor is skipped instead of entering onboarding.

Response outcomes

matched
The external reference already belongs to this vendor.
linked
A unique existing vendor was found and linked to the external reference.
created
A new vendor was created and prepared for onboarding.
skipped
No vendor was created. skipped_reason is track_1099_false when tracking is disabled or vendor_excluded when the vendor is excluded.

If no email is available, a vendor can still be created, but no invitation email is queued. Check email_queued instead of assuming one was sent.

Webhooks

Signed notifications for vendor events

An owner or admin can register an HTTPS receiver from the Webhooks page. OnComply sends a signed JSON request whenever a subscribed event occurs. The signing secret is shown once when the receiver is created; store it in a secrets manager.

Supported vendor events

vendor.compliance_changed
A vendor's eligibility status changes.
Fields: previous_status, new_status
vendor.invited
An onboarding invitation is sent or resent.
Fields: invite_expires_at, scope, resend
vendor.onboarding_completed
A vendor submits onboarding for the first time.
Fields: queued_documents, terms_version
vendor.document.uploaded
A submitted document passes upload scanning and enters processing.
Fields: document_id, requirement_id, mime_type, file_size
vendor.document.failed_validation
Automated processing cannot finish and the document enters manual review.
Fields: document_id, requirement_id, reason
vendor.expiring_soon
A passing document or requirement approaches expiration or renewal.
Fields: requirement_id, document_id, expires_at, due_at, days, due_kind

Vendor-event payloads always include event, timestamp, and vendor_id. A manual webhook.test delivery instead identifies the workspace, receiver, and delivery; it does not include a vendor ID.

Delivery headers
Content-Type: application/json
X-OnComply-Event: vendor.compliance_changed
X-OnComply-Delivery: 7f3d2a1b-9c8e-4f5a-b6d7-0e1f2a3b4c5d
X-OnComply-Signature: sha256=a1b2c3d4e5f6...
Signature verification (Node.js)
import crypto from "node:crypto";

export function verifyOnComplySignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !/^sha256=[0-9a-f]{64}$/.test(signatureHeader)) {
    return false;
  }

  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const expectedBytes = Buffer.from(expected, "utf8");
  const suppliedBytes = Buffer.from(signatureHeader, "utf8");

  return (
    suppliedBytes.length === expectedBytes.length &&
    crypto.timingSafeEqual(suppliedBytes, expectedBytes)
  );
}

Delivery and retries

Verify the signature over the exact raw request bytes, then return any 2xx response only after the event is durably accepted. Failed deliveries receive up to five total attempts, including the first attempt, with exponential delays beginning at five minutes. After the final failure the receiver is disabled and must be re-enabled in OnComply.

Delivery order is not guaranteed. Keep handlers idempotent and deduplicate on X-OnComply-Delivery. Manual test deliveries are sent once and are not retried. Receivers should respond within 10 seconds; redirects are not followed.

Payload examples

vendor.compliance_changedView JSON
Code example
{
  "event": "vendor.compliance_changed",
  "timestamp": "2026-07-28T16:20:00Z",
  "vendor_id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
  "previous_status": "pending",
  "new_status": "compliant"
}
vendor.invitedView JSON
Code example
{
  "event": "vendor.invited",
  "timestamp": "2026-07-28T16:21:00Z",
  "vendor_id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
  "invite_expires_at": "2026-07-31T16:21:00Z",
  "scope": "onboarding",
  "resend": false
}
vendor.onboarding_completedView JSON
Code example
{
  "event": "vendor.onboarding_completed",
  "timestamp": "2026-07-28T16:22:00Z",
  "vendor_id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
  "queued_documents": 2,
  "terms_version": "2026-03-01"
}
vendor.document.uploadedView JSON
Code example
{
  "event": "vendor.document.uploaded",
  "timestamp": "2026-07-28T16:22:41Z",
  "vendor_id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
  "document_id": "5c6d7e8f-2a3b-4c5d-9e0f-1a2b3c4d5e6f",
  "requirement_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "mime_type": "application/pdf",
  "file_size": 482133
}
vendor.document.failed_validationView JSON
Code example
{
  "event": "vendor.document.failed_validation",
  "timestamp": "2026-07-28T16:25:00Z",
  "vendor_id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
  "document_id": "5c6d7e8f-2a3b-4c5d-9e0f-1a2b3c4d5e6f",
  "requirement_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "reason": "manual_review"
}
vendor.expiring_soonView JSON
Code example
{
  "event": "vendor.expiring_soon",
  "timestamp": "2026-07-28T06:00:00Z",
  "vendor_id": "3b9d4a6e-1f2c-4d8b-a5e7-9c0f1a2b3c4d",
  "requirement_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "document_id": "5c6d7e8f-2a3b-4c5d-9e0f-1a2b3c4d5e6f",
  "expires_at": "2026-08-27T00:00:00Z",
  "due_at": "2026-08-27T00:00:00Z",
  "days": 30,
  "due_kind": "expiration"
}
webhook.testView JSON
Code example
{
  "event": "webhook.test",
  "timestamp": "2026-07-28T16:30:00Z",
  "tenant_id": "6d1f2e3a-4b5c-678d-9e0f-1a2b3c4d5e6f",
  "webhook_id": "8e2f3a4b-5c6d-789e-0f1a-2b3c4d5e6f7a",
  "delivery_id": "7f3d2a1b-9c8e-4f5a-b6d7-0e1f2a3b4c5d"
}
Errors & Operations

Handle failures without losing context

Error responses include an error string and may add structured context. Every response carries an X-Request-ID; include it when contacting support.

Request bodies are limited to 2 MiB. Keep the same provider and external ID when retrying vendor resolution, and design write-side processing for responses or events that may be observed more than once.

HTTP status codes returned by the public integration API
StatusMeaning
400The identifier or request body is invalid.
401The API key is missing, invalid, revoked, or lacks the required scope.
402Workspace access is locked. Contact the workspace owner or OnComply support.
403Public integration access is not enabled for the workspace.
404The vendor was not found or is outside the authenticated workspace.
409The request conflicts with an existing vendor record.
413The request body exceeds the 2 MiB limit.
5xxA server error occurred. Retry safe requests with exponential backoff.

Built-in integrations

QuickBooks Online vendor sync, MakersHub invoice intake, and SFTP document-package delivery can be configured in OnComply without custom code. Use the public endpoints above when your system needs a custom eligibility or vendor-resolution workflow.

Create your first API key

Sign in, open the API Keys page, and create a key with only the scopes your integration needs.

Sign in to get started
W-9 CollectionCOI TrackingACH AuthorizationDocument Fill & SignAutomated ValidationRenewal RemindersCan-Work / Can-Pay ControlsVendor PortalCompliance DashboardWebhook IntegrationsEligibility APIAudit-Ready ExportsLicense TrackingGrace Period ManagementCustom FormsW-9 CollectionCOI TrackingACH AuthorizationDocument Fill & SignAutomated ValidationRenewal RemindersCan-Work / Can-Pay ControlsVendor PortalCompliance DashboardWebhook IntegrationsEligibility APIAudit-Ready ExportsLicense TrackingGrace Period ManagementCustom Forms