API & Webhooks
A plain REST API and signed outbound webhooks for connecting Orbinly to your own tools — or to no-code platforms like Zapier and Make without writing any code at all.
Available on the Starter plan and above. Generate a key from Settings → Developer in your dashboard.
Authentication
Every request is authenticated with a bearer token in the Authorization header. A key represents your whole agency — every resource it touches is automatically scoped to that agency. Keys are shown once, at creation, and can be revoked and regenerated anytime.
Authorization: Bearer ob_live_xxxxxxxxxxxxxxxxxxxxxxxxPagination & errors
List endpoints accept ?limit= (max 100, default 50) and ?offset=, and return results newest-first — that ordering makes them usable as Zapier/Make polling triggers out of the box, with no extra "since" parameter needed.
{ "data": [ ... ], "total": 142 }Errors return a matching HTTP status with a plain message:
{ "error": "client_id not found for this agency" }Clients
The companies or individuals an agency works with.
Fields
| id | uuid | |
| name | string | |
| string | ||
| company | string | null | |
| phone | string | null | |
| avatar_url | string | null | |
| address | string | null | |
| portal_access_enabled | boolean | |
| created_at | timestamp | |
| updated_at | timestamp |
Create a client
curl https://orbinly.com/api/v1/clients \
-H "Authorization: Bearer ob_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Inc.",
"email": "hello@acme.com",
"company": "Acme Inc."
}'Projects
A project belongs to one client.
Fields
| id | uuid | |
| client_id | uuid | |
| name | string | |
| description | string | null | |
| status | "active" | "paused" | "completed" | "archived" | |
| color | string | null | hex, e.g. #4f46e5 |
| due_date | timestamp | null | |
| completed_at | timestamp | null | |
| created_at | timestamp | |
| updated_at | timestamp |
Create a project
curl https://orbinly.com/api/v1/projects \
-H "Authorization: Bearer ob_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Website redesign",
"client_id": "3c1a...-uuid",
"status": "active"
}'Tasks
A task belongs to one project. Internal-only tasks are never exposed through the API.
Fields
| id | uuid | |
| project_id | uuid | |
| parent_id | uuid | null | |
| title | string | |
| description | string | null | |
| status | "todo" | "in_progress" | "in_review" | "done" | "canceled" | |
| priority | "low" | "medium" | "high" | "urgent" | |
| position | number | |
| due_date | timestamp | null | |
| completed_at | timestamp | null | |
| created_at | timestamp | |
| updated_at | timestamp |
Create a task
curl https://orbinly.com/api/v1/tasks \
-H "Authorization: Bearer ob_live_..." \
-H "Content-Type: application/json" \
-d '{
"title": "Design homepage hero",
"project_id": "9b2e...-uuid",
"priority": "high"
}'Invoices
Invoices always belong to a client, and optionally a project. Line items are required on create.
Fields
| id | uuid | |
| client_id | uuid | |
| project_id | uuid | null | |
| invoice_number | string | |
| status | "draft" | "sent" | "viewed" | "paid" | "overdue" | "void" | |
| currency | string | 3-letter code, e.g. USD |
| subtotal | integer | cents |
| tax_rate | number | 0–1 |
| tax_amount | integer | cents |
| total_amount | integer | cents |
| due_date | timestamp | |
| sent_at / viewed_at / paid_at / void_at | timestamp | null | |
| notes | string | null |
Create a invoice
curl https://orbinly.com/api/v1/invoices \
-H "Authorization: Bearer ob_live_..." \
-H "Content-Type: application/json" \
-d '{
"client_id": "3c1a...-uuid",
"due_date": "2026-10-15T00:00:00Z",
"line_items": [
{ "description": "Design work", "quantity": 1, "unit_amount": 150000 }
]
}'Webhooks
Add an endpoint URL and pick events from Settings → Developer and Orbinly will POST a JSON payload to it in real time as those events happen — no polling required. Failed deliveries are retried automatically for up to 5 attempts.
Event types
| client.created | A new client was added |
| project.created | A new project was created |
| project.status_changed | A project moved to a new status |
| invoice.created | A new invoice was created (usually as a draft) |
| invoice.paid | An invoice was paid in full |
| invoice.overdue | An invoice passed its due date unpaid |
| proposal.accepted | A client accepted a proposal |
| proposal.rejected | A client rejected a proposal |
| contract.accepted | A client signed a contract |
| contract.rejected | A client declined a contract |
Payload shape
{
"type": "invoice.paid",
"created_at": "2026-09-16T14:03:00.000Z",
"data": {
"id": "0f2c...-uuid",
"invoice_number": "INV-202609-4821",
"total_amount": 150000,
"currency": "USD"
}
}Verifying the signature
Every delivery includes an X-Orbinly-Signature header — an HMAC-SHA256 of the raw request body, signed with the endpoint's own secret (shown once, when you create the endpoint). Recompute it and compare before trusting a payload:
const expected = "sha256=" + crypto
.createHmac("sha256", endpointSecret)
.update(rawRequestBody)
.digest("hex");
// compare to the X-Orbinly-Signature headerEmbedded apps
From Admin → Integrations, an agency can embed any tool with its own web page — a booking widget, a dashboard, a form — directly in the client portal via iframe. One URL per tool, shown to every client of that agency. Orbinly appends a short-lived, signed context to the URL so your tool's own backend can verify which agency, client, and contact is viewing.
Agencies can also pick ready-made tools from a gallery — Calendly, Cal.com, Google Calendar, HubSpot Meetings, Typeform, Jotform, Google Forms, YouTube, Vimeo, Loom and Airtable. Those can't use a signed context, so they are added with “Tell this tool who is viewing it” switched off and receive the plain URL with no client details. A custom tool you build keeps it on unless the agency turns it off.
Query parameters appended to your URL
| orbinly_ctx | Base64url-encoded JSON payload — agency/client/contact identity plus iat/exp |
| orbinly_sig | sha256=<hex> — HMAC-SHA256 of the orbinly_ctx value, same convention as webhook signatures |
Decoded payload shape
{
"agencyId": "…-uuid", "agencySlug": "acme",
"clientId": "…-uuid", "clientName": "Acme Corp",
"contactId": "…-uuid", "contactName": "Jane Smith", "contactEmail": "jane@acme.com",
"iat": 1758000000, "exp": 1758000300
}Verifying the signature
Same recipe as webhooks — recompute the HMAC over the raw orbinly_ctx value using the signing secret shown once when the integration was added, and compare:
const expected = "sha256=" + crypto
.createHmac("sha256", integrationSecret)
.update(orbinlyCtx)
.digest("hex");
// compare to orbinly_sig, then check payload.exp hasn't passedThis token travels in a URL, so treat it as something that will end up in your own server logs and possibly your own outbound referrers — it isn't a secret channel. Verify it once on load, then mint your own session rather than re-trusting the URL on every subsequent request.
Connect to Zapier
There's no published Orbinly app in the Zapier directory yet — but because Orbinly is a plain, documented REST API with real webhooks, you can wire up a working Zap today with Zapier's own built-in tools. No code required.
Trigger on an Orbinly event (e.g. "when an invoice is paid")
- Create a Zap and choose Webhooks by Zapier → Catch Hook as the trigger.
- Copy the custom webhook URL Zapier gives you.
- In Orbinly, go to Settings → Developer → Webhooks, add that URL as an endpoint, and check the events you want (e.g.
invoice.paid). - Trigger a real event in Orbinly once to let Zapier capture a sample payload, then build the rest of your Zap from its fields.
Take an action in Orbinly (e.g. "create a client")
- Add an action step and choose Webhooks by Zapier → POST.
- Set the URL to the endpoint you need, e.g.
https://orbinly.com/api/v1/clients. - Under Headers, add
Authorization: Bearer ob_live_...with your API key from Settings → Developer. - Set the payload type to JSON and map in the fields from earlier steps in your Zap.
Connect to Make
Same idea in Make (formerly Integromat) — no published Orbinly app yet, but its generic HTTP and Webhooks modules cover everything above.
- To trigger on an Orbinly event: add a Webhooks module, create a new webhook, copy its URL into Orbinly's Developer settings as an endpoint, and select the events you want.
- To take an action in Orbinly: add an HTTP → Make a request module, point it at the endpoint you need (e.g.
POST /api/v1/tasks), and add anAuthorization: Bearer ob_live_...header with your key.
Questions, or want an endpoint that isn't here yet? Get in touch.