Developers
Gig Nest has a REST API and signed webhooks, so your enquiries, bookings and payments can reach the tools you already use. The webhooks carry the same events that run Gig Nest's own automations.
OpenAPI 3.1 document · import it into Postman, Insomnia or your code generator.
Getting started
- In Gig Nest, open Settings → API & webhooks and make a key. Read-only keys can look things up; read-and-write keys can also add enquiries and set up webhooks.
- Send it on every request:
Authorization: Bearer gn_… - Try it:
curl https://gig-nest.com/api/v1/me -H "Authorization: Bearer gn_…"
Base URL https://gig-nest.com/api/v1. A key only ever sees the business it belongs to.
Conventions
- Money is
{ amount, currency }, withamountin pence: £850 is85000, currencyGBP. - Instants are ISO 8601 in UTC. A gig's date is a plain
YYYY-MM-DDin UK time, with start and finish asHH:MM. - Lists are newest first, 25 to a page (
limitup to 100). WhenhasMoreis true, passnextCursorback as?cursor=. - Errors are
{ "error": { "code": "not_found", "message": "…" } }with the usual HTTP status: 400, 401, 402 (trial ended), 403 (wrong scope), 404, 429. - 120 requests a minute per key. Over that you get 429 with Retry-After.
- This is v1. We add fields; we don't rename or remove them within v1.
Endpoints
GET/api/v1/meread key
The business this key belongs to
GET/api/v1/leadsread key
List leads
Query: limitcursorstatuscreatedSince
POST/api/v1/leadswrite key
Create a lead
Adds an enquiry exactly as if it came through your website form: it's scored and a reply drafted (when AI is on), you're alerted, the enquirer gets an acknowledgement (unless `sendAcknowledgement` is false), and your automations and `lead.created` webhooks fire. Needs a name and at least one of a message, an event date or a phone number.
GET/api/v1/leads/{id}read key
Get a lead
GET/api/v1/clientsread key
List or find clients
Query: limitcursoremailq
GET/api/v1/clients/{id}read key
Get a client
GET/api/v1/eventsread key
List bookings
Query: limitcursorstatusclientIdfromto
GET/api/v1/events/{id}read key
Get a booking
PATCH/api/v1/events/{id}write key
Update a booking's title, notes or times
Only fields with no knock-on effects can change here. Status, price and date move deposits, holds, contracts and client emails, so they're changed in Gig Nest itself.
GET/api/v1/invoicesread key
List invoices and credit notes
Query: limitcursorstatusclientIdeventId
GET/api/v1/invoices/{id}read key
Get an invoice
GET/api/v1/paymentsread key
List payments
Deposits, balances and instalments: requested (`pending`), received (`paid`) or cancelled (`void`).
Query: limitcursorstatuseventId
GET/api/v1/packagesread key
List packages
Your package catalogue, cheapest first, in one page. Retired packages are left out unless `active=false`.
Query: active
GET/api/v1/webhook-eventsread key
Recent events, as webhooks deliver them
Newest first. Handy for sample data, or for tools that poll instead of receiving webhooks. The object is rendered as it is now.
Query: limitcursortype
POST/api/v1/hookswrite key
Subscribe a URL to events (REST hooks)
What Zapier and Make call when a Zap is switched on. Creates a webhook owned by this key; revoking the key switches it off. The signing secret is returned once.
DELETE/api/v1/hooks/{id}write key
Unsubscribe (REST hooks)
Only removes subscriptions made through the API. Webhooks added in Settings stay until you delete them there.
GET/api/v1/openapi.jsonno key needed
This document
Objects
Lead
object"lead"idstringstatusnew | contacted | quoted | won | lostnamestringemailstring or nullphonestring or nullmessagestringsourcestring or null · Where it came from, e.g. Website, phone-ai, api.eventTypestring or nulleventDatestring or nulllocationstring or nullguestCountinteger or nullscoreinteger or null · AI score out of 100, once triaged.scoreBandstring or nullquoteMoney or nullclientIdstring or nulleventIdstring or null · The booking it became, if any.createdAtstring or nullupdatedAtstring or null
Client
object"client"idstringnamestringemailstring or nullphonestring or nullonAccountbooleanpaymentTermsDaysinteger or nullcreatedAtstring or null
Event
object"event"idstringtitlestringstatusenquiry | pencilled | confirmed | completed | cancelleddatestring or null · The gig's day, UK time.startTimestring or null · HH:MM, UK time.endTimestring or null · HH:MM, UK time.priceMoneydepositMoneypackageobject or nullcontractSignedAtstring or nullnotesstring or nullclientIdstringclientobject or nullvenueobject or nullcreatedAtstring or nullupdatedAtstring or null
Invoice
object"invoice"idstringreferencestringkindinvoice | credit_notestatusdraft | sent | paid | overdue | voidclientIdstringeventIdstring or nullissuedAtstring or nulldueAtstring or nullpaidAtstring or nullpoNumberstring or nullvatRatePercentintegernetMoneyvatMoneytotalMoneylinesarraycreatedAtstring or nullupdatedAtstring or null
Payment
object"payment"idstringeventIdstringkinddeposit | balance | instalment | otherstatuspending | paid | voidamountMoneyrefundedMoneynotestring or nullpaidAtstring or nullrefundedAtstring or nullcreatedAtstring or null
Package
object"package"idstringnamestringdescriptionstring or nullpriceMoneyhoursinteger or nullactiveboolean
WebhookEvent
idstring · The event id. The same on every retry.typelead.created | lead.replied | lead.lost | quote.sent | proposal.viewed | proposal.accepted | proposal.expiring | proposal.expired | booking.confirmed | booking.cancelled | contract.sent | contract.signed | payment.received | payment.failed | instalment.due | invoice.issued | invoice.paid | invoice.overdue | credit_note.issued | statement.issued | meeting.booked | meeting.cancelled | call.answered | call.question | music.locked | webhook.testcreatedAtstringdataobject
Webhooks
Add an address in Settings → API & webhooks (or subscribe one through POST /api/v1/hooks) and choose the events. We POST each event as JSON within about a minute. data.object is the same shape the API returns.
{
"id": "cm2x9q1ab0001",
"type": "lead.created",
"createdAt": "2026-10-22T14:03:00.000Z",
"data": {
"object": {
"object": "lead",
"id": "cm2x9q0zz0000",
"status": "new",
"name": "Sam Patel",
"email": "sam@example.com",
"eventDate": "2027-06-12",
"quote": null,
"createdAt": "2026-10-22T14:03:00.000Z"
},
"context": { "source": "Website" }
}
}Checking the signature
Every request has a Gig-Nest-Signature: t=<unix seconds>,v1=<hex> header. v1 is the HMAC-SHA256 of t, a full stop, and the raw body, keyed with the webhook's signing secret. Check it, and that t is recent:
import crypto from "node:crypto";
// rawBody: the request body exactly as received (a string, before JSON.parse)
// header: the Gig-Nest-Signature header, e.g. "t=1792683600,v1=5f1c…"
// secret: the webhook's signing secret (whsec_…)
export function verifyGigNest(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
const t = Number(parts.t);
if (!Number.isInteger(t) || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // too old: a replay
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(parts.v1, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Delivery and retries
- Answer with any 2xx within ten seconds. We don't follow redirects.
- Anything else is retried: after 1 minute, 5 minutes, 30 minutes, 2, 5, 10 and 12 hours — eight tries over about a day.
- The
Gig-Nest-Event-Idheader (and the body'sid) stays the same on every retry, so you can ignore one you've already handled. - If an address has failed for a day, we switch it off and email the business owner. Answer
410 Goneto unsubscribe straight away. - Addresses must be https and reachable on the public internet.
Events
lead.created· New enquirylead.replied· Client repliedlead.lost· Lead marked lostquote.sent· Quote sentproposal.viewed· Proposal viewedproposal.accepted· Proposal acceptedproposal.expiring· Proposal expiring soonproposal.expired· Proposal expiredbooking.confirmed· Booking confirmedbooking.cancelled· Booking cancelledcontract.sent· Contract sentcontract.signed· Contract signedpayment.received· Payment receivedpayment.failed· Payment failedinstalment.due· Instalment dueinvoice.issued· Invoice issuedinvoice.paid· Invoice paidinvoice.overdue· Invoice overduecredit_note.issued· Credit note issuedstatement.issued· Crew statement issuedmeeting.booked· Call bookedmeeting.cancelled· Call cancelledcall.answered· Receptionist answered a callcall.question· Receptionist couldn't answer a questionmusic.locked· Music plan lockedwebhook.test· the settings screen's test button
Zapier, Make and n8n
Zapier
Use Webhooks by Zapier: a Catch Hook trigger, with its address added here as a webhook. For actions, use its Custom Request with the header Authorization: Bearer gn_….
Make
Start a scenario with Webhooks → Custom webhook, copy its address into Gig Nest as a webhook, and choose your events. Use the HTTP module with Authorization: Bearer gn_… to look things up or add a lead.
n8n
Use a Webhook node (POST) as the trigger and add its production URL in Gig Nest. For actions, use the HTTP Request node with a Header Auth credential: name Authorization, value Bearer gn_….
Already sending Facebook Lead Ads into Gig Nest through Zapier or Make? That inbound address keeps working exactly as before.