Skip to content

List bookings API with GET /api/v1/bookings

The list bookings API is GET /api/v1/bookings: it returns your business’s appointments in time order, each with its local time in its branch and its UTC instant, selected by day and by status. It needs a key with the bookings.read scope.

It returns one page of bookings in data, from the earliest appointment to the latest, with a nextCursor for the next page, or null on the last page.

  • Without from and to, you get every booking from the earliest, past and upcoming.
  • Appointments booked by the agent or your team in Mujib are included. Historical rows imported from an old register are not part of the API.
  • Read bookings is offered when you create a key only if your business uses appointments.

All parameters are optional, and any other parameter returns a 400:

ParameterTypeMeaning
fromdate YYYY-MM-DDFirst day, included
todate YYYY-MM-DDLast day, included
statusstringOne status only (see the next table)
limitintegerBookings per page: 50 by default, up to 100
cursorstringThe previous page’s nextCursor. See cursor pagination
  • from and to are days in each branch’s calendar and time zone, not UTC. An appointment at ten in the morning in your branch falls on its day as you see it in the dashboard.
  • A date must be a real day: 2026-02-31 gets a 400, and so does a from after to.
  • For a single day’s bookings, set from and to to the same day.

status values, and what the dashboard calendar calls them:

ValueIn the dashboard
requestedPending
confirmedConfirmed
cancelledCancelled
completedAttended
no_showNo-show

This example asks for a month of confirmed bookings:

نافذة طرفيّة
curl "https://api.mujib.ai/api/v1/bookings?from=2026-11-01&to=2026-11-30&status=confirmed&limit=100" \
-H "Authorization: Bearer $MUJIB_API_KEY"
const url = new URL('https://api.mujib.ai/api/v1/bookings');
url.searchParams.set('from', '2026-11-01');
url.searchParams.set('to', '2026-11-30');
url.searchParams.set('status', 'confirmed');
url.searchParams.set('limit', '100');
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.MUJIB_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
for (const b of body.data) console.log(b.localTime, b.branch?.name, b.customer.name);
import os
import requests
res = requests.get(
"https://api.mujib.ai/api/v1/bookings",
params={"from": "2026-11-01", "to": "2026-11-30", "status": "confirmed", "limit": 100},
headers={"Authorization": f"Bearer {os.environ['MUJIB_API_KEY']}"},
timeout=30,
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{res.status_code} {body['error']['code']}: {body['error']['message']}")
for b in body["data"]:
print(b["localTime"], (b["branch"] or {}).get("name"), b["customer"]["name"])

To read every page to the end, use the function in cursor pagination.

A 200. The data is made up, for a branch in Amman:

{
"data": [
{
"id": "3f0c9a52-7d1e-4b8a-9c41-2e6f8a1b0d77",
"status": "confirmed",
"source": "agent",
"service": "consultation",
"startsAt": "2026-11-12T07:30:00Z",
"localTime": "2026-11-12T10:30:00",
"timezone": "Asia/Amman",
"durationMinutes": 30,
"branch": { "id": "e7f6a5b4-3c2d-4e1f-9a8b-7c6d5e4f3a21", "name": "الفرع الرئيسي" },
"specialist": "ليلى",
"customer": { "contactId": "5d8f2a61-0c4e-4b7a-9f13-6e2b8c0d4a57", "name": "سارة", "phone": "962790000000" },
"createdAt": "2026-11-04T18:22:09.117Z"
},
{
"id": "c2a7e915-6f3b-4d80-b4e1-7a9d5c0f2b36",
"status": "requested",
"source": "staff",
"service": "followup",
"startsAt": "2026-11-12T09:00:00Z",
"localTime": "2026-11-12T12:00:00",
"timezone": "Asia/Amman",
"durationMinutes": null,
"branch": { "id": "e7f6a5b4-3c2d-4e1f-9a8b-7c6d5e4f3a21", "name": "الفرع الرئيسي" },
"specialist": null,
"customer": { "contactId": null, "name": "أحمد", "phone": "0790000000" },
"createdAt": "2026-11-05T08:01:44.360Z"
}
],
"nextCursor": "MjAyNi0xMS0xMlQxMjowMDowMHxjMmE3ZTkxNS02ZjNiLTRkODAtYjRlMS03YTlkNWMwZjJiMzY"
}

Every booking always carries these fields; a field with no value comes as null:

FieldTypeMeaning
idstringThe booking’s stable id, for get a booking
statusstringThe booking’s status (see the table above)
sourcestringWho made it: agent, the agent in a conversation, or staff, your team in the dashboard
servicestringThe visit type’s id as your business defined it, such as consultation, not its display name. See visit types
startsAtUTC instantThe start in UTC, as YYYY-MM-DDTHH:MM:SSZ
localTimestringThe start on the branch’s clock, with no offset, as YYYY-MM-DDTHH:MM:SS. This is the time the customer was given
timezonestringThe time zone of localTime, such as Asia/Amman: the branch’s zone, else your business’s
durationMinutesinteger or nullLength in minutes, or null when your business’s default length applies
branchobject or nullThe branch, with id and name, or null when the booking has none
specialiststring or nullThe specialist’s name, or null when none is assigned
customer.contactIdstring or nullThe customer’s id for get a contact, or null for a booking without a registered customer
customer.namestring or nullThe name written on the booking, else the customer’s name
customer.phonestring or nullThe number written on the booking, else the customer’s number
createdAtUTC instantWhen the booking was made
HTTPcodeWhy
400VALIDATION_ERRORAn unknown parameter, a date not in YYYY-MM-DD or not a real day, from after to, an unknown status, a limit out of range, or a cursor that cannot be read
401UNAUTHORIZEDNo key, or a key that is not valid
403FORBIDDENThe key lacks bookings.read
429RATE_LIMITEDYou went over a rate limit
500INTERNALAn unexpected server error

The details are in API errors and rate limits.

Frequently asked questions

Are from and to in UTC?

No. They are calendar days in each branch's own time zone, and both days are included. startsAt in the response is a UTC instant.

Do old bookings I imported from a previous register show up?

No. Historical rows imported from an old register are not part of the API. Appointments booked in Mujib are.

What does a null durationMinutes mean?

The booking carries no length of its own, so your business's default length applies.

Can the list tell me which bookings changed recently?

There is no parameter for that. Read the window of days you care about again, or use webhooks to hear about each new or cancelled booking as it happens.