TimeTuna

Partner API

Agencies on the white label plan run their customers from their own dashboard. This is the API that does it: create a company, give its staff seats, and sign them in, all without anyone meeting a signup form.

Every endpoint lives under https://timetuna.com/api/partner/v1 and speaks JSON. For what the white label plan includes, see the white label page.

Authentication

Send your API key as a bearer token. Keys start with tt_live_ and are shown once, when they are created: we store only a hash, so a lost key is replaced, never recovered. Mint and revoke them yourself under API keys in the Agency panel.

HTTP
Authorization: Bearer tt_live_...

The key decides which partner you are, so no request body ever carries a partner id, and a key can only ever reach companies belonging to that partner. Errors come back as { "error": "<code>", "message": "..." }. Requests are limited to 60 per minute per key, answered with 429 rate_limited.

Keep the key on your server
An API key can create companies, remove seats, and mint sign-in links for any person in them. It belongs in your backend, never in a browser or a mobile app.

Companies

A company is one of your customers: a team of up to six people, all on our top plan, with their own booking pages. Your plan includes ten of them.

POST /companies

Creates the company, the owner's account (already confirmed, so they never get an email from us), and their plan.

HTTP
POST /api/partner/v1/companies
Content-Type: application/json

{
  "name": "Bella Salon",
  "external_ref": "cust_8241",
  "owner": { "email": "owner@bellasalon.com", "name": "Bella Rossi" }
}

external_ref is your own id for the customer, and it makes this call safe to retry: posting the same external_ref twice returns the company that already exists with 200 instead of creating a second one. The response carries billable: true once you are past the ten companies your plan includes.

GET /companies

Lists companies with their seat counts, plus a usage block showing how many companies and seats are currently billable.

GET /companies/{id}

One company, with everyone in it.

PATCH /companies/{id}

Renames a company, or sets status to deactivated when a customer leaves you. Their booking pages stop taking bookings and the company stops being billable. Nothing is deleted: setting status back to active puts the pages and the plan back exactly as they were.

HTTP
PATCH /api/partner/v1/companies/{id}
Content-Type: application/json

{ "status": "deactivated" }

Seats

POST /companies/{id}/users

Adds someone to a company. The seventh person and beyond are billable add-ons, so the response says billable: true and you can warn your customer before you confirm. We never block the seat: a salon hiring on a Friday should not wait for a plan change.

HTTP
POST /api/partner/v1/companies/{id}/users
Content-Type: application/json

{ "email": "stylist@bellasalon.com", "name": "Ana", "external_ref": "user_5512" }

Adding an address that is already on the team is a no-op, so a retry cannot create a second seat or a second charge.

DELETE /companies/{id}/users/{userId}

Frees a seat. The owner cannot be removed this way: deactivate the company instead, which is reversible. The person keeps their account, so someone moving between two of your customers keeps their history.

Signing people in

POST /users/{id}/sso-link

You authenticate your customer on your own dashboard, then ask us for a link and send them to it. It works once, expires after 60 seconds, and only opens on your domain.

HTTP
POST /api/partner/v1/users/{id}/sso-link
Content-Type: application/json

{ "next": "/booking-pages" }

{
  "url": "https://book.youragency.com/auth/partner?token=...",
  "expires_at": "2026-09-09T10:00:00.000Z",
  "expires_in": 60
}

Redirect the person straight to url. Do not email it or store it: for those 60 seconds, anyone holding it is that person. Mint a new one for every sign-in, they are free.

This is the only way in
There is no password, no Google button, and no email code on your domain. Anyone who reaches the dashboard signed out is sent to your login page, not ours.

What your customers see

  • Your logo and product name in the dashboard, and your favicon in the browser tab.
  • Your mark in the footer of every booking page that has not set its own. Companies can override it, since they all have our top plan.
  • Your help link instead of ours, and no pricing, plan or upgrade prompt anywhere: you hold the plan, so there is nothing for them to buy.