Skip to main content
Skip to content
Pricing
Try a live demo, it's freeBook a DemoSign InStart free

OneBookPlus Public API · v1.0.0

API Reference

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.

Base URL & authentication

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.

Request template
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-keys

Conventions: pagination, errors, rate limits

Cursor pagination

List endpoints return { data, next_cursor }. Pass ?cursor= to fetch the next page; next_cursor is null when exhausted. limit accepts 1 to 200 (default 50), and updated_since filters by ISO 8601 timestamp for incremental syncs.

Errors

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).

Rate limits

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.

Endpoints

25 operations across 7 resource groups.

Meta

Ping & diagnostic endpoints.

GET/pingVerify API key and connectivity

Responses

StatusDescriptionBody
200OK{ ok: boolean, tenantId: string (uuid), timestamp: string (date-time) }
401ErrorError
403ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Contacts

GET/contactsList contacts

Parameters

NameInTypeRequiredDescription
limitqueryintegerNoMax rows to return (1-200). Min: 1. Max: 200. Default: 50.
cursorquerystring (uuid)NoOpaque UUID cursor from a previous response's next_cursor.
updated_sincequerystring (date-time)NoOnly return rows with updated_at >= this ISO 8601 timestamp.
emailquerystring (email)NoExact (case-insensitive) email match. Powers Find Contact.

Responses

StatusDescriptionBody
200OK{ data: array of Contact, next_cursor: string | null (uuid) }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
POST/contactsCreate a contact

Request body (application/json, ContactCreate)

FieldTypeRequiredDescription
emailstring (email)Yesn/a
first_namestring | nullNon/a
last_namestring | nullNon/a
phonestring | nullNon/a
company_namestring | nullNon/a
citystring | nullNon/a
statestring | nullNon/a
postcodestring | nullNon/a

Responses

StatusDescriptionBody
201Created{ data: Contact }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
PATCH/contacts/{id}Update a contact

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Request body (application/json, ContactUpdate)

At least one field must be supplied.

FieldTypeRequiredDescription
emailstring | null (email)Non/a
first_namestring | nullNon/a
last_namestring | nullNon/a
phonestring | nullNon/a
company_namestring | nullNon/a
citystring | nullNon/a
statestring | nullNon/a
postcodestring | nullNon/a

Responses

StatusDescriptionBody
200OK{ data: Contact }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
DELETE/contacts/{id}Soft-delete a contact

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Responses

StatusDescriptionBody
204No Content (soft-deleted).n/a
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Invoices

GET/invoicesList invoices

Parameters

NameInTypeRequiredDescription
limitqueryintegerNoMax rows to return (1-200). Min: 1. Max: 200. Default: 50.
cursorquerystring (uuid)NoOpaque UUID cursor from a previous response's next_cursor.
updated_sincequerystring (date-time)NoOnly return rows with updated_at >= this ISO 8601 timestamp.
statusquerystringNoOnly return invoices with this status (e.g. paid). One of: draft, sent, viewed, partial, paid, overdue, cancelled.
numberquerystringNoExact invoice_number match. Powers Find Invoice.

Responses

StatusDescriptionBody
200OK{ data: array of Invoice, next_cursor: string | null (uuid) }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Bookings

GET/bookingsList bookings

Parameters

NameInTypeRequiredDescription
limitqueryintegerNoMax rows to return (1-200). Min: 1. Max: 200. Default: 50.
cursorquerystring (uuid)NoOpaque UUID cursor from a previous response's next_cursor.
updated_sincequerystring (date-time)NoOnly return rows with updated_at >= this ISO 8601 timestamp.

Responses

StatusDescriptionBody
200OK{ data: array of Booking, next_cursor: string | null (uuid) }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
POST/bookingsCreate a booking

Request body (application/json, BookingCreate)

FieldTypeRequiredDescription
contact_idstring (uuid)Yesn/a
service_namestringYesn/a
start_timestring (date-time)Yesn/a
end_timestring | null (date-time)NoDefaults to start_time + 60 minutes if omitted.
notesstring | nullNon/a

Responses

StatusDescriptionBody
201Created{ data: Booking }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
PATCH/bookings/{id}Update a booking

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Request body (application/json, BookingUpdate)

At least one field must be supplied.

FieldTypeRequiredDescription
statusstringNoOne of: cancelled, confirmed, completed, no_show.
notesstring | nullNon/a
start_timestring (date-time)Non/a
end_timestring (date-time)Non/a

Responses

StatusDescriptionBody
200OK{ data: Booking }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Quotes

GET/quotesList quotes

Parameters

NameInTypeRequiredDescription
limitqueryintegerNoMax rows to return (1-200). Min: 1. Max: 200. Default: 50.
cursorquerystring (uuid)NoOpaque UUID cursor from a previous response's next_cursor.
updated_sincequerystring (date-time)NoOnly return rows with updated_at >= this ISO 8601 timestamp.
statusquerystringNoOnly return quotes with this status (e.g. accepted). One of: draft, sent, viewed, accepted, declined, expired, converted.

Responses

StatusDescriptionBody
200OK{ data: array of Quote, next_cursor: string | null (uuid) }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
POST/quotesCreate a quote

Request body (application/json, QuoteCreate)

FieldTypeRequiredDescription
contact_idstring (uuid)Yesn/a
totalnumberYesMin: 0.
currencystring | nullNo3-letter ISO 4217 code. Defaults to AUD. Pattern: ^[A-Z]{3}$
valid_untilstring | null (date-time)NoDefaults to 30 days from today.
line_itemsarray of objectNoAccepted for forward compatibility but currently ignored server-side — the canonical line-item table is not reconciled from API writes yet.

Responses

StatusDescriptionBody
201Created{ data: Quote }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
PATCH/quotes/{id}Update a quote

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Request body (application/json, QuoteUpdate)

At least one field must be supplied.

FieldTypeRequiredDescription
statusstringNoOne of: draft, sent, viewed, accepted, declined, expired, converted.
totalnumberNoMin: 0.
valid_untilstring (date-time)Non/a

Responses

StatusDescriptionBody
200OK{ data: Quote }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Jobs

GET/jobsList jobs

Parameters

NameInTypeRequiredDescription
limitqueryintegerNoMax rows to return (1-200). Min: 1. Max: 200. Default: 50.
cursorquerystring (uuid)NoOpaque UUID cursor from a previous response's next_cursor.
updated_sincequerystring (date-time)NoOnly return rows with updated_at >= this ISO 8601 timestamp.
statusquerystringNoOnly return jobs with this status (e.g. completed). One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled.
job_numberquerystringNoExact job_number match. Powers Find Job.

Responses

StatusDescriptionBody
200OK{ data: array of Job, next_cursor: string | null (uuid) }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
POST/jobsCreate a job

Request body (application/json, JobCreate)

FieldTypeRequiredDescription
titlestringYesn/a
contact_idstring | null (uuid)Non/a
job_typestring | nullNon/a
prioritystring | nullNon/a
statusstringNoDefaults to quoted. One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled.
scheduled_startstring | null (date-time)Non/a
scheduled_endstring | null (date-time)Non/a
site_addressstring | nullNon/a
site_suburbstring | nullNon/a
site_statestring | nullNon/a
site_postcodestring | nullNon/a
estimated_totalnumber | nullNoMin: 0.

Responses

StatusDescriptionBody
201Created{ data: Job }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
PATCH/jobs/{id}Update a job

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Request body (application/json, JobUpdate)

At least one field must be supplied.

FieldTypeRequiredDescription
titlestringNon/a
statusstringNoOne of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled.
job_typestring | nullNon/a
prioritystring | nullNon/a
scheduled_startstring | null (date-time)Non/a
scheduled_endstring | null (date-time)Non/a
estimated_totalnumber | nullNoMin: 0.
actual_totalnumber | nullNoMin: 0.

Responses

StatusDescriptionBody
200OK{ data: Job }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Webhooks

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.

GET/webhooksList webhook subscriptions

Parameters

NameInTypeRequiredDescription
limitqueryintegerNoMax rows to return (1-200). Min: 1. Max: 200. Default: 50.
cursorquerystring (uuid)NoOpaque UUID cursor from a previous response's next_cursor.
updated_sincequerystring (date-time)NoOnly return rows with updated_at >= this ISO 8601 timestamp.

Responses

StatusDescriptionBody
200OK{ data: array of WebhookSubscription, next_cursor: string | null (uuid) }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
POST/webhooksCreate a webhook subscription

Request body (application/json, WebhookCreate)

FieldTypeRequiredDescription
urlstring (uri)YesHTTPS URL to POST deliveries to. Must be a public host.
eventsarray of stringYesEvents to subscribe to. Use ["*"] for all events.
descriptionstring | nullNon/a

Responses

StatusDescriptionBody
201Created{ data: WebhookSubscriptionWithSecret }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
PATCH/webhooks/{id}Update a webhook subscription

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Request body (application/json, WebhookUpdate)

At least one field must be supplied.

FieldTypeRequiredDescription
urlstring (uri)Non/a
eventsarray of stringNon/a
enabledbooleanNon/a
descriptionstring | nullNon/a

Responses

StatusDescriptionBody
200OK{ data: WebhookSubscription }
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError
DELETE/webhooks/{id}Delete a webhook subscription (unsubscribe)

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yesn/a

Responses

StatusDescriptionBody
204No Content (soft-deleted).n/a
400ErrorError
401ErrorError
403ErrorError
404ErrorError
409ErrorError
415ErrorError
429Too Many RequestsRateLimitError
500ErrorError

Object schemas

The 19 object models referenced by request and response bodies above.

Error

FieldTypeRequiredDescription
errorstringYesn/a
fieldstringNoField name when a validator fails (400 responses).

RateLimitError

FieldTypeRequiredDescription
errorstringYesn/a
retry_after_msintegerNoMin: 0.

Contact

FieldTypeRequiredDescription
idstring (uuid)Yesn/a
emailstring | null (email)Non/a
first_namestring | nullNon/a
last_namestring | nullNon/a
phonestring | nullNon/a
company_namestring | nullNon/a
citystring | nullNon/a
statestring | nullNon/a
postcodestring | nullNon/a
created_atstring (date-time)Yesn/a
updated_atstring (date-time)Yesn/a

ContactCreate

FieldTypeRequiredDescription
emailstring (email)Yesn/a
first_namestring | nullNon/a
last_namestring | nullNon/a
phonestring | nullNon/a
company_namestring | nullNon/a
citystring | nullNon/a
statestring | nullNon/a
postcodestring | nullNon/a

ContactUpdate

At least one field must be supplied.

FieldTypeRequiredDescription
emailstring | null (email)Non/a
first_namestring | nullNon/a
last_namestring | nullNon/a
phonestring | nullNon/a
company_namestring | nullNon/a
citystring | nullNon/a
statestring | nullNon/a
postcodestring | nullNon/a

Invoice

FieldTypeRequiredDescription
idstring (uuid)Yesn/a
invoice_numberstringYesn/a
contact_idstring | null (uuid)Non/a
statusstringYesn/a
issue_datestring | null (date)Non/a
due_datestring | null (date)Non/a
totalnumberYesn/a
currencystringYesExactly 3 characters.
paid_atstring | null (date-time)Non/a
created_atstring (date-time)Yesn/a
updated_atstring (date-time)Yesn/a

Booking

FieldTypeRequiredDescription
idstring (uuid)Yesn/a
contact_idstring | null (uuid)Non/a
service_namestring | nullNon/a
start_timestring (date-time)Yesn/a
end_timestring (date-time)Yesn/a
statusstringYesOne of: cancelled, confirmed, completed, no_show.
notesstring | nullNon/a
created_atstring (date-time)Yesn/a
updated_atstring (date-time)Yesn/a

BookingCreate

FieldTypeRequiredDescription
contact_idstring (uuid)Yesn/a
service_namestringYesn/a
start_timestring (date-time)Yesn/a
end_timestring | null (date-time)NoDefaults to start_time + 60 minutes if omitted.
notesstring | nullNon/a

BookingUpdate

At least one field must be supplied.

FieldTypeRequiredDescription
statusstringNoOne of: cancelled, confirmed, completed, no_show.
notesstring | nullNon/a
start_timestring (date-time)Non/a
end_timestring (date-time)Non/a

Quote

FieldTypeRequiredDescription
idstring (uuid)Yesn/a
quote_numberstringYesn/a
contact_idstring | null (uuid)Non/a
statusstringYesOne of: draft, sent, viewed, accepted, declined, expired, converted.
issue_datestring | null (date)Non/a
valid_untilstring | null (date)Non/a
totalnumberYesn/a
currencystringYesExactly 3 characters.
created_atstring (date-time)Yesn/a
updated_atstring (date-time)Yesn/a

QuoteCreate

FieldTypeRequiredDescription
contact_idstring (uuid)Yesn/a
totalnumberYesMin: 0.
currencystring | nullNo3-letter ISO 4217 code. Defaults to AUD. Pattern: ^[A-Z]{3}$
valid_untilstring | null (date-time)NoDefaults to 30 days from today.
line_itemsarray of objectNoAccepted for forward compatibility but currently ignored server-side — the canonical line-item table is not reconciled from API writes yet.

QuoteUpdate

At least one field must be supplied.

FieldTypeRequiredDescription
statusstringNoOne of: draft, sent, viewed, accepted, declined, expired, converted.
totalnumberNoMin: 0.
valid_untilstring (date-time)Non/a

Job

FieldTypeRequiredDescription
idstring (uuid)Yesn/a
job_numberstringYesn/a
titlestringYesn/a
statusstringYesOne of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled.
job_typestring | nullNon/a
prioritystring | nullNon/a
contact_idstring | null (uuid)Non/a
customer_namestring | nullNon/a
customer_emailstring | nullNon/a
customer_phonestring | nullNon/a
site_addressstring | nullNon/a
site_suburbstring | nullNon/a
site_statestring | nullNon/a
site_postcodestring | nullNon/a
scheduled_startstring | null (date-time)Non/a
scheduled_endstring | null (date-time)Non/a
actual_startstring | null (date-time)Non/a
actual_endstring | null (date-time)Non/a
estimated_totalnumber | nullNon/a
actual_totalnumber | nullNon/a
quote_idstring | null (uuid)Non/a
invoice_idstring | null (uuid)Non/a
created_atstring (date-time)Yesn/a
updated_atstring (date-time)Yesn/a

JobCreate

FieldTypeRequiredDescription
titlestringYesn/a
contact_idstring | null (uuid)Non/a
job_typestring | nullNon/a
prioritystring | nullNon/a
statusstringNoDefaults to quoted. One of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled.
scheduled_startstring | null (date-time)Non/a
scheduled_endstring | null (date-time)Non/a
site_addressstring | nullNon/a
site_suburbstring | nullNon/a
site_statestring | nullNon/a
site_postcodestring | nullNon/a
estimated_totalnumber | nullNoMin: 0.

JobUpdate

At least one field must be supplied.

FieldTypeRequiredDescription
titlestringNon/a
statusstringNoOne of: quoted, scheduled, in_progress, on_hold, completed, invoiced, cancelled.
job_typestring | nullNon/a
prioritystring | nullNon/a
scheduled_startstring | null (date-time)Non/a
scheduled_endstring | null (date-time)Non/a
estimated_totalnumber | nullNoMin: 0.
actual_totalnumber | nullNoMin: 0.

WebhookSubscription

FieldTypeRequiredDescription
idstring (uuid)Yesn/a
urlstring (uri)Yesn/a
eventsarray of stringYes["*"] means all events.
enabledbooleanYesn/a
descriptionstring | nullNon/a
created_atstring (date-time)Yesn/a
last_delivery_atstring | null (date-time)Non/a
last_delivery_statusinteger | nullNoHTTP status of the most recent delivery (0/-1 for network/SSRF failures).

WebhookSubscriptionWithSecret

object

WebhookCreate

FieldTypeRequiredDescription
urlstring (uri)YesHTTPS URL to POST deliveries to. Must be a public host.
eventsarray of stringYesEvents to subscribe to. Use ["*"] for all events.
descriptionstring | nullNon/a

WebhookUpdate

At least one field must be supplied.

FieldTypeRequiredDescription
urlstring (uri)Non/a
eventsarray of stringNon/a
enabledbooleanNon/a
descriptionstring | nullNon/a

Get API access

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.