Endpoints Reference

All endpoints are under https://onboarding-hub.com/api/v1/ and require Bearer token authentication.

For the interactive API reference with request/response schemas, see the Swagger UI.


Contacts

Manage the people you are onboarding. Contacts can be associated with organisations and enrolled in guides.

Scopes: contacts:read (read), contacts:write (write)

List contacts

GET /api/v1/contacts

Query parameters:

Parameter Type Description
page integer Page number (default: 1)
email string Filter by exact email
organisation_id uuid Filter by organisation

curl:

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  "https://onboarding-hub.com/api/v1/contacts?page=1"

Response (200):

{
  "data": [
    {
      "id": "01234567-89ab-cdef-0123-456789abcdef",
      "email": "[email protected]",
      "first_name": "Jane",
      "last_name": "Doe",
      "external_id": "cust_123",
      "organisation_id": "fedcba98-7654-3210-fedc-ba9876543210",
      "metadata": { "plan": "pro" },
      "created_at": "2026-01-15T10:30:00Z",
      "updated_at": "2026-01-15T10:30:00Z"
    }
  ]
}

Get a contact

GET /api/v1/contacts/:id

Create a contact

POST /api/v1/contacts

Body:

{
  "contact": {
    "email": "[email protected]",
    "first_name": "Jane",
    "last_name": "Doe",
    "external_id": "cust_123",
    "organisation_id": "fedcba98-7654-3210-fedc-ba9876543210",
    "metadata": { "plan": "pro" }
  }
}

curl:

curl -X POST -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"contact":{"email":"[email protected]","first_name":"Jane","last_name":"Doe"}}' \
  https://onboarding-hub.com/api/v1/contacts

Ruby:

require "net/http"
require "json"

uri = URI("https://onboarding-hub.com/api/v1/contacts")
req = Net::HTTP::Post.new(uri, {
  "Authorization" => "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type" => "application/json"
})
req.body = {
  contact: { email: "[email protected]", first_name: "Jane", last_name: "Doe" }
}.to_json

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Python:

import requests

response = requests.post(
    "https://onboarding-hub.com/api/v1/contacts",
    headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
    json={
        "contact": {
            "email": "[email protected]",
            "first_name": "Jane",
            "last_name": "Doe",
        }
    },
)
print(response.json())

JavaScript:

const response = await fetch("https://onboarding-hub.com/api/v1/contacts", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    contact: {
      email: "[email protected]",
      first_name: "Jane",
      last_name: "Doe",
    },
  }),
});
const data = await response.json();

Response (201):

{
  "data": {
    "id": "01234567-89ab-cdef-0123-456789abcdef",
    "email": "[email protected]",
    "first_name": "Jane",
    "last_name": "Doe",
    "external_id": null,
    "organisation_id": null,
    "metadata": {},
    "created_at": "2026-02-09T12:00:00Z",
    "updated_at": "2026-02-09T12:00:00Z"
  }
}

Update a contact

PATCH /api/v1/contacts/:id

Only include the fields you want to change.

Delete a contact

DELETE /api/v1/contacts/:id

Soft-deletes the contact (sets deleted_at). Returns 204 No Content.

Search contacts

GET /api/v1/contacts/search?query=jane

Searches by first name, last name, and email. Designed for Zapier's "Find Contact" action.


Organisations

Group contacts into organisations for easier management and enrollment tracking.

Scopes: organisations:read (read), organisations:write (write)

List organisations

GET /api/v1/organisations

Query parameters:

Parameter Type Description
page integer Page number (default: 1)
per_page integer Items per page (default: 25, max: 100)
name string Filter by name (partial, case-insensitive)
domain string Filter by exact domain

Get an organisation

GET /api/v1/organisations/:id

Create an organisation

POST /api/v1/organisations
{
  "organisation": {
    "name": "Acme Corp",
    "domain": "acme.com",
    "metadata": { "industry": "SaaS" }
  }
}

Update an organisation

PATCH /api/v1/organisations/:id

Delete an organisation

DELETE /api/v1/organisations/:id

Permanently deletes the organisation. Returns 204 No Content.


Enrollments

Enrollments represent a contact's assignment to a guide. Track progress, completion, and feedback.

Scopes: enrollments:read (read), enrollments:write (write)

List enrollments

GET /api/v1/enrollments

Query parameters:

Parameter Type Description
page integer Page number (default: 1)
per_page integer Items per page (default: 25, max: 100)
contact_id uuid Filter by contact
guide_id uuid Filter by guide
organisation_id uuid Filter by organisation (via contact)
status string Filter by status: invited, in_progress, completed, expired

Response (200):

{
  "data": [
    {
      "id": "...",
      "contact_id": "...",
      "guide_id": "...",
      "organisation_id": "...",
      "status": "in_progress",
      "progress_percentage": 66.7,
      "access_token": "abc123",
      "started_at": "2026-01-15T10:30:00Z",
      "completed_at": null,
      "expires_at": null,
      "metadata": {},
      "created_at": "2026-01-15T10:00:00Z",
      "updated_at": "2026-01-15T10:30:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 42,
    "total_pages": 2
  }
}

Get an enrollment

GET /api/v1/enrollments/:id

The detail view includes additional fields: progress, completed_step_ids, total_steps, days_to_completion, ces_score, nested contact and guide objects.

Create an enrollment

POST /api/v1/enrollments
{
  "enrollment": {
    "contact_id": "01234567-...",
    "guide_id": "fedcba98-...",
    "metadata": { "source": "api" }
  }
}

The access_token is auto-generated by the model.

Update an enrollment

PATCH /api/v1/enrollments/:id
{
  "enrollment": {
    "status": "completed",
    "metadata": { "completed_via": "api" }
  }
}

Delete an enrollment

DELETE /api/v1/enrollments/:id

Permanently deletes the enrollment. Returns 204 No Content.


Guides

Read-only access to published guides and their structure (sections and steps).

Scopes: guides:read

List published guides

GET /api/v1/guides

Returns only published guides. Draft and archived guides are not included.

Query parameters:

Parameter Type Description
page integer Page number (default: 1)
per_page integer Items per page (default: 25, max: 100)

Get a guide

GET /api/v1/guides/:id

Returns the full guide structure with nested sections and steps:

{
  "data": {
    "id": "...",
    "title": "Getting Started Guide",
    "description": "Welcome to our platform",
    "sections_count": 3,
    "steps_count": 12,
    "published_at": "2026-01-10T09:00:00Z",
    "created_at": "2026-01-05T14:00:00Z",
    "updated_at": "2026-01-10T09:00:00Z",
    "sections": [
      {
        "id": "...",
        "title": "Welcome",
        "position": 0,
        "steps": [
          {
            "id": "...",
            "title": "Introduction",
            "position": 0,
            "type": "simple_content"
          }
        ]
      }
    ]
  }
}

Webhook Endpoints

Manage outbound webhook subscriptions. See Webhooks for event types and payload formats.

Scopes: webhooks:manage

List webhook endpoints

GET /api/v1/webhook_endpoints

Get a webhook endpoint

GET /api/v1/webhook_endpoints/:id

Includes the 10 most recent delivery records.

Create a webhook endpoint

POST /api/v1/webhook_endpoints
{
  "webhook_endpoint": {
    "url": "https://yourapp.com/webhooks/onboardinghub",
    "events": ["enrollment.created", "enrollment.completed"],
    "description": "Production webhook"
  }
}

The signing secret is included in the response only on create. Store it securely.

Update a webhook endpoint

PATCH /api/v1/webhook_endpoints/:id

Delete a webhook endpoint

DELETE /api/v1/webhook_endpoints/:id

Send test ping

POST /api/v1/webhook_endpoints/:id/test

Sends a test ping event to the endpoint and returns the result synchronously.


Next steps