REST API reference
Fresha API
14 endpoints for Fresha. Each one is a POST with a JSON body, called with your API key.
- Base URL
- https://cotlet.dev/api/v1/fresha
- Connects with
- Your own Fresha business account (owner, or a team member whose permissions cover the calendar, clients, reports and wallet)
- Integration page
- Fresha
| Endpoint | Access | Description |
|---|---|---|
| list_appointments | read | Appointments in a date range, with client, services, team member and status. |
| find_available_slots | read | Free start times on one day for one or more services, for anyone or one team member. |
| list_clients | read | Your client list with contact details, last appointment and marketing consent. |
| get_client | read | Client profile: details, notes, allergies, and upcoming and past appointments. |
| list_services | read | Your service menu with categories, durations and prices. |
| list_team_members | read | Bookable team members with their locations and services. |
| get_sales_summary | read | Sales, discounts and refunds from the Sales summary report, for a date range. |
| list_payouts | read | Payouts from your business wallet to your bank, with dates, amounts and fees. |
| create_appointment | write | Book one or more services for a client at a given time. |
| reschedule_appointment | write | Move an appointment to a new time, and optionally to another team member. |
| cancel_appointment | write | Cancel a current or future appointment with one of your cancellation reasons. |
| add_client | write | Create a client profile. Nothing is sent to the client. |
| add_client_note | write | Save a note on a client profile, such as a color formula or preference. |
| add_blocked_time | write | Block time in a team member's calendar for a break, training or admin. |
List appointments
readPOST https://cotlet.dev/api/v1/fresha/list_appointments
Lists appointments for the dates you give, ordered by start time. Each one has its client, services, team member and status. Statuses are Booked, Confirmed, Completed, Cancelled and No-show, plus any custom statuses your business created in Settings; custom ones come back under their own name. Pass appointment_id from an item to reschedule_appointment or cancel_appointment. Pass next_cursor back as cursor for the next page.
Parameters
| Name | Type | Description |
|---|---|---|
| from required | date | First day. |
| to | date | Last day. Default: same as from. |
| status | string | booked, confirmed, completed, cancelled or no_show, or the name of a custom status. Default: all. |
| team_member_id | string | Only this team member. |
| client_id | string | Only this client. |
| location_id | string | Only this location. Default: all locations. |
| cursor | string | Next page cursor from the previous call. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/list_appointments \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"from":"2026-10-01"}' result = client.call("fresha", "list_appointments", {"from":"2026-10-01"}) const result = await cotlet.call('fresha', 'list_appointments', {"from":"2026-10-01"}); cotlet call fresha list_appointments --data '{"from":"2026-10-01"}' Example response
{
"appointments": [
{
"appointment_id": "ap_90311301",
"client": {
"client_id": "cl_48213977",
"name": "Anna Smith"
},
"start_at": "2026-10-15T10:00:00+01:00",
"end_at": "2026-10-15T10:45:00+01:00",
"services": [
"Haircut"
],
"team_member": {
"team_member_id": "tm_5521",
"name": "Sam"
},
"status": "Booked",
"location_id": "loc_201"
}
],
"next_cursor": null
} Find available slots
readPOST https://cotlet.dev/api/v1/fresha/find_available_slots
Returns the free start times on one day for the services you list, booked back to back in that order. Each slot names the team member who is free. Pass start_at from a slot to create_appointment or reschedule_appointment. The search covers one day per call.
Parameters
| Name | Type | Description |
|---|---|---|
| service_ids required | string[] | Services from list_services, booked in this order. |
| date required | date | Day to search. |
| team_member_id | string | Only this team member. Default: anyone. |
| location_id | string | Only this location. Default: all locations. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/find_available_slots \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"service_ids":["service ids"],"date":"2026-10-01"}' result = client.call("fresha", "find_available_slots", {"service_ids":["service ids"],"date":"2026-10-01"}) const result = await cotlet.call('fresha', 'find_available_slots', {"service_ids":["service ids"],"date":"2026-10-01"}); cotlet call fresha find_available_slots --data '{"service_ids":["service ids"],"date":"2026-10-01"}' Example response
{
"date": "2026-10-16",
"slots": [
{
"start_at": "2026-10-16T14:30:00+01:00",
"end_at": "2026-10-16T15:15:00+01:00",
"team_member_id": "tm_5521",
"team_member": "Sam"
},
{
"start_at": "2026-10-16T16:00:00+01:00",
"end_at": "2026-10-16T16:45:00+01:00",
"team_member_id": "tm_5521",
"team_member": "Sam"
}
]
} List clients
readPOST https://cotlet.dev/api/v1/fresha/list_clients
Lists clients, A to Z, with contact details, their last appointment date and marketing consent. The last appointment ignores cancelled and no-show bookings, the same as Fresha's Client insights report. Use last_appointment_before to find clients who have not been in since a date. Card details are never returned. Pages hold up to 500 clients; pass next_cursor back as cursor.
Parameters
| Name | Type | Description |
|---|---|---|
| search | string | Name, email or phone. |
| last_appointment_before | date | Only clients whose last appointment was before this date. |
| location_id | string | Only this location. Default: all locations. |
| limit | integer | 1 to 500. Default: 100. |
| cursor | string | Next page cursor from the previous call. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/list_clients \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("fresha", "list_clients") const result = await cotlet.call('fresha', 'list_clients'); cotlet call fresha list_clients Example response
{
"clients": [
{
"client_id": "cl_48213977",
"name": "Anna Smith",
"email": "anna@example.com",
"phone": "+44 7700 900123",
"last_appointment": "2026-06-20",
"accepts_marketing": true,
"accepts_sms_marketing": false
}
],
"next_cursor": "eyJvZmZzZXQiOjEwMH0"
} Get client
readPOST https://cotlet.dev/api/v1/fresha/get_client
Returns one client's profile: contact details, the notes your team saved, allergies, and upcoming and past appointments, newest first. Notes are visible only to your team. Use it before booking or writing to a client.
Parameters
| Name | Type | Description |
|---|---|---|
| client_id required | string | Client ID from list_clients. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/get_client \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"client_id":"client_8c41d2"}' result = client.call("fresha", "get_client", {"client_id":"client_8c41d2"}) const result = await cotlet.call('fresha', 'get_client', {"client_id":"client_8c41d2"}); cotlet call fresha get_client --data '{"client_id":"client_8c41d2"}' Example response
{
"client_id": "cl_48213977",
"name": "Anna Smith",
"phone": "+44 7700 900123",
"notes": [
{
"text": "Prefers a warm toner, no fragrance.",
"created_at": "2026-05-14T11:02:00+01:00"
}
],
"allergies": [],
"upcoming_appointments": [
{
"appointment_id": "ap_90311245",
"start_at": "2026-10-16T14:30:00+01:00",
"services": [
"Haircut"
]
}
],
"past_appointments": [
{
"appointment_id": "ap_88120411",
"start_at": "2026-06-20T11:00:00+01:00",
"services": [
"Colour"
],
"status": "Completed"
}
]
} List services
readPOST https://cotlet.dev/api/v1/fresha/list_services
Returns your service menu grouped by category, with duration and price for each service. Prices are in your business currency. Use service_id from an item in find_available_slots and create_appointment.
Parameters
| Name | Type | Description |
|---|---|---|
| location_id | string | Only this location. Default: all locations. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/list_services \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("fresha", "list_services") const result = await cotlet.call('fresha', 'list_services'); cotlet call fresha list_services Example response
{
"services": [
{
"service_id": "sv_1203",
"name": "Haircut",
"category": "Hair",
"duration_minutes": 45,
"price": "45.00",
"currency": "GBP"
},
{
"service_id": "sv_1288",
"name": "Colour",
"category": "Hair",
"duration_minutes": 90,
"price": "85.00",
"currency": "GBP"
}
]
} List team members
readPOST https://cotlet.dev/api/v1/fresha/list_team_members
Lists the team members who can be booked, with their locations and the services each one offers. Use team_member_id from an item to filter list_appointments or to book with a specific person.
Parameters
| Name | Type | Description |
|---|---|---|
| location_id | string | Only this location. Default: all locations. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/list_team_members \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("fresha", "list_team_members") const result = await cotlet.call('fresha', 'list_team_members'); cotlet call fresha list_team_members Example response
{
"team_members": [
{
"team_member_id": "tm_5521",
"name": "Sam",
"locations": [
"loc_201"
],
"service_ids": [
"sv_1203",
"sv_1288"
]
}
]
} Get sales summary
readPOST https://cotlet.dev/api/v1/fresha/get_sales_summary
Returns the Sales summary report for the dates you give: items sold, sales, discounts and refunds. Set group_by to split the totals by payment method, discount name or discount type. Tips and service charges are not in this report, because it is built from sale items. Amounts are in your business currency.
Parameters
| Name | Type | Description |
|---|---|---|
| from required | date | First day. |
| to | date | Last day. Default: same as from. |
| group_by | enum | payment_method, discount_name or discount_type. Default: no grouping. |
| location_id | string | Only this location. Default: all locations. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/get_sales_summary \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"from":"2026-10-13","to":"2026-10-13","group_by":"payment_method","location_id":"loc_201"}' result = client.call("fresha", "get_sales_summary", {"from":"2026-10-13","to":"2026-10-13","group_by":"payment_method","location_id":"loc_201"}) const result = await cotlet.call('fresha', 'get_sales_summary', {"from":"2026-10-13","to":"2026-10-13","group_by":"payment_method","location_id":"loc_201"}); cotlet call fresha get_sales_summary --data '{"from":"2026-10-13","to":"2026-10-13","group_by":"payment_method","location_id":"loc_201"}' Example response
{
"from": "2026-10-10",
"to": "2026-10-10",
"currency": "GBP",
"groups": [
{
"payment_method": "Card",
"items_sold": 18,
"sales": "742.00",
"discounts": "30.00",
"refunds": "0.00"
},
{
"payment_method": "Cash",
"items_sold": 7,
"sales": "266.00",
"discounts": "10.00",
"refunds": "45.00"
}
],
"total": {
"items_sold": 25,
"sales": "1008.00",
"discounts": "40.00",
"refunds": "45.00"
}
} List payouts
readPOST https://cotlet.dev/api/v1/fresha/list_payouts
Lists transfers from your business wallet to your bank, newest first. Each has its date, amount, the fees Fresha deducted and the net amount. Scheduled and manual payouts are both included. It works only when Fresha Payments is on, and the account needs the Wallet and card processing permission.
Parameters
| Name | Type | Description |
|---|---|---|
| from | date | Start of the period. Default: 30 days ago. |
| to | date | End of the period. Default: today. |
| cursor | string | Next page cursor from the previous call. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/list_payouts \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("fresha", "list_payouts") const result = await cotlet.call('fresha', 'list_payouts'); cotlet call fresha list_payouts Example response
{
"payouts": [
{
"payout_id": "po_77120",
"type": "scheduled",
"date": "2026-09-29",
"amount": "840.00",
"fees": "12.60",
"net": "827.40",
"currency": "GBP"
},
{
"payout_id": "po_76988",
"type": "manual",
"date": "2026-09-22",
"amount": "300.00",
"fees": "0.50",
"net": "299.50",
"currency": "GBP"
}
],
"next_cursor": null
} POST https://cotlet.dev/api/v1/fresha/create_appointment
Books the services you list for a client, back to back, from start_at. The appointment starts as Booked. Without team_member_id it goes to the first team member who is free. Check the time with find_available_slots first; a time that is taken fails. The booking can reach the client. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| client_id required | string | Client ID from list_clients. |
| start_at required | datetime | ISO 8601 with time zone. |
| service_ids required | string[] | Services from list_services, in order. |
| team_member_id | string | Team member. Default: first available. |
| location_id | string | Only this location. Default: all locations. |
| note | string | Appointment note for your team. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/create_appointment \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"client_id":"cl_48213977","start_at":"2026-10-16T14:30:00+01:00","service_ids":["sv_1203"],"team_member_id":"tm_5521"}' result = client.call("fresha", "create_appointment", {"client_id":"cl_48213977","start_at":"2026-10-16T14:30:00+01:00","service_ids":["sv_1203"],"team_member_id":"tm_5521"}) const result = await cotlet.call('fresha', 'create_appointment', {"client_id":"cl_48213977","start_at":"2026-10-16T14:30:00+01:00","service_ids":["sv_1203"],"team_member_id":"tm_5521"}); cotlet call fresha create_appointment --data '{"client_id":"cl_48213977","start_at":"2026-10-16T14:30:00+01:00","service_ids":["sv_1203"],"team_member_id":"tm_5521"}' Example response
{
"appointment_id": "ap_90311245",
"status": "Booked",
"start_at": "2026-10-16T14:30:00+01:00",
"end_at": "2026-10-16T15:15:00+01:00",
"services": [
{
"service_id": "sv_1203",
"name": "Haircut",
"price": "45.00",
"currency": "GBP"
}
],
"team_member": "Sam"
} POST https://cotlet.dev/api/v1/fresha/reschedule_appointment
Moves one appointment to a new start time, keeping its services. Set team_member_id to hand it to someone else. Check the new time with find_available_slots first. The move can reach the client. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
| start_at required | datetime | New start, ISO 8601 with time zone. |
| team_member_id | string | New team member. Default: unchanged. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/reschedule_appointment \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"appointment_id":"ap_90311301","start_at":"2026-10-15T10:00:00+01:00","team_member_id":"tm_5530"}' result = client.call("fresha", "reschedule_appointment", {"appointment_id":"ap_90311301","start_at":"2026-10-15T10:00:00+01:00","team_member_id":"tm_5530"}) const result = await cotlet.call('fresha', 'reschedule_appointment', {"appointment_id":"ap_90311301","start_at":"2026-10-15T10:00:00+01:00","team_member_id":"tm_5530"}); cotlet call fresha reschedule_appointment --data '{"appointment_id":"ap_90311301","start_at":"2026-10-15T10:00:00+01:00","team_member_id":"tm_5530"}' Example response
{
"appointment_id": "ap_90311301",
"status": "Booked",
"start_at": "2026-10-16T10:00:00+01:00",
"end_at": "2026-10-16T10:45:00+01:00",
"team_member": "Sam"
} POST https://cotlet.dev/api/v1/fresha/cancel_appointment
Cancels one appointment. Fresha only cancels appointments that start in the future, so a past one fails; mark it as a no-show in the app instead. The reason must be one of the cancellation reasons you manage in Fresha. Your payment policy for the appointment applies as it does in the app. For a repeating series, scope picks this appointment or the whole series. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
| reason required | string | Name of one of your cancellation reasons. |
| notify_client | boolean | Send the client a cancellation message. Default: true. |
| scope | enum | this_appointment or whole_series, for repeating appointments. Default: this_appointment. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/cancel_appointment \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"appointment_id":"appointment_8c41d2","reason":"reason"}' result = client.call("fresha", "cancel_appointment", {"appointment_id":"appointment_8c41d2","reason":"reason"}) const result = await cotlet.call('fresha', 'cancel_appointment', {"appointment_id":"appointment_8c41d2","reason":"reason"}); cotlet call fresha cancel_appointment --data '{"appointment_id":"appointment_8c41d2","reason":"reason"}' Example response
{
"appointment_id": "ap_90311245",
"status": "Cancelled",
"reason": "Team member unwell",
"scope": "this_appointment",
"client_notified": true
} Add client
writePOST https://cotlet.dev/api/v1/fresha/add_client
Creates a client profile and returns its client_id, which you pass to create_appointment. It sends nothing to the client and reaches no one, so it runs without asking first. Search with list_clients first to avoid a duplicate profile.
Parameters
| Name | Type | Description |
|---|---|---|
| first_name required | string | First name. |
| last_name | string | Last name. |
| string | Email. | |
| phone | string | Mobile number with country code. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/add_client \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"first_name":"first name"}' result = client.call("fresha", "add_client", {"first_name":"first name"}) const result = await cotlet.call('fresha', 'add_client', {"first_name":"first name"}); cotlet call fresha add_client --data '{"first_name":"first name"}' Example response
{
"client_id": "cl_48213990",
"name": "Maya Patel",
"phone": "+44 7700 900456"
} Add client note
writePOST https://cotlet.dev/api/v1/fresha/add_client_note
Adds a simple note to a client profile. Notes are private: only your team sees them, never the client. Fresha cannot recover a deleted note, so the agent adds notes and never deletes them. It reaches no one, so it runs without asking first.
Parameters
| Name | Type | Description |
|---|---|---|
| client_id required | string | Client ID from list_clients. |
| text required | string | Note text. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/add_client_note \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"client_id":"client_8c41d2","text":"text"}' result = client.call("fresha", "add_client_note", {"client_id":"client_8c41d2","text":"text"}) const result = await cotlet.call('fresha', 'add_client_note', {"client_id":"client_8c41d2","text":"text"}); cotlet call fresha add_client_note --data '{"client_id":"client_8c41d2","text":"text"}' Example response
{
"client_id": "cl_48213977",
"note_id": "nt_5521",
"created_at": "2026-10-11T09:12:00+01:00"
} Add blocked time
writePOST https://cotlet.dev/api/v1/fresha/add_blocked_time
Blocks a time range in one team member's calendar, so no one can book it. Use title for a reason such as one of your blocked time types, and description for a note your team sees. It reaches no client and is removed in Fresha in one step, so it runs without asking first.
Parameters
| Name | Type | Description |
|---|---|---|
| team_member_id required | string | Team member from list_team_members. |
| start_at required | datetime | ISO 8601 with time zone. |
| end_at required | datetime | ISO 8601 with time zone. |
| title | string | Reason, e.g. one of your blocked time types. |
| description | string | Note your team sees on the block. |
Request
curl -X POST https://cotlet.dev/api/v1/fresha/add_blocked_time \
-H "Authorization: Bearer $COTLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"team_member_id":"team_member_8c41d2","start_at":"2026-10-01T09:00:00Z","end_at":"2026-10-01T09:00:00Z"}' result = client.call("fresha", "add_blocked_time", {"team_member_id":"team_member_8c41d2","start_at":"2026-10-01T09:00:00Z","end_at":"2026-10-01T09:00:00Z"}) const result = await cotlet.call('fresha', 'add_blocked_time', {"team_member_id":"team_member_8c41d2","start_at":"2026-10-01T09:00:00Z","end_at":"2026-10-01T09:00:00Z"}); cotlet call fresha add_blocked_time --data '{"team_member_id":"team_member_8c41d2","start_at":"2026-10-01T09:00:00Z","end_at":"2026-10-01T09:00:00Z"}' Example response
{
"blocked_time_id": "bt_3302",
"team_member": "Sam",
"start_at": "2026-10-14T13:00:00+01:00",
"end_at": "2026-10-14T14:00:00+01:00",
"title": "Training"
}