Integrations

The operating system for your service business.

SendLynx runs the whole day — booking, payments, reminders, and follow-up. Connect the tools you already use, and let partners build on top with our API.

Live now

Connected today

Google Calendar

Live

Two-way sync. Your bookings land on your Google Calendar and your personal events block your availability — automatically.

Stripe

Live

Take deposits and card payments straight to your own bank on Stripe Connect. We never touch or take a cut of your money.

Apple & Google Sign-In

Live

One-tap sign-in with Apple or Google, on the web and in the iOS app. Link either to your account in Settings.

SendLynx Partner API

Live

A scoped OAuth 2.0 API for trusted partners (like Quickflo) to book, check availability, and read payments on a business's behalf.

Webhooks

Live

Real-time HTTPS webhooks with HMAC signatures for bookings, payments, and new clients. Subscribe from your dashboard (Developers → Webhooks) or via the API.

HubSpot

Live

Direct CRM sync — new clients land in HubSpot as contacts and confirmed bookings log as meetings on their timeline. Connect it in Settings.

Coming soon

These aren't live yet. Tell us which one you need and we'll get you early access the moment it ships.

QuickBooks Online

Soon

Direct accounting sync is built and rolling out — payments post to your books as sales receipts automatically. (Accounting CSV export is available today.)

Request early access

Zapier

Soon

Wire SendLynx into thousands of apps with no code. Our Zapier app is built and awaiting Zapier's review — it goes live the moment they publish it.

Request early access

Mailchimp

Soon

Push your client list into email marketing campaigns.

Request early access

Google Business Profile

Soon

Pull reviews and keep your listing in sync.

Request early access

Square (import)

Soon

Bring your existing clients and history over from Square.

Request early access
Developer & Partner API

Build on SendLynx

A scoped OAuth 2.0 REST API with signed webhooks. Read and manage a business's scheduling data — only after that business explicitly authorizes your app.

PKCE-required auth REST endpoints Signed webhooks

OAuth 2.0 · REST · Webhooks

Overview

The SendLynx API lets your platform read and manage a business's scheduling data after that business explicitly authorizes you. Access is scoped per business: you only ever touch the data of businesses that connected your app.

Connecting an app is a SendLynx Studio feature. If a connected business later drops below Studio, its tokens stop refreshing and API access lapses within an hour (403 access_denied); it resumes automatically if they upgrade again, with no re-authorization needed.

  1. Redirect the business owner to SendLynx to log in and approve your app.
  2. SendLynx redirects back with a one-time code.
  3. Your server exchanges the code for an access token + refresh token.
  4. You call /api/v1/* with the access token.
  5. SendLynx sends you signed webhooks as bookings and payments change.

Discovery metadata: https://sendlynx.com/.well-known/oauth-authorization-server

Quickstart

Apps are created in two ways: self-serve from your dashboard (Developers → Create app) or by the SendLynx team for partners. Either way you get a client_id, a client_secret (shown once), your scopes, and an optional webhook_secret. The flow is Authorization Code with PKCE (S256, required); keep your client_secret server-side.

Authentication

Generate a PKCE verifier/challenge and send the owner's browser to:

https://sendlynx.com/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/oauth/callback
  &scope=availability:read bookings:read bookings:write clients:write
  &state=RANDOM_CSRF_STRING
  &code_challenge=BASE64URL_SHA256_OF_VERIFIER
  &code_challenge_method=S256

The owner approves; SendLynx redirects to your redirect_uri with ?code=...&state=... (the redirect_uri must exactly match a registered one). Exchange the code:

curl -X POST https://sendlynx.com/api/oauth/token \
  -u YOUR_CLIENT_ID:YOUR_CLIENT_SECRET \
  -d grant_type=authorization_code \
  -d code=THE_CODE \
  -d redirect_uri=https://yourapp.com/oauth/callback \
  -d code_verifier=YOUR_PKCE_VERIFIER

# → { "access_token": "...", "token_type": "Bearer",
#     "expires_in": 3600, "refresh_token": "...", "scope": "..." }

Access tokens last 1 hour. Refresh tokens last 30 days and rotate on every use, so store the newest one. Replaying an old refresh token revokes the whole authorization.

curl -X POST https://sendlynx.com/api/oauth/token \
  -u YOUR_CLIENT_ID:YOUR_CLIENT_SECRET \
  -d grant_type=refresh_token \
  -d refresh_token=THE_REFRESH_TOKEN

Scopes

services:readView your services, pricing, variants and add-ons
services:writeCreate, update and remove your services
staff:readView your team members
staff:writeAdd, update and remove your team members
availability:readCheck your open appointment times
bookings:readView your appointments
bookings:writeCreate, reschedule and cancel appointments
clients:readView your customer contacts
clients:writeAdd and update customer contacts
payments:readView deposit/payment status for jobs
quotes:readView your quotes, estimates and invoices
quotes:writeCreate, send, convert and collect on quotes
hooks:manageSubscribe to and manage webhook notifications for your business
bookings:manageConfirm, complete, mark no-show and annotate appointments
payments:writeIssue refunds and resend deposit links
schedule:writeEdit availability, exceptions and time blocks
messaging:sendMessage your clients by email or SMS
team:manageManage team members and invitations
waitlist:manageManage your waitlist
reviews:manageView and publish client reviews
settings:readView your business settings
settings:writeUpdate your business settings
insights:readView dashboard metrics and insights
devices:writeRegister this device for push notifications
account:readView your account security status (two-factor)
account:writeManage your account security (enable/disable two-factor)

API console

Once you're logged in on a Studio (or trial) account, you can run real API calls against your own business data right in the browser: pick an endpoint, edit the params, and hit Send.

Open the API console →

Endpoints

Base URL https://sendlynx.com/api/v1. Pass the access token as Authorization: Bearer …. List endpoints are cursor-paginated (?limit= max 100, ?cursor=) and return { data, next_cursor, has_more }. Send an Idempotency-Key header on POSTs so retries never double-book.

Services

GET
/api/v1/services
services:read

List services with their variants and add-ons.

activequeryOnly active services (default true).
limitqueryPage size, max 100.
cursorqueryPagination cursor from a previous response.
GET
/api/v1/services/:id
services:read

Retrieve a single service.

idpath · requiredService id.
POST
/api/v1/services
services:write

Create a service. Money is in integer cents. paymentMode defaults to 'deposit' when a deposit is set, else 'in_person'.

Example body

{
  "name": "Men's Haircut",
  "description": "Classic cut and style.",
  "durationMin": 30,
  "priceCents": 5000,
  "depositCents": 1000,
  "paymentMode": "deposit",
  "bufferMin": 5,
  "active": true,
  "rebookEnabled": true,
  "rebookIntervalDays": 28
}
PATCH
/api/v1/services/:id
services:write

Update a service. Send only the fields you want to change.

idpath · requiredService id.

Example body

{
  "priceCents": 5500,
  "active": true
}
DELETE
/api/v1/services/:id
services:write

Delete a service. Fails with 409 if it has bookings — deactivate it (PATCH active:false) instead to keep its history.

idpath · requiredService id.

Staff

GET
/api/v1/staff
staff:read

List team members (optionally filtered to a service).

serviceIdqueryOnly staff who offer this service.
activequery
POST
/api/v1/staff
staff:write

Create a provider (owner/admin). Enforces your plan's provider cap and seeds default Mon–Fri 9–5 hours. Pass serviceIds to set which services they offer.

Example body

{
  "name": "Jordan Smith",
  "email": "jordan@example.com",
  "bio": "Senior stylist",
  "active": true,
  "serviceIds": []
}
PATCH
/api/v1/staff/:id
staff:write

Update a provider (owner/admin). Send only the fields you want to change; serviceIds replaces their service assignments.

idpath · requiredStaff id.

Example body

{
  "name": "Jordan A. Smith",
  "active": true
}
DELETE
/api/v1/staff/:id
staff:write

Delete a provider (owner/admin). Fails with 409 if they have bookings — deactivate (PATCH active:false) instead to keep history.

idpath · requiredStaff id.

Availability

GET
/api/v1/availability
availability:read

Open appointment slots per day across a date range (max 14 days). For a multi-service session pass additionalServiceIds — slots are sized to the merged duration and only providers who offer EVERY selected service are considered (so the slots are bookable with the same combo via POST /bookings).

serviceIdquery · required
staffIdqueryA staff id, or 'any' (default).
fromquery · requiredYYYY-MM-DD.
toqueryYYYY-MM-DD (defaults to `from`).
durationqueryOverride duration in minutes (applies to the primary service).
additionalServiceIdsqueryComma-separated extra service ids for a multi-service session — their duration is added and the provider pool is narrowed to those offering all of them.

Bookings

GET
/api/v1/bookings
bookings:read

List bookings, newest first.

statusquerypending | confirmed | completed | cancelled | no_show
clientIdquery
fromqueryISO datetime: filters startTime.
toqueryISO datetime: filters startTime.
limitquery
cursorquery
POST
/api/v1/bookings
bookings:write

Create an appointment. customer.email OR customer.phone is required (a phone-only customer gets a synthetic address). smsConsent is a LEGAL CONSENT ASSERTION, not a message toggle: pass true ONLY when your application has captured the customer's express consent to receive appointment texts (TCPA) — it is recorded durably on the client. When true (with a phone), SendLynx also sends an SMS confirmation. Set notify:false to suppress SendLynx's confirmation (when you send your own). The response carries sms:{sent,reason} so you can see whether the confirmation text went out (e.g. reason:"sms_disabled"). If a deposit is required, returns a depositCheckoutUrl. MULTI-SERVICE: pass additionalServiceIds:[…] to book several services in one appointment — their duration + price merge into the session, the chosen provider must offer EVERY service (with staffId:"any" only providers who do all of them are considered), and the booking response includes a services[] snapshot ({serviceId,name,durationMin,priceCents}, primary first). variantId applies to the primary service; addOnIds may reference an add-on of ANY service in the session (primary or an additionalServiceId) and each add-on's price + time merges into the totals.

Example body

{
  "serviceId": "REPLACE_WITH_SERVICE_ID",
  "staffId": "any",
  "startUtc": "2026-06-20T15:00:00Z",
  "customer": {
    "name": "Jane Doe",
    "phone": "+15551234567"
  },
  "additionalServiceIds": [],
  "addOnIds": [],
  "smsConsent": true,
  "notify": true,
  "serviceAddress": "12 Main St",
  "notes": "Leaky faucet"
}
GET
/api/v1/bookings/:id
bookings:read

Retrieve a single booking.

idpath · required
PATCH
/api/v1/bookings/:id
bookings:write

Reschedule a booking to a new start time.

idpath · required

Example body

{
  "startUtc": "2026-06-21T16:00:00Z"
}
POST
/api/v1/bookings/:id/cancel
bookings:write

Cancel a booking.

idpath · required

Example body

{
  "reason": "Customer requested"
}
POST
/api/v1/bookings/:id/cancel-series
bookings:write

Cancel this booking and every upcoming occurrence of its recurring series (each goes through the full cancel path: deposit refund, seat release, calendar + waitlist). Falls back to a single cancel if the booking isn't recurring. Returns { cancelled: <count> }.

idpath · required

Clients

GET
/api/v1/clients
clients:read

List customer contacts (each includes phone). Look up by email or phone.

emailqueryExact-match lookup by email.
phonequeryLookup by phone — matches on the last 10 digits, so any format works (+1, spaces, dashes, parens).
limitquery
cursorquery
POST
/api/v1/clients
clients:write

Create or update a customer by email (201 if new, 200 if matched).

Example body

{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+15551234567",
  "smsConsent": false
}
GET
/api/v1/clients/:id
clients:read

Retrieve a single customer.

idpath · required
PATCH
/api/v1/clients/:id
clients:write

Update a customer. Email can be changed (e.g. a phone-only client who later gives a real address); it's the dedup key, so a collision with another client returns 409. smsConsent can only be turned on; pass notes to set the operator note (empty string clears it).

idpath · required

Example body

{
  "name": "Jane A. Doe",
  "email": "jane@example.com",
  "phone": "+15559876543",
  "notes": "Prefers morning appointments."
}

Payments

GET
/api/v1/payments
payments:read

List deposit/payment records (no raw Stripe ids).

bookingIdquery
statusquerypending | paid | refunded | failed | not_required
limitquery
cursorquery

Webhooks

GET
/api/v1/hooks
hooks:manage

List your webhook subscriptions (signing secrets are never returned).

POST
/api/v1/hooks
hooks:manage

Subscribe an HTTPS URL to events: booking.created, booking.requested, booking.canceled, booking.rescheduled, payment.received, client.created. Returns the HMAC signing `secret` ONCE — store it to verify the X-SendLynx-Signature header. 10 consecutive delivery failures auto-disable a subscription.

Example body

{
  "url": "https://example.com/webhooks/sendlynx",
  "events": [
    "booking.created",
    "payment.received"
  ]
}
DELETE
/api/v1/hooks/:id
hooks:manage

Unsubscribe a webhook (Zapier calls this when a Zap is turned off).

idpath · requiredSubscription id.
GET
/api/v1/hooks/sample/:event
hooks:manage

A realistic static sample delivery for an event type — shaped exactly like a live webhook POST body.

eventpath · requiredOne of the event types listed under hooks.create.

Account

GET
/api/v1/account/2fa
account:read

Two-factor status for your account: { enabled, enabledAt }.

POST
/api/v1/account/2fa/enroll
account:write

Begin two-factor enrollment. Returns an otpauth keyUri, a QR data URL, and the manual secret. Does not enable 2FA until you confirm.

POST
/api/v1/account/2fa/confirm
account:write

Confirm enrollment with a live code; enables 2FA and returns the one-time backup codes.

Example body

{
  "code": "123456"
}
POST
/api/v1/account/2fa/disable
account:write

Disable 2FA after re-proving identity with your password OR a current authenticator code.

Example body

{
  "code": "123456"
}

Settings

GET
/api/v1/settings
settings:read

The business's operational config — including smsEnabled (whether SMS confirmations/reminders are turned on), timezone, deposit/notice/cancel policies, and branding.

PATCH
/api/v1/settings
settings:write

Partial update of operational settings (owner/admin). Set smsEnabled:true to turn on SMS for a business — new businesses start with it OFF. (SMS still also requires an SMS-capable plan and per-client consent before a text actually sends.)

Example body

{
  "smsEnabled": true,
  "notifyOnPayment": true
}
GET
/api/v1/settings/calendar
settings:read

Google Calendar status: { connected, googleEmail, available, connectUrl }. Open connectUrl in a browser to connect.

DELETE
/api/v1/settings/calendar
settings:write

Disconnect Google Calendar for your provider profile.

POST
/api/v1/settings/logo
settings:write

Upload the business logo (multipart 'file', image/* ≤10MB). Sets logoUrl.

POST
/api/v1/settings/cover
settings:write

Upload the business cover image (multipart 'file', image/* ≤10MB). Sets coverImageUrl.

SMS

GET
/api/v1/sms/usage
settings:read

SMS allowance + usage this month: { monthlyCap, usedThisMonth, allowanceRemaining, purchasedCreditBalance }. Buying credits is web-only.

Webhooks

Webhook subscriptions (REST hooks)

Subscribe any HTTPS endpoint to events with POST /api/v1/hooks (scope hooks:manage) — pass { url, events } and store the returned secret (shown once). Events: booking.created, booking.requested, booking.canceled, booking.rescheduled, payment.received, client.created. Each delivery is a JSON envelope { id, event, createdAt, data } signed via the X-SendLynx-Signature header (same HMAC scheme as below). Unsubscribe with DELETE /api/v1/hooks/:id; get editor sample data from GET /api/v1/hooks/sample/:event. Ten consecutive delivery failures auto-disable a subscription (re-enable it from Developers → Webhooks). This is the surface our Zapier app rides on.

Partner-app webhooks

If your OAuth app has a webhook URL, SendLynx POSTs JSON events: booking.created, booking.rescheduled, booking.cancelled, booking.completed, payment.completed. Delivery is at-least-once with retries, so dedupe on the Sendlynx-Event-Id header. Verify the signature before trusting an event:

const crypto = require("crypto");

function verifySendlynxWebhook(rawBody, signatureHeader, secret) {
  // header: "t=1718900000,v1=<hex>"
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
  const expected = crypto
    .createHmac("sha256", secret)
    .update(parts.t + "." + rawBody)
    .digest("hex");
  const ok = crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
  if (!ok) throw new Error("Invalid signature");
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) throw new Error("Stale webhook");
  return JSON.parse(rawBody); // { id, type, created, business_id, data }
}

Errors

Errors are JSON: { "error": "code", "error_description": "..." }.

400  invalid_request        Malformed request / validation failed
401  invalid_token          Missing, expired, or revoked access token
403  insufficient_scope     Token lacks the required scope
403  access_denied          Business's plan no longer includes API access (Studio)
403  business_inactive      The business isn't taking bookings right now
404  not_found              Resource missing or not yours
409  slot_unavailable       That time was just taken
409  client_conflict        Customer already has an overlapping booking
422  group_booking_unsupported  Class/group services can't be booked via API yet
429  rate_limited           Slow down

Revocation

A business owner can revoke your app anytime from Settings → Connected apps; you can also revoke programmatically (RFC 7009):

curl -X POST https://sendlynx.com/api/oauth/revoke \
  -u YOUR_CLIENT_ID:YOUR_CLIENT_SECRET \
  -d token=THE_TOKEN

After revocation, all tokens for that business stop working immediately.

Need an integration we don't have yet?

Tell us what you use and we'll build the connection — or partner with us on the API.