/pingVerify API key and connectivityResponses
| Status | Description | Body |
|---|---|---|
| 200 | OK | { ok: boolean, tenantId: string (uuid), timestamp: string (date-time) } |
| 401 | Error | Error |
| 403 | Error | Error |
| 429 | Too Many Requests | RateLimitError |
| 500 | Error | Error |
OneBookPlus Public API · v1.0.0
Every endpoint on this page is rendered from the same OpenAPI 3.1 document the API itself serves, so the reference can't drift from the implementation. The stable v1 surface covers contacts, invoices, quotes and bookings; breaking changes only ship under the v2 preview.
All v1 requests are made against a single base URL. Authentication uses a bearer API key issued from your dashboard (Settings → API keys); keys are scoped to one business account with read or read-write permissions. API access requires developer-access approval on your account.
API keys issued from /dashboard/settings/api-keys. Format: `obp_live_<random>` (prefix `obp_`). Send as `Authorization: Bearer obp_...`.
A v2 preview of the same surface is served under /api/v2 (spec at /api/v2/openapi.json) — identical today, and the only place breaking changes will land.
curl https://onebookplus.com.au/api/v1/ping \
-H "Authorization: Bearer obp_..."
# Base URL: https://onebookplus.com.au/api/v1
# Keys are issued at /dashboard/settings/api-keysList endpoints return { data, next_cursor }. Pass ?cursor= to fetch the next page; next_cursor is null when exhausted. limit accepts 1–200 (default 50), and updated_since filters by ISO 8601 timestamp for incremental syncs.
Failures return a JSON body of { error } with an optional field naming the failing validator on 400s. Statuses used: 400, 401, 403, 404, 409, 415, 429 and 500 (see the Error schema).
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. The default limit is 60 requests per minute per API key, with tighter per-endpoint caps on write operations; 429 responses include Retry-After.
25 operations across 7 resource groups.
Ping & diagnostic endpoints.
/pingVerify API key and connectivity| Status | Description | Body |
|---|---|---|
| 200 | OK | { ok: boolean, tenantId: string (uuid), timestamp: string (date-time) } |
| 401 | Error | Error |
| 403 | Error | Error |
| 429 | Too Many Requests | RateLimitError |
| 500 | Error | Error |
/contactsList contacts| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Max rows to return (1-200). Min: 1. Max: 200. Default: 50. |
| cursor | query | string (uuid) | No | Opaque UUID cursor from a previous response's next_cursor. |
| updated_since | query | string (date-time) | No | Only return rows with updated_at >= this ISO 8601 timestamp. |
| query | string (email) | No | Exact (case-insensitive) email match. Powers Find Contact. |
/contactsCreate a contact| Field | Type | Required | Description |
|---|---|---|---|
| string (email) | Yes | — | |
| first_name | string | null | No | — |
| last_name | string | null | No | — |
| phone | string | null | No | — |
| company_name | string | null | No | — |
| city | string | null | No | — |
| state | string | null | No | — |
| postcode | string | null | No | — |
/contacts/{id}Get a contact| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
/contacts/{id}Update a contact| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| string | null (email) | No | — | |
| first_name | string | null | No | — |
| last_name | string | null | No | — |
| phone | string | null | No | — |
| company_name | string | null | No | — |
| city | string | null | No | — |
| state | string | null | No | — |
| postcode | string | null | No | — |
/contacts/{id}Soft-delete a contact| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
/invoicesList invoices| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Max rows to return (1-200). Min: 1. Max: 200. Default: 50. |
| cursor | query | string (uuid) | No | Opaque UUID cursor from a previous response's next_cursor. |
| updated_since | query | string (date-time) | No | Only return rows with updated_at >= this ISO 8601 timestamp. |
| status | query | string | No | Only return invoices with this status (e.g. paid). One of: draft, sent, viewed, partial, paid, overdue, cancelled. |
| number | query | string | No | Exact invoice_number match. Powers Find Invoice. |
/invoices/{id}Get an invoice| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
/bookingsList bookings| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Max rows to return (1-200). Min: 1. Max: 200. Default: 50. |
| cursor | query | string (uuid) | No | Opaque UUID cursor from a previous response's next_cursor. |
| updated_since | query | string (date-time) | No | Only return rows with updated_at >= this ISO 8601 timestamp. |
/bookingsCreate a booking| Field | Type | Required | Description |
|---|---|---|---|
| contact_id | string (uuid) | Yes | — |
| service_name | string | Yes | — |
| start_time | string (date-time) | Yes | — |
| end_time | string | null (date-time) | No | Defaults to start_time + 60 minutes if omitted. |
| notes | string | null | No | — |
/bookings/{id}Get a booking| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
/bookings/{id}Update a booking| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | No | One of: cancelled, confirmed, completed, no_show. |
| notes | string | null | No | — |
| start_time | string (date-time) | No | — |
| end_time | string (date-time) | No | — |
/quotesList quotes| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Max rows to return (1-200). Min: 1. Max: 200. Default: 50. |
| cursor | query | string (uuid) | No | Opaque UUID cursor from a previous response's next_cursor. |
| updated_since | query | string (date-time) | No | Only return rows with updated_at >= this ISO 8601 timestamp. |
| status | query | string | No | Only return quotes with this status (e.g. accepted). One of: draft, sent, viewed, accepted, declined, expired, converted. |
/quotesCreate a quote| Field | Type | Required | Description |
|---|---|---|---|
| contact_id | string (uuid) | Yes | — |
| total | number | Yes | Min: 0. |
| currency | string | null | No | 3-letter ISO 4217 code. Defaults to AUD. Pattern: ^[A-Z]{3}$ |
| valid_until | string | null (date-time) | No | Defaults to 30 days from today. |
| line_items | array of object | No | Accepted for forward compatibility but currently ignored server-side — the canonical line-item table is not reconciled from API writes yet. |
/quotes/{id}Get a quote| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
/quotes/{id}Update a quote| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | No | One of: draft, sent, viewed, accepted, declined, expired, converted. |
| total | number | No | Min: 0. |
| valid_until | string (date-time) | No | — |
/jobsList jobs| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Max rows to return (1-200). Min: 1. Max: 200. Default: 50. |
| cursor | query | string (uuid) | No | Opaque UUID cursor from a previous response's next_cursor. |
| updated_since | query | string (date-time) | No | Only return rows with updated_at >= this ISO 8601 timestamp. |
| status | query | string | No | Only return jobs with this status (e.g. completed). One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled. |
| job_number | query | string | No | Exact job_number match. Powers Find Job. |
/jobsCreate a job| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | — |
| contact_id | string | null (uuid) | No | — |
| job_type | string | null | No | — |
| priority | string | null | No | — |
| status | string | No | Defaults to quoted. One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled. |
| scheduled_start | string | null (date-time) | No | — |
| scheduled_end | string | null (date-time) | No | — |
| site_address | string | null | No | — |
| site_suburb | string | null | No | — |
| site_state | string | null | No | — |
| site_postcode | string | null | No | — |
| estimated_total | number | null | No | Min: 0. |
/jobs/{id}Get a job| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
/jobs/{id}Update a job| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | No | — |
| status | string | No | One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled. |
| job_type | string | null | No | — |
| priority | string | null | No | — |
| scheduled_start | string | null (date-time) | No | — |
| scheduled_end | string | null (date-time) | No | — |
| estimated_total | number | null | No | Min: 0. |
| actual_total | number | null | No | Min: 0. |
Subscribe to events (invoice.paid, quote.accepted, booking.created, contact.created, …). Deliveries are POSTed to your URL, signed with HMAC-SHA256 in the X-OBP-Signature header using the secret returned once at creation. Powers the Zapier integration's instant triggers.
/webhooksList webhook subscriptions| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Max rows to return (1-200). Min: 1. Max: 200. Default: 50. |
| cursor | query | string (uuid) | No | Opaque UUID cursor from a previous response's next_cursor. |
| updated_since | query | string (date-time) | No | Only return rows with updated_at >= this ISO 8601 timestamp. |
| Status | Description | Body |
|---|---|---|
| 200 | OK | { data: array of WebhookSubscription, next_cursor: string | null (uuid) } |
| 400 | Error | Error |
| 401 | Error | Error |
| 403 | Error | Error |
| 404 | Error | Error |
| 409 | Error | Error |
| 415 | Error | Error |
| 429 | Too Many Requests | RateLimitError |
| 500 | Error | Error |
/webhooksCreate a webhook subscription| Field | Type | Required | Description |
|---|---|---|---|
| url | string (uri) | Yes | HTTPS URL to POST deliveries to. Must be a public host. |
| events | array of string | Yes | Events to subscribe to. Use ["*"] for all events. |
| description | string | null | No | — |
| Status | Description | Body |
|---|---|---|
| 201 | Created | { data: WebhookSubscriptionWithSecret } |
| 400 | Error | Error |
| 401 | Error | Error |
| 403 | Error | Error |
| 404 | Error | Error |
| 409 | Error | Error |
| 415 | Error | Error |
| 429 | Too Many Requests | RateLimitError |
| 500 | Error | Error |
/webhooks/{id}Get a webhook subscription| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
| Status | Description | Body |
|---|---|---|
| 200 | OK | { data: WebhookSubscription } |
| 400 | Error | Error |
| 401 | Error | Error |
| 403 | Error | Error |
| 404 | Error | Error |
| 409 | Error | Error |
| 415 | Error | Error |
| 429 | Too Many Requests | RateLimitError |
| 500 | Error | Error |
/webhooks/{id}Update a webhook subscription| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| url | string (uri) | No | — |
| events | array of string | No | — |
| enabled | boolean | No | — |
| description | string | null | No | — |
| Status | Description | Body |
|---|---|---|
| 200 | OK | { data: WebhookSubscription } |
| 400 | Error | Error |
| 401 | Error | Error |
| 403 | Error | Error |
| 404 | Error | Error |
| 409 | Error | Error |
| 415 | Error | Error |
| 429 | Too Many Requests | RateLimitError |
| 500 | Error | Error |
/webhooks/{id}Delete a webhook subscription (unsubscribe)| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes | — |
The 19 object models referenced by request and response bodies above.
| Field | Type | Required | Description |
|---|---|---|---|
| error | string | Yes | — |
| field | string | No | Field name when a validator fails (400 responses). |
| Field | Type | Required | Description |
|---|---|---|---|
| error | string | Yes | — |
| retry_after_ms | integer | No | Min: 0. |
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | — |
| string | null (email) | No | — | |
| first_name | string | null | No | — |
| last_name | string | null | No | — |
| phone | string | null | No | — |
| company_name | string | null | No | — |
| city | string | null | No | — |
| state | string | null | No | — |
| postcode | string | null | No | — |
| created_at | string (date-time) | Yes | — |
| updated_at | string (date-time) | Yes | — |
| Field | Type | Required | Description |
|---|---|---|---|
| string (email) | Yes | — | |
| first_name | string | null | No | — |
| last_name | string | null | No | — |
| phone | string | null | No | — |
| company_name | string | null | No | — |
| city | string | null | No | — |
| state | string | null | No | — |
| postcode | string | null | No | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| string | null (email) | No | — | |
| first_name | string | null | No | — |
| last_name | string | null | No | — |
| phone | string | null | No | — |
| company_name | string | null | No | — |
| city | string | null | No | — |
| state | string | null | No | — |
| postcode | string | null | No | — |
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | — |
| invoice_number | string | Yes | — |
| contact_id | string | null (uuid) | No | — |
| status | string | Yes | — |
| issue_date | string | null (date) | No | — |
| due_date | string | null (date) | No | — |
| total | number | Yes | — |
| currency | string | Yes | Exactly 3 characters. |
| paid_at | string | null (date-time) | No | — |
| created_at | string (date-time) | Yes | — |
| updated_at | string (date-time) | Yes | — |
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | — |
| contact_id | string | null (uuid) | No | — |
| service_name | string | null | No | — |
| start_time | string (date-time) | Yes | — |
| end_time | string (date-time) | Yes | — |
| status | string | Yes | One of: cancelled, confirmed, completed, no_show. |
| notes | string | null | No | — |
| created_at | string (date-time) | Yes | — |
| updated_at | string (date-time) | Yes | — |
| Field | Type | Required | Description |
|---|---|---|---|
| contact_id | string (uuid) | Yes | — |
| service_name | string | Yes | — |
| start_time | string (date-time) | Yes | — |
| end_time | string | null (date-time) | No | Defaults to start_time + 60 minutes if omitted. |
| notes | string | null | No | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | No | One of: cancelled, confirmed, completed, no_show. |
| notes | string | null | No | — |
| start_time | string (date-time) | No | — |
| end_time | string (date-time) | No | — |
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | — |
| quote_number | string | Yes | — |
| contact_id | string | null (uuid) | No | — |
| status | string | Yes | One of: draft, sent, viewed, accepted, declined, expired, converted. |
| issue_date | string | null (date) | No | — |
| valid_until | string | null (date) | No | — |
| total | number | Yes | — |
| currency | string | Yes | Exactly 3 characters. |
| created_at | string (date-time) | Yes | — |
| updated_at | string (date-time) | Yes | — |
| Field | Type | Required | Description |
|---|---|---|---|
| contact_id | string (uuid) | Yes | — |
| total | number | Yes | Min: 0. |
| currency | string | null | No | 3-letter ISO 4217 code. Defaults to AUD. Pattern: ^[A-Z]{3}$ |
| valid_until | string | null (date-time) | No | Defaults to 30 days from today. |
| line_items | array of object | No | Accepted for forward compatibility but currently ignored server-side — the canonical line-item table is not reconciled from API writes yet. |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | No | One of: draft, sent, viewed, accepted, declined, expired, converted. |
| total | number | No | Min: 0. |
| valid_until | string (date-time) | No | — |
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | — |
| job_number | string | Yes | — |
| title | string | Yes | — |
| status | string | Yes | One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled. |
| job_type | string | null | No | — |
| priority | string | null | No | — |
| contact_id | string | null (uuid) | No | — |
| customer_name | string | null | No | — |
| customer_email | string | null | No | — |
| customer_phone | string | null | No | — |
| site_address | string | null | No | — |
| site_suburb | string | null | No | — |
| site_state | string | null | No | — |
| site_postcode | string | null | No | — |
| scheduled_start | string | null (date-time) | No | — |
| scheduled_end | string | null (date-time) | No | — |
| actual_start | string | null (date-time) | No | — |
| actual_end | string | null (date-time) | No | — |
| estimated_total | number | null | No | — |
| actual_total | number | null | No | — |
| quote_id | string | null (uuid) | No | — |
| invoice_id | string | null (uuid) | No | — |
| created_at | string (date-time) | Yes | — |
| updated_at | string (date-time) | Yes | — |
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | — |
| contact_id | string | null (uuid) | No | — |
| job_type | string | null | No | — |
| priority | string | null | No | — |
| status | string | No | Defaults to quoted. One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled. |
| scheduled_start | string | null (date-time) | No | — |
| scheduled_end | string | null (date-time) | No | — |
| site_address | string | null | No | — |
| site_suburb | string | null | No | — |
| site_state | string | null | No | — |
| site_postcode | string | null | No | — |
| estimated_total | number | null | No | Min: 0. |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | No | — |
| status | string | No | One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled. |
| job_type | string | null | No | — |
| priority | string | null | No | — |
| scheduled_start | string | null (date-time) | No | — |
| scheduled_end | string | null (date-time) | No | — |
| estimated_total | number | null | No | Min: 0. |
| actual_total | number | null | No | Min: 0. |
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (uuid) | Yes | — |
| url | string (uri) | Yes | — |
| events | array of string | Yes | ["*"] means all events. |
| enabled | boolean | Yes | — |
| description | string | null | No | — |
| created_at | string (date-time) | Yes | — |
| last_delivery_at | string | null (date-time) | No | — |
| last_delivery_status | integer | null | No | HTTP status of the most recent delivery (0/-1 for network/SSRF failures). |
object
| Field | Type | Required | Description |
|---|---|---|---|
| url | string (uri) | Yes | HTTPS URL to POST deliveries to. Must be a public host. |
| events | array of string | Yes | Events to subscribe to. Use ["*"] for all events. |
| description | string | null | No | — |
At least one field must be supplied.
| Field | Type | Required | Description |
|---|---|---|---|
| url | string (uri) | No | — |
| events | array of string | No | — |
| enabled | boolean | No | — |
| description | string | null | No | — |
API keys are created in the dashboard under Settings → API keys and require developer-access approval. Webhooks, key scopes and delivery logs are covered on the developer overview.