Info
Welcome to the generated API reference. Get Postman Collection
This API is being developed constantly with more endpoints being added regularly.
Authentication
All endpoints require authentication via the Authorization: Bearer {access_token}
header. There are 2 ways to get the Access Token:
- The user creates a token themselves directly in EasyPractice. This requires no set up upfront and is recommended for small/test environments where you will only need data access for one or two users.
- OAuth2 flow. This requires you to perform additional actions, such as redirecting a user from your app to EasyPractice and then exchanging the received authorization code for an Access Token. This is a more user-friendly approach and will work great for multi-user platforms.
Authentication - Scopes
Scopes constrains the endpoints to which a client has access. Once you create a Personal Access Token, you cannot redefine the scopes.
Note: Most of the scopes are not required until 1st of November 2021 in order to allow existing integrations time to migrate to a scope-based authentication. On the 1st of November 2021 the scope requirements will be enforced on every route that has scope(s) documented as a requirement.
Currently the following scopes are available:
Scope | Description |
---|---|
clients-read | Ability to view clients |
clients-readwrite | Ability to view and edit clients |
journals-read | Ability to view client journals |
journals-readwrite | Ability to view and edit client journals |
journal-files-read | Ability to view and download client journal files |
calendars-read | Ability to view calendars and appointments |
calendars-readwrite | Ability to view and edit calendars and appointments |
invoices-read | Ability to view invoices |
invoices-readwrite | Ability to view and edit invoices |
easypay-read | Ability to view information about online payments |
#Authentication - Personal Access Tokens
- Log in to your EasyPractice account (or create a new account)
- Go to the Apps page and activate the API app.
- Go to the API Settings page
- In the Personal Access Tokens section click on the Create New Token button to generate a new token. Remember to choose the scopes you require.
- Copy the new generated token. You will NOT be able to view it again, so keep it safe. In case you lose it, you can generate as many new tokens as you'd like.
- Add an
Authorization
header to your requests with the value ofBearer {token}
where {token} is your token you copied earlier.
#Authentication - OAuth2 We also support the standard OAuth2 flow for authenticating requests. Your app will be able to "Request access to EasyPractice", where the user will be able to either Authorize or Deny the request. This is a much more user-friendly approach, but requires more set up in advance.
Step 1 - Creating a OAuth2 Client
In order to authenticate with EasyPractice, you'll need to set up a new Client so we can identify who's accessing the API, as well as to help the user know what app is requiring their EasyPractice data.
- Log in to your EasyPractice account (or create a new account)
- Go to the Apps page and activate the API app.
- Go to the API Settings page
- In the OAuth Clients section click on the Create New Client button to set up a new Client. The "Name" will be visible to your users when they try to connect to EasyPractice. The "Redirect URL" is your publicly accessible website address, where we'll send the user back after they have accepted or denied the request to connect.
- Once created, note down the Client's ID and the Secret. You will need them later.
Step 2 - Initiating the authorization request
To begin the OAuth2 authorization flow, you'll need to redirect your user to a special EasyPractice page with a few query parameters.
Example: https://system.easypractice.net/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&response_type=code&scope[]=journals-readwrite&scope[]=calendars-readwrite&state=STATE
HTTP Request
GET oauth/authorize
Query Parameters
Parameter | Type | Status | Description |
---|---|---|---|
client_id | integer | required | The OAuth Client's ID that you have set up earlier. |
redirect_uri | string | required | The OAuth Client's Redirect URL that you have set up earlier. |
response_type | string | required | Always "code". |
scope | string | optional | A string or array of supported scopes. |
state | string | optional | custom string (usually a hash) that you keep on your user's session. This is not required, but it will be returned back to you after authorization to help you identify the user session if needed. |
Once you redirect the user to the above URL, they will be prompted that your app wants to connect to their EasyPractice account. The user will see the list of scopes requested, so they know what data will be shared with your app.
They can either Approve (Authorize) or Deny the request. Either way, they will be redirected back to the REDIRECT_URL that you have supplied, along with an Authorization Code that you will need to exchange for a valid Access Token.
Step 3 - Converting Authorization Code to Access Token
Example Access Token request:
{
"grant_type": "authorization_code",
"client_id": 5,
"client_secret": "N7ecQ5dxS4wYXyEi2PCon0ldF5PfnoSmCxv1J0Or",
"redirect_uri": "https://example.com/callback",
"code": "def50200d2712ea33c5a36c273505502a785d5aa8fe0...",
"scope": ["journals-readwrite", "calendars-readwrite"]
}
Once the user has been redirected back, you'll receive a few query parameters, one of which will be a code
parameter.
HTTP Request
POST oauth/token
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
grant_type | string | required | Always "authorization_code". |
client_id | integer | required | The OAuth Client's ID that you have set up earlier. |
client_secret | string | required | The OAuth Client's Secret that you have set up earlier. |
redirect_uri | string | required | The OAuth Client's Redirect URL that you have set up earlier. |
code | string | required | The code parameter value that you have received from the authorization request. |
Example Access Token response:
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "eyJ0eXAiOiJKV1QiLCJhb...",
"refresh_token": "def502005caf0df4486d4e7..."
}
Response data values explained:
-
"token_type" - this will always be "Bearer". It means that it's a Bearer token, and in order to use it you just have to set an
Authorization: Bearer {access_token}
header to every API request you make. - "expires_in" - number of seconds before this token expires. Currently the default is one year.
-
"access_token" - the Access Token. You can store it in your database for the current user and can use this token to access the user's data from EasyPractice using this API. You can now access the user's data by adding a
Authorization: Bearer {token}
header to every API request, where {token} is this Access Token. - "refresh_token" - the Refresh Token. You can store it in your database for the current user and use this Refresh Token to fetch a brand new Access Token without any user input. See Step 4.
Step 4 (optional) - Refreshing Access Tokens
Access Tokens have an expiry date. If it's not refreshed, the user will have to re-authorize your app again (Step 2). In order to fetch a new Access Token by using a Refresh Token, you'll need to make a POST request to https://system.easypractice.net/oauth/token
.
Example Refresh Token request:
{
"grant_type": "refresh_token",
"refresh_token": "def502005caf0df4486d4e7cbad6159ee5...",
"client_id": 5,
"client_secret": "N7ecQ5dxS4wYXyEi2PCon0ldF5PfnoSmCxv1J0Or",
"scope": ["journals-readwrite", "calendars-readwrite"]
}
HTTP Request
POST oauth/token
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
grant_type | string | required | Always "refresh_token" when refreshing an access token. |
refresh_token | string | required | The Refresh Token that you have received before in Step 3. |
client_id | integer | required | The OAuth Client's ID that you have set up earlier. |
client_secret | string | required | The OAuth Client's Secret that you have set up earlier. |
scope | string | optional | A string or array of supported scopes. |
Example Refresh Token response:
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiI...",
"refresh_token": "def50200734e746461d1d5a84420c4bab..."
}
Response data values explained:
-
"token_type" - this will always be "Bearer". It means that it's a Bearer token, and in order to use it you just have to set an
Authorization: Bearer {access_token}
header to every API request you make. - "expires_in" - number of seconds before this token expires. Currently the default is one year.
- "access_token" - the Access Token. You can store it in your database for the current user and can use this token to access the user's data from EasyPractice using this API.
- "refresh_token" - the Refresh Token. You can store it in your database for the current user and use this Refresh Token to fetch a brand new Access Token without any user input. See Step 4.
Support
If you have any questions about setting up OAuth2 flow with our API, please get in touch with us at api@easypractice.net.
Bookings
List bookings
Requires authentication
Returns all of user's bookings. Use the filter options provided to narrow down the results. For example: GET api/v1/bookings?start=2019-06-15&order_by_date=asc
Scope : bookings-read
or bookings-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/bookings", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"start" => "2019-03-25",
"end" => "2019-03-25",
"client_id" => "54347",
"calendar_id" => "54347",
"product_id" => "54347",
"employee_id" => "23",
"status" => "absent",
"order_by_date" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/bookings" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/bookings");
let params = {
"start": "2019-03-25",
"end": "2019-03-25",
"client_id": "54347",
"calendar_id": "54347",
"product_id": "54347",
"employee_id": "23",
"status": "absent",
"order_by_date": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"start": "2019-06-15T16:25:00+02:00",
"start_formatted": "Saturday 15 June 2019, 16:25",
"end": "2019-06-15T17:15:00+02:00",
"end_formatted": "Saturday 15 June 2019, 17:15",
"calendar_id": 167,
"calendar_name": "Main calendar",
"employee_id": 23,
"employee_name": "John Doe",
"type": "client_booking",
"status": "finished",
"heading": "",
"notes": "First time for this client",
"recurring": null,
"until": null,
"client_id": 1348,
"client_name": "John Smith",
"notify_email": 0,
"notify_phone": 0,
"created_via_api": true,
"products": [
{
"id": 125,
"name": "Main service"
}
],
"updated_at": "2022-06-15T17:15:00+02:00",
"created_at": "2022-06-15T17:15:00+02:00"
},
{
"id": 2,
"start": "2019-09-30T17:55:00+02:00",
"start_formatted": "Monday 30 September 2019, 17:55",
"end": "2019-09-30T21:30:00+02:00",
"end_formatted": "Monday 30 September 2019, 21:30",
"calendar_id": 173,
"calendar_name": "201",
"employee_id": 23,
"employee_name": "John Doe",
"type": "Client appointment",
"status": "finished",
"heading": "",
"notes": "First time for this client",
"recurring": null,
"until": null,
"invoice_id": 1239,
"invoice_status": "payed",
"client_id": 648,
"client_name": "Mary Williams",
"notify_email": 1,
"notify_phone": 0,
"created_via_api": false,
"products": [
{
"id": 125,
"name": "Main service",
"addons": [
{
"id": 434,
"name": "Extra time"
}
]
},
{
"id": 264,
"name": "Other service"
}
],
"updated_at": "2022-06-15T17:15:00+02:00",
"created_at": "2022-06-15T17:15:00+02:00"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/bookings
Query Parameters
Parameter | Status | Description |
---|---|---|
start |
optional | Return only the bookings scheduled on or after the given date. |
end |
optional | Return only the bookings scheduled on or before the given date. |
client_id |
optional | Return only bookings belonging to this client ID. |
calendar_id |
optional | Return only bookings belonging to this calendar ID. |
product_id |
optional | Return only bookings belonging to this product ID. |
employee_id |
optional | Return only bookings belonging to this employee ID. |
status |
optional | Return only booking with the given status (must have "Appointment Status" app active). |
order_by_date |
optional | =[asc|desc] Order results by date. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Create booking
Requires authentication
Creates a new booking with the given data.
Scope : bookings-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/bookings", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"start" => "2019-03-25T10:00:00+02:00",
"end" => "2019-03-25T10:00:00+02:00",
"calendar_id" => 54347,
"employee_id" => 23,
"type" => "client_booking",
"status" => "not_started",
"heading" => "New skill course",
"notes" => "First time for this client",
"recurring" => "daily",
"until" => "2019-03-28",
"client_id" => 1594,
"send_receipt" => true,
"send_phone_receipt" => false,
"notify_email" => true,
"notify_phone" => false,
"products" => [
[
"id" => 1574,
],
[
"id" => 2164,
"addons" => [
[
"id" => 434,
],
],
],
],
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/bookings" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"start":"2019-03-25T10:00:00+02:00","end":"2019-03-25T10:00:00+02:00","calendar_id":54347,"employee_id":23,"type":"client_booking","status":"not_started","heading":"New skill course","notes":"First time for this client","recurring":"daily","until":"2019-03-28","client_id":1594,"send_receipt":1,"send_phone_receipt":false,"notify_email":1,"notify_phone":false,"products":[{"id":1574},{"id":2164,"addons":[{"id":434}]}]}'
const url = new URL("http://localhost/api/v1/bookings");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"start": "2019-03-25T10:00:00+02:00",
"end": "2019-03-25T10:00:00+02:00",
"calendar_id": 54347,
"employee_id": 23,
"type": "client_booking",
"status": "not_started",
"heading": "New skill course",
"notes": "First time for this client",
"recurring": "daily",
"until": "2019-03-28",
"client_id": 1594,
"send_receipt": 1,
"send_phone_receipt": false,
"notify_email": 1,
"notify_phone": false,
"products": [
{
"id": 1574
},
{
"id": 2164,
"addons": [
{
"id": 434
}
]
}
]
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (201):
{
"message": "Created",
"data": {
"id": 1,
"start": "2019-06-15T16:25:00+02:00",
"start_formatted": "Saturday 15 June 2019, 16:25",
"end": "2019-06-15T17:15:00+02:00",
"end_formatted": "Saturday 15 June 2019, 17:15",
"calendar_id": 167,
"calendar_name": "Main calendar",
"employee_id": 23,
"employee_name": "John Doe",
"type": "client_booking",
"status": "finished",
"heading": "",
"notes": "First time for this client",
"recurring": null,
"until": null,
"invoice_id": null,
"invoice_status": null,
"client_id": 1348,
"client_name": "John Smith",
"notify_email": 0,
"notify_phone": 0,
"products": [
{
"id": 125,
"name": "Main service",
"addons": [
{
"id": 434,
"name": "Extra time"
}
]
}
],
"updated_at": "2022-06-15T17:15:00+02:00",
"created_at": "2022-06-15T17:15:00+02:00"
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"end": [
"The End time must be after the Start time."
]
}
}
HTTP Request
POST api/v1/bookings
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
start |
date_format:Y-m-d\TH:i:sP | required | The start date for the appointment in the full ISO 8601 format (e.g. 2019-10-30T08:50:31+00:00). |
end |
date_format:Y-m-d\TH:i:sP | required | The end date for the appointment in the full ISO 8601 format (e.g. 2019-10-30T08:50:31+00:00). |
calendar_id |
integer | required | The calendar ID associated to the appointment. |
employee_id |
integer | optional | The user employee ID associated to the appointment. |
type |
string | required | The appointment type =['other_booking', 'close_online_booking', 'client_booking']. |
status |
string | optional | The status of the appointment. Must have the "Appointment Status" app enabled. |
heading |
string | optional | The appointment title (It's required only for 'other_booking' type). |
notes |
string | optional | The appointment additional notes. |
recurring |
string | optional | How often this appointment is repeated =[false, 'daily', 'weekly', 'every_other_week'] (It's required for 'other_booking' and 'close_online_booking' types). |
until |
date_format:Y-m-d | optional | Until what date this appointment is repeated (It's required if recurring field is different than false). |
client_id |
integer | optional | The client ID associated to the appointment (It's required for 'client_booking' type). |
send_receipt |
boolean | optional | Should we send the confirmation email straight away? Client must have a valid email address. |
send_phone_receipt |
boolean | optional | Should we send the confirmation SMS straight away? Client must have a valid phone number. |
notify_email |
boolean | optional | Should we send the reminder email to the client the day before the appointment. |
notify_phone |
boolean | optional | Should we send the reminder SMS to the client the day before the appointment. |
products |
array | optional | The products associated to the appointment (It's required for 'client_booking' type). |
Create multiple bookings
Requires authentication
Create multiple (up to 100) bookings with a single request
The root-level "bookings" attribute must be used to provide an array of bookings to be created.
Each booking object in the array has the same rules as when creating a single booking via the "Create booking" endpoint. If there's at least one booking with a validation error, none will be created.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/bookings/bulk", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"bookings" => [
[
"start" => "2019-03-25T10:00:00+02:00",
"end" => "2019-03-25T10:00:00+02:00",
"calendar_id" => 54347,
"employee_id" => 23,
"type" => "client_booking",
"status" => "not_started",
"heading" => "New skill course",
"notes" => "First time for this client",
"recurring" => "daily",
"until" => "2019-03-28",
"client_id" => 1594,
"send_receipt" => true,
"send_phone_receipt" => false,
"notify_email" => true,
"notify_phone" => false,
"products" => [
[
"id" => 1574,
],
[
"id" => 2164,
"addons" => [
[
"id" => 434,
],
],
],
],
],
],
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/bookings/bulk" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"bookings":[{"start":"2019-03-25T10:00:00+02:00","end":"2019-03-25T10:00:00+02:00","calendar_id":54347,"employee_id":23,"type":"client_booking","status":"not_started","heading":"New skill course","notes":"First time for this client","recurring":"daily","until":"2019-03-28","client_id":1594,"send_receipt":1,"send_phone_receipt":false,"notify_email":1,"notify_phone":false,"products":[{"id":1574},{"id":2164,"addons":[{"id":434}]}]}]}'
const url = new URL("http://localhost/api/v1/bookings/bulk");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"bookings": [
{
"start": "2019-03-25T10:00:00+02:00",
"end": "2019-03-25T10:00:00+02:00",
"calendar_id": 54347,
"employee_id": 23,
"type": "client_booking",
"status": "not_started",
"heading": "New skill course",
"notes": "First time for this client",
"recurring": "daily",
"until": "2019-03-28",
"client_id": 1594,
"send_receipt": 1,
"send_phone_receipt": false,
"notify_email": 1,
"notify_phone": false,
"products": [
{
"id": 1574
},
{
"id": 2164,
"addons": [
{
"id": 434
}
]
}
]
}
]
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (201):
{
"message": "Created",
"data": [
{
"id": 1,
"start": "2019-06-15T16:25:00+02:00",
"start_formatted": "Saturday 15 June 2019, 16:25",
"end": "2019-06-15T17:15:00+02:00",
"end_formatted": "Saturday 15 June 2019, 17:15",
"calendar_id": 167,
"calendar_name": "Main calendar",
"employee_id": 23,
"employee_name": "John Doe",
"type": "client_booking",
"status": "finished",
"heading": "",
"notes": "First time for this client",
"recurring": null,
"until": null,
"invoice_id": null,
"invoice_status": null,
"client_id": 1348,
"client_name": "John Smith",
"notify_email": 0,
"notify_phone": 0,
"products": [
{
"id": 125,
"name": "Main service",
"addons": [
{
"id": 434,
"name": "Extra time"
}
]
}
],
"updated_at": "2022-06-15T17:15:00+02:00",
"created_at": "2022-06-15T17:15:00+02:00"
}
]
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"bookings.0.end": [
"The End time must be after the Start time."
]
}
}
HTTP Request
POST api/v1/bookings/bulk
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
bookings.0.start |
date_format:Y-m-d\TH:i:sP | required | The start date for the appointment in the full ISO 8601 format (e.g. 2019-10-30T08:50:31+00:00). |
bookings.0.end |
date_format:Y-m-d\TH:i:sP | required | The end date for the appointment in the full ISO 8601 format (e.g. 2019-10-30T08:50:31+00:00). |
bookings.0.calendar_id |
integer | required | The calendar ID associated to the appointment. |
bookings.0.employee_id |
integer | optional | The user employee ID associated to the appointment. |
bookings.0.type |
string | required | The appointment type =['other_booking', 'close_online_booking', 'client_booking']. |
bookings.0.status |
string | optional | The status of the appointment. Must have the "Appointment Status" app enabled. |
bookings.0.heading |
string | optional | The appointment title (It's required only for 'other_booking' type). |
bookings.0.notes |
string | optional | The appointment additional notes. |
bookings.0.recurring |
string | optional | How often this appointment is repeated =[false, 'daily', 'weekly', 'every_other_week'] (It's required for 'other_booking' and 'close_online_booking' types). |
bookings.0.until |
date_format:Y-m-d | optional | Until what date this appointment is repeated (It's required if recurring field is different than false). |
bookings.0.client_id |
integer | optional | The client ID associated to the appointment (It's required for 'client_booking' type). |
bookings.0.send_receipt |
boolean | optional | Should we send the confirmation email straight away? Client must have a valid email address. |
bookings.0.send_phone_receipt |
boolean | optional | Should we send the confirmation SMS straight away? Client must have a valid phone number. |
bookings.0.notify_email |
boolean | optional | Should we send the reminder email to the client the day before the appointment. |
bookings.0.notify_phone |
boolean | optional | Should we send the reminder SMS to the client the day before the appointment. |
bookings.0.products |
array | optional | The products associated to the appointment (It's required for 'client_booking' type). |
Show booking
Requires authentication
Returns the booking data for a given ID.
Scope : bookings-read
or bookings-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/bookings/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/bookings/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/bookings/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"start": "2019-06-15T16:25:00+02:00",
"start_formatted": "Saturday 15 June 2019, 16:25",
"end": "2019-06-15T17:15:00+02:00",
"end_formatted": "Saturday 15 June 2019, 17:15",
"calendar_id": 167,
"calendar_name": "Main calendar",
"employee_id": 23,
"employee_name": "John Doe",
"type": "client_booking",
"status": "finished",
"heading": "",
"notes": "First time for this client",
"recurring": null,
"until": null,
"invoice_id": 1239,
"invoice_status": "payed",
"client_id": 1348,
"client_name": "John Smith",
"notify_email": 0,
"notify_phone": 0,
"created_via_api": false,
"products": [
{
"id": 125,
"name": "Main service",
"addons": [
{
"id": 434,
"name": "Extra time"
}
]
}
],
"updated_at": "2022-06-15T17:15:00+02:00",
"created_at": "2022-06-15T17:15:00+02:00"
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/bookings/{booking}
Update booking
Requires authentication
Updates the booking.
Scope : bookings-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/bookings/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"start" => "2019-03-25T10:00:00+02:00",
"end" => "2019-03-25T10:00:00+02:00",
"calendar_id" => 54347,
"employee_id" => 23,
"status" => "finished",
"heading" => "New skill course",
"notes" => "First time for this client",
"recurring" => "daily",
"until" => "2019-03-28",
"client_id" => 1594,
"notify_email" => true,
"notify_phone" => false,
"products" => [
[
"id" => 1574,
],
[
"id" => 2164,
"addons" => [
[
"id" => 434,
],
],
],
],
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/bookings/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"start":"2019-03-25T10:00:00+02:00","end":"2019-03-25T10:00:00+02:00","calendar_id":54347,"employee_id":23,"status":"finished","heading":"New skill course","notes":"First time for this client","recurring":"daily","until":"2019-03-28","client_id":1594,"notify_email":1,"notify_phone":false,"products":[{"id":1574},{"id":2164,"addons":[{"id":434}]}]}'
const url = new URL("http://localhost/api/v1/bookings/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"start": "2019-03-25T10:00:00+02:00",
"end": "2019-03-25T10:00:00+02:00",
"calendar_id": 54347,
"employee_id": 23,
"status": "finished",
"heading": "New skill course",
"notes": "First time for this client",
"recurring": "daily",
"until": "2019-03-28",
"client_id": 1594,
"notify_email": 1,
"notify_phone": false,
"products": [
{
"id": 1574
},
{
"id": 2164,
"addons": [
{
"id": 434
}
]
}
]
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Updated",
"data": {
"id": 1,
"start": "2019-06-15T16:25:00+02:00",
"start_formatted": "Saturday 15 June 2019, 16:25",
"end": "2019-06-15T17:15:00+02:00",
"end_formatted": "Saturday 15 June 2019, 17:15",
"calendar_id": 167,
"calendar_name": "Main calendar",
"employee_id": 23,
"employee_name": "John Doe",
"type": "client_booking",
"status": "finished",
"heading": "",
"notes": "First time for this client",
"recurring": null,
"until": null,
"invoice_id": null,
"invoice_status": null,
"client_id": 1348,
"client_name": "John Smith",
"notify_email": 0,
"notify_phone": 0,
"products": [
{
"id": 125,
"name": "Main service",
"addons": [
{
"id": 434,
"name": "Extra time"
}
]
}
],
"updated_at": "2022-06-15T17:15:00+02:00",
"created_at": "2022-06-15T17:15:00+02:00"
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"name": [
"The Name field is required."
]
}
}
HTTP Request
PUT api/v1/bookings/{booking}
PATCH api/v1/bookings/{booking}
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
start |
date_format:Y-m-d\TH:i:sP | optional | The start date for the appointment in the full ISO 8601 format (e.g. 2019-10-30T08:50:31+00:00). |
end |
date_format:Y-m-d\TH:i:sP | optional | The end date for the appointment in the full ISO 8601 format (e.g. 2019-10-30T08:50:31+00:00). |
calendar_id |
integer | optional | The calendar ID associated to the appointment. |
employee_id |
integer | optional | The user employee ID associated to the appointment. |
status |
string | optional | The status of the appointment. Must have the "Appointment Status" app enabled. |
heading |
string | optional | The appointment heading for 'other_booking' type. |
notes |
string | optional | The appointment additional notes. |
recurring |
string | optional | How often this appointment is repeated =[false, 'daily', 'weekly', 'every_other_week'] (It's required for 'other_booking' and 'close_online_booking' types). |
until |
date_format:Y-m-d | optional | Until what date this appointment is repeated (It's required if recurring field is different than false). |
client_id |
integer | optional | The client ID associated to the appointment. |
notify_email |
boolean | optional | Should we send the reminder email to the client the day before the appointment. |
notify_phone |
boolean | optional | Should we send the reminder SMS to the client the day before the appointment. |
products |
array | optional | The products associated to the appointment. |
Delete booking
Requires authentication
Deletes the booking.
Scope : bookings-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/bookings/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "http://localhost/api/v1/bookings/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/bookings/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "DELETE",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Deleted"
}
HTTP Request
DELETE api/v1/bookings/{booking}
Calendar Opening Times
Show Opening Times
Requires authentication
Returns opening times for a Calendar. For example: GET api/v1/calendars/1/opening-times
Scope: calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/calendars/1/opening-times", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/calendars/1/opening-times" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/calendars/1/opening-times");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": {
"id": 1,
"user_id": 1,
"calendar_id": 1,
"show_in_calendar": true,
"times": {
"monday_start": "09:00",
"monday_end": "17:00",
"monday_closed": false,
"tuesday_start": "09:00",
"tuesday_end": "17:00",
"tuesday_closed": false,
"wednesday_start": "09:00",
"wednesday_end": "17:00",
"wednesday_closed": false,
"thursday_start": "09:00",
"thursday_end": "17:00",
"thursday_closed": false,
"friday_start": "09:00",
"friday_end": "17:00",
"friday_closed": false,
"saturday_start": "09:00",
"saturday_end": "17:00",
"saturday_closed": true,
"sunday_start": "09:00",
"sunday_end": "17:00",
"sunday_closed": true
}
}
}
HTTP Request
GET api/v1/calendars/{calendar}/opening-times
Update Opening Times
Requires authentication
Updates an Opening Times entry for a given calendar. For example: PUT api/v1/calendars/1/opening-times
Scope: calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/calendars/1/opening-times", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"show_in_calendar" => true,
"times" => [
"monday_start" => "09:00",
"monday_end" => "17:00",
"monday_closed" => false,
"tuesday_start" => "09:00",
"tuesday_end" => "17:00",
"tuesday_closed" => false,
"wednesday_start" => "09:00",
"wednesday_end" => "17:00",
"wednesday_closed" => false,
"thursday_start" => "09:00",
"thursday_end" => "17:00",
"thursday_closed" => false,
"friday_start" => "09:00",
"friday_end" => "17:00",
"friday_closed" => false,
"saturday_start" => "09:00",
"saturday_end" => "17:00",
"saturday_closed" => false,
"sunday_start" => "09:00",
"sunday_end" => "17:00",
"sunday_closed" => false,
],
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/calendars/1/opening-times" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"show_in_calendar":1,"times":{"monday_start":"09:00","monday_end":"17:00","monday_closed":false,"tuesday_start":"09:00","tuesday_end":"17:00","tuesday_closed":false,"wednesday_start":"09:00","wednesday_end":"17:00","wednesday_closed":false,"thursday_start":"09:00","thursday_end":"17:00","thursday_closed":false,"friday_start":"09:00","friday_end":"17:00","friday_closed":false,"saturday_start":"09:00","saturday_end":"17:00","saturday_closed":false,"sunday_start":"09:00","sunday_end":"17:00","sunday_closed":false}}'
const url = new URL("http://localhost/api/v1/calendars/1/opening-times");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"show_in_calendar": 1,
"times": {
"monday_start": "09:00",
"monday_end": "17:00",
"monday_closed": false,
"tuesday_start": "09:00",
"tuesday_end": "17:00",
"tuesday_closed": false,
"wednesday_start": "09:00",
"wednesday_end": "17:00",
"wednesday_closed": false,
"thursday_start": "09:00",
"thursday_end": "17:00",
"thursday_closed": false,
"friday_start": "09:00",
"friday_end": "17:00",
"friday_closed": false,
"saturday_start": "09:00",
"saturday_end": "17:00",
"saturday_closed": false,
"sunday_start": "09:00",
"sunday_end": "17:00",
"sunday_closed": false
}
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Your opening hours were updated",
"data": {
"id": 1,
"user_id": 1,
"calendar_id": 1,
"show_in_calendar": true,
"times": {
"monday_start": "09:00",
"monday_end": "17:00",
"monday_closed": false,
"tuesday_start": "09:00",
"tuesday_end": "17:00",
"tuesday_closed": false,
"wednesday_start": "09:00",
"wednesday_end": "17:00",
"wednesday_closed": false,
"thursday_start": "09:00",
"thursday_end": "17:00",
"thursday_closed": false,
"friday_start": "09:00",
"friday_end": "17:00",
"friday_closed": false,
"saturday_start": "09:00",
"saturday_end": "17:00",
"saturday_closed": true,
"sunday_start": "09:00",
"sunday_end": "17:00",
"sunday_closed": true
}
}
}
HTTP Request
PUT api/v1/calendars/{calendar}/opening-times
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
show_in_calendar |
boolean | required | The flag for whether this opening time is displayed on its calendar. |
times.monday_start |
date_format:H:i | required | Monday Start time. |
times.monday_end |
date_format:H:i | required | Monday End time. |
times.monday_closed |
boolean | required | Monday Closed. |
times.tuesday_start |
date_format:H:i | required | Tuesday Start time. |
times.tuesday_end |
date_format:H:i | required | Tuesday End time. |
times.tuesday_closed |
boolean | required | Tuesday Closed. |
times.wednesday_start |
date_format:H:i | required | Wednesday Start time. |
times.wednesday_end |
date_format:H:i | required | Wednesday End time. |
times.wednesday_closed |
boolean | required | Wednesday Closed. |
times.thursday_start |
date_format:H:i | required | Thursday Start time. |
times.thursday_end |
date_format:H:i | required | Thursday End time. |
times.thursday_closed |
boolean | required | Thursday Closed. |
times.friday_start |
date_format:H:i | required | Friday Start time. |
times.friday_end |
date_format:H:i | required | Friday End time. |
times.friday_closed |
boolean | required | Friday Closed. |
times.saturday_start |
date_format:H:i | required | Saturday Start time. |
times.saturday_end |
date_format:H:i | required | Saturday End time. |
times.saturday_closed |
boolean | required | Saturday Closed. |
times.sunday_start |
date_format:H:i | required | Sunday Start time. |
times.sunday_end |
date_format:H:i | required | Sunday End time. |
times.sunday_closed |
boolean | required | Sunday Closed. |
Calendar Pauses
List Pauses
Requires authentication
Returns all of user's Pauses per each Calendar. For example: GET api/v1/calendars/1/pauses
Scope: calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/calendars/1/pauses", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/calendars/1/pauses" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/calendars/1/pauses");
let params = {
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"calendar_id": 1,
"weekday": null,
"date": "2020-07-03",
"start_time": "08:00",
"end_time": "20:00"
},
{
"id": 2,
"calendar_id": 1,
"weekday": 3,
"date": null,
"start_time": "12:00",
"end_time": "12:30"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/calendars/{calendar}/pauses
Query Parameters
Parameter | Status | Description |
---|---|---|
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Create a Pause
Requires authentication
Create a new Pause entry. For example: POST api/v1/calendars/1/pauses
Scope: calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/calendars/1/pauses", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"weekday" => 1,
"date" => "2020-07-03",
"start_time" => "08:00",
"end_time" => "22:00",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/calendars/1/pauses" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"weekday":1,"date":"2020-07-03","start_time":"08:00","end_time":"22:00"}'
const url = new URL("http://localhost/api/v1/calendars/1/pauses");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"weekday": 1,
"date": "2020-07-03",
"start_time": "08:00",
"end_time": "22:00"
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Pause Saved",
"data": {
"id": 1,
"calendar_id": 1,
"weekday": null,
"date": "2020-07-03",
"starttime": "08:00",
"endtime": "22:00"
}
}
HTTP Request
POST api/v1/calendars/{calendar}/pauses
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
weekday |
integer | optional | The number of the day of the week (eg: 1 - Monday, 7 - Sunday) |
date |
date_format:Y-m-d | optional | The start date of a week long Pause. |
start_time |
date_format:H:i | required | The start time of the Pause |
end_time |
date_format:H:i | required | Th end time of the Pause |
Show Pause
Requires authentication
Returns a Pause. For example: GET api/v1/calendars/1/pauses/1
Scope: calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/calendars/1/pauses/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/calendars/1/pauses/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/calendars/1/pauses/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"calendar_id": 1,
"weekday": null,
"date": "2020-07-03",
"start_time": "08:00",
"end_time": "20:00"
}
HTTP Request
GET api/v1/calendars/{calendar}/pauses/{pause}
Update Pause
Requires authentication
Updates a Pause entry for a given calendar. For example: PUT api/v1/calendars/1/pauses/1
Scope: calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/calendars/1/pauses/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"weekday" => 1,
"date" => "2020-07-03",
"start_time" => "08:00",
"end_time" => "22:00",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/calendars/1/pauses/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"weekday":1,"date":"2020-07-03","start_time":"08:00","end_time":"22:00"}'
const url = new URL("http://localhost/api/v1/calendars/1/pauses/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"weekday": 1,
"date": "2020-07-03",
"start_time": "08:00",
"end_time": "22:00"
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Pause Saved",
"data": {
"id": 1,
"calendar_id": 1,
"weekday": null,
"date": "2020-07-03",
"starttime": "08:00",
"endtime": "22:00"
}
}
HTTP Request
PUT api/v1/calendars/{calendar}/pauses/{pause}
PATCH api/v1/calendars/{calendar}/pauses/{pause}
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
weekday |
integer | optional | The number of the day of the week (eg: 1 - Monday, 7 - Sunday) |
date |
date_format:Y-m-d | optional | The start date of a week long Pause. |
start_time |
date_format:H:i | required | The start time of the Pause |
end_time |
date_format:H:i | required | Th end time of the Pause |
Delete Pause
Requires authentication
Deletes the Pause. For example: DELETE api/v1/calendars/1/pauses/1
Scope: calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/calendars/1/pauses/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "http://localhost/api/v1/calendars/1/pauses/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/calendars/1/pauses/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "DELETE",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Deleted"
}
HTTP Request
DELETE api/v1/calendars/{calendar}/pauses/{pause}
Calendars
List calendars
Requires authentication
Returns all of user's calendars. Use the filter options provided to narrow down the results. For example: GET api/v1/calendars?order_by_name=asc
Scope : calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/calendars", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"order_by_name" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/calendars" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/calendars");
let params = {
"order_by_name": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"name": "Calendar",
"description": "This is the description of a calendar",
"color": "#C3E1FF",
"type": "standard",
"is_available_in_online_booking": true
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/calendars
Query Parameters
Parameter | Status | Description |
---|---|---|
order_by_name |
optional | =[asc|desc] Order results by name. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Create a calendar
Requires authentication
Creates a new calendar with the given data.
Scope : calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/calendars", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "Calendar name",
"description" => "Calendar description",
"color" => "#c3e1ff",
"type" => "standard",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/calendars" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"Calendar name","description":"Calendar description","color":"#c3e1ff","type":"standard"}'
const url = new URL("http://localhost/api/v1/calendars");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "Calendar name",
"description": "Calendar description",
"color": "#c3e1ff",
"type": "standard"
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (201):
{
"message": "The calendar was added",
"data": {
"id": 1,
"name": "Name of calendar",
"description": "Description of calendar",
"color": "#c3e1ff",
"type": "standard",
"is_available_in_online_booking": true
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"name": [
"The Name field is required."
],
"type": [
"The type field is required.",
"The type field needs to be 'standard'."
],
"color": [
"The color field is required.",
"The color field is not a valid HEX value."
]
}
}
HTTP Request
POST api/v1/calendars
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | The name of the calendar |
description |
string | optional | The description of the calendar |
color |
string | required | The color (hex-value) of the calendar |
type |
string | required | The calendar type (currently only "standard" is supported) |
Show a calendar
Requires authentication
Returns the calendar data for a given ID.
Scope : calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/calendars/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/calendars/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/calendars/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "Calendar",
"description": "This is the description of a calendar",
"color": "#C3E1FF",
"type": "standard",
"is_available_in_online_booking": true
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/calendars/{calendar}
Client Custom Attributes
List attributes
Requires authentication
Returns all of the possible custom client attributes which can be used when creating/updating cliengs. These custom attributes are created using the "Custom Fields" app in the system.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-custom-attributes", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/client-custom-attributes" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-custom-attributes");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
[
{
"identifier": "birthday",
"name": "Birthday",
"type": "date",
"required": false
},
{
"identifier": "age",
"name": "Age",
"type": "number",
"required": false
}
]
HTTP Request
GET api/v1/client-custom-attributes
Show attribute
Requires authentication
Returns the information about a custom attribute given its identifier.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-custom-attributes/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/client-custom-attributes/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-custom-attributes/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"identifier": "birthday",
"name": "Birthday",
"type": "date",
"required": false
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/client-custom-attributes/{identifier}
Client Journal Files
List client journal files
Requires authentication
Returns information about all of the client's journal files.
Scope : journal-files-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1/journal-files", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients/1/journal-files" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1/journal-files");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
[
{
"id": 1,
"file_name": "1537433053_253518_1537529505_photo.jpeg",
"system_download_url": "https:\/\/system.easypractice.net\/app\/client\/1\/journal_file\/1",
"api_download_url": "https:\/\/system.easypractice.net\/api\/v1\/clients\/1\/journal-files\/1\/download",
"file_type": "jpeg",
"created_at": "2021-08-19T23:39:04+02:00",
"mime_type": "image\/jpeg",
"size": 53776
},
{
"id": 2,
"file_name": "1537433053_253518_1537529505_document.pdf",
"system_download_url": "https:\/\/system.easypractice.net\/app\/client\/1\/journal_file\/2",
"api_download_url": "https:\/\/system.easypractice.net\/api\/v1\/clients\/1\/journal-files\/2\/download",
"file_type": "pdf",
"created_at": "2021-08-19T23:39:04+02:00",
"mime_type": "application\/pdf",
"size": 1187182
}
]
HTTP Request
GET api/v1/clients/{client}/journal-files
Show client journal file
Requires authentication
Returns the client journal file data for a given ID.
Scope : journal-files-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1/journal-files/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients/1/journal-files/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1/journal-files/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"file_name": "1537433053_253518_1537529505_photo.jpeg",
"system_download_url": "https:\/\/system.easypractice.net\/app\/client\/1\/journal_file\/1",
"api_download_url": "https:\/\/system.easypractice.net\/api\/v1\/clients\/1\/journal-files\/1\/download",
"file_type": "jpeg",
"created_at": "2021-08-19T23:39:04+02:00",
"mime_type": "image\/jpeg",
"size": 53776
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/clients/{client}/journal-files/{journal_file}
Download client journal file
Requires authentication
Downloads the client journal file data for a given ID.
Scope : journal-files-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1/journal-files/1/download", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients/1/journal-files/1/download" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1/journal-files/1/download");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
Example response (500):
{
"error": {
"message": "Internal Error",
"status_code": 500
}
}
HTTP Request
GET api/v1/clients/{client}/journal-files/{journal_file}/download
Client Journals
List client journals
Requires authentication
Returns all of specified clients journal entries. Use the filter options provided to narrow down the results. For example: GET api/v1/clients/{client_id}/journals?draft=1&order_by_date=desc
Scope : journals-read
or journals-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1/journals", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"locked" => "1",
"favorite" => "1",
"draft" => "1",
"order_by_date" => "desc",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients/1/journals" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1/journals");
let params = {
"locked": "1",
"favorite": "1",
"draft": "1",
"order_by_date": "desc",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"date": "2020-01-23",
"title": "Client Journal Title",
"content": "Client Journal Content",
"favorite": true,
"draft": false,
"locked": false,
"locked_at": null
},
{
"id": 3,
"date": "2020-01-22",
"title": "Client Journal Title example2",
"content": "Client Journal Content example2",
"favorite": false,
"draft": true,
"locked": true,
"locked_at": "2020-01-26T18:10:47+00:00"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/clients/{client}/journals
Query Parameters
Parameter | Status | Description |
---|---|---|
locked |
optional | Return only locked journals. |
favorite |
optional | Return only favorited journals. |
draft |
optional | Return only draft journals. Drafts are entries auto-saved whilst typing. |
order_by_date |
optional | =[asc|desc] Order results by journal date. |
Create client journal
Requires authentication
Creates a new client journal with the given data.
Scope : journals-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/clients/1/journals", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"date" => "2019-03-25",
"content" => "The journal content",
"favorite" => true,
"draft" => false,
"locked" => false,
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/clients/1/journals" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"date":"2019-03-25","content":"The journal content","favorite":1,"draft":false,"locked":false}'
const url = new URL("http://localhost/api/v1/clients/1/journals");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"date": "2019-03-25",
"content": "The journal content",
"favorite": 1,
"draft": false,
"locked": false
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (201):
{
"message": "The journal entry was saved",
"data": {
"id": 1,
"date": "2019-03-25",
"title": "The journal title",
"content": "The journal content",
"favorite": true,
"draft": false,
"locked": false,
"locked_at": null
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"content": [
"The Content field is required."
]
}
}
HTTP Request
POST api/v1/clients/{client}/journals
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
date |
date_format:Y-m-d | required | The date for the journal in the YYYY-MM-DD format. |
content |
string | required | The content for the journal. |
favorite |
boolean | optional | Mark journal as favorite. Only one favorite per client is allowed. Marking this as a favorite will unmark other favorites from the same client. |
draft |
boolean | optional | Mark journal as draft. |
locked |
boolean | optional | Mark journal as locked. Locked journals can no longer be updated or deleted. |
Show client journal
Requires authentication
Returns the client journal data for a given ID.
Scope : journals-read
or journals-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1/journals/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients/1/journals/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1/journals/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"date": "2020-01-23",
"title": "Client Journal Title",
"content": "Client Journal Content",
"favorite": true,
"draft": false,
"locked": false,
"locked_at": null
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/clients/{client}/journals/{journal}
Update client journal
Requires authentication
Updates the client journal. Provide all properties. Any missing properties will be updated to null
Scope : journals-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/clients/1/journals/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"date" => "2019-03-25",
"content" => "The journal content",
"favorite" => true,
"draft" => false,
"locked" => false,
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/clients/1/journals/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"date":"2019-03-25","content":"The journal content","favorite":1,"draft":false,"locked":false}'
const url = new URL("http://localhost/api/v1/clients/1/journals/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"date": "2019-03-25",
"content": "The journal content",
"favorite": 1,
"draft": false,
"locked": false
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "The journal entry was saved",
"data": {
"id": 1,
"date": "2019-03-25",
"title": "The journal title",
"content": "The journal content",
"favorite": true,
"draft": false,
"locked": false,
"locked_at": null
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"content": [
"The Content field is required."
]
}
}
HTTP Request
PUT api/v1/clients/{client}/journals/{journal}
PATCH api/v1/clients/{client}/journals/{journal}
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
date |
date_format:Y-m-d | required | The date for the journal in the YYYY-MM-DD format. |
content |
string | required | The content for the journal. |
favorite |
boolean | optional | Mark journal as favorite. Only one favorite per client is allowed. Marking this as a favorite will unmark other favorites from the same client. |
draft |
boolean | optional | Mark journal as draft. |
locked |
boolean | optional | Mark journal as locked. Locked journals can no longer be updated or deleted. |
Delete client journal
Requires authentication
Deletes the client journal.
Scope : journals-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/clients/1/journals/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "http://localhost/api/v1/clients/1/journals/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1/journals/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "DELETE",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Deleted"
}
HTTP Request
DELETE api/v1/clients/{client}/journals/{journal}
Client Vouchers
List clients vouchers
Requires authentication
Returns all of the client vouchers. Use the filter options provided to narrow down the results. For example: GET api/v1/client-vouchers?active=1&vat=1&forEvents=1&page_size=20
Scope: clients-read
or clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-vouchers", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"active" => "1",
"vat" => "1",
"forEvents" => "1",
"forServices" => "1",
"client" => "1",
"order_by_created_at" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/client-vouchers" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-vouchers");
let params = {
"active": "1",
"vat": "1",
"forEvents": "1",
"forServices": "1",
"client": "1",
"order_by_created_at": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"name": "Silver voucher",
"is_for_events": false,
"client_id": 1,
"clips": 5,
"clips_used": 2,
"currency": "EUR",
"vat": true,
"vat_rate": 23,
"price": "3.00",
"expires_on": "2022-01-10",
"created_at": "2019-09-29T17:55:00+02:00",
"updated_at": "2019-09-30T17:55:00+02:00",
"service": {
"id": 1,
"name": "Example of a service"
}
},
{
"id": 2,
"name": "Gold voucher",
"is_for_events": true,
"client_id": 1,
"clips": 10,
"clips_used": 1,
"currency": "EUR",
"vat": true,
"vat_rate": 23,
"price": "25.00",
"expires_on": null,
"created_at": "2019-09-29T17:55:00+02:00",
"updated_at": "2019-09-30T17:55:00+02:00",
"service": null
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/client-vouchers
Query Parameters
Parameter | Status | Description |
---|---|---|
active |
optional | Return only the active vouchers. |
vat |
optional | Return only the vouchers with vat. |
forEvents |
optional | Return only the vouchers used for events. |
forServices |
optional | Return only the vouchers used for services. |
client |
optional | Return only client vouchers belonging to the client id given. |
order_by_created_at |
optional | =[asc|desc] Order results by created at. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show client voucher
Requires authentication
Returns the client voucher data for a given ID.
Scope: clients-read
or clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-vouchers/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/client-vouchers/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-vouchers/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "Silver voucher",
"is_for_events": false,
"client_id": 1,
"clips": 5,
"clips_used": 2,
"currency": "EUR",
"vat": true,
"vat_rate": 23,
"price": "3.00",
"expires_on": "2022-01-10",
"created_at": "2019-09-29T17:55:00+02:00",
"updated_at": "2019-09-30T17:55:00+02:00",
"service": {
"id": 1,
"name": "Example of a service"
}
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/client-vouchers/{client_voucher}
Clients
List clients
Requires authentication
Returns all of user's clients. Use the filter options provided to narrow down the results. For example: GET api/v1/clients?hasEmail&email=asc
Scope : clients-read
or clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"active" => "1",
"inactive" => "1",
"has_email" => "1",
"email" => "john@email.com",
"has_phone" => "1",
"cpr" => "1205001234",
"tag_id" => "54347",
"order_by_name" => "asc",
"order_by_created" => "desc",
"order_by_email" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients");
let params = {
"active": "1",
"inactive": "1",
"has_email": "1",
"email": "john@email.com",
"has_phone": "1",
"cpr": "1205001234",
"tag_id": "54347",
"order_by_name": "asc",
"order_by_created": "desc",
"order_by_email": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"name": "John Smith",
"email": "john@mydomain.dk",
"phone": "+45 61175736",
"address": "159 Bailey Brooks",
"address_line_2": "Kastanievej 17",
"zip": "W10 6DY",
"city": "Copenhagen",
"zone": "Region Sjælland",
"country": "da",
"alpha2": "DK",
"cpr": "1598431234",
"date_of_birth": "1991-01-20",
"notes": "Notes about John",
"profile_image_url": "https:\/\/www.gravatar.com\/avatar\/5ea799d8476cbe0b1965c39e7c7dbd99?d=mm&s=200",
"status": "active",
"created_at": "2019-04-16 11:54:42",
"tags": [],
"custom_attributes": [
{
"identifier": "birthday",
"value": "1991-05-23"
}
],
"danmark_group": null
},
{
"id": 2,
"name": "Mary Williams",
"email": "m.williams@mycompany.dk",
"phone": "+45 43612915",
"address": "3 Mike Common",
"address_line_2": "Kastanievej 17",
"zip": "NG34 9HJ",
"city": "Copenhagen",
"zone": "Region Sjælland",
"country": "da",
"alpha2": "DK",
"cpr": "3574261234",
"date_of_birth": null,
"notes": "",
"profile_image_url": "https:\/\/www.gravatar.com\/avatar\/5ea799d8476cbe0b1965c39e7c7dbd99?d=mm&s=200",
"status": "inactive",
"created_at": "2019-04-20 08:14:21",
"tags": [],
"custom_attributes": [],
"danmark_group": 1
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/clients
Query Parameters
Parameter | Status | Description |
---|---|---|
active |
optional | Return only the active clients. |
inactive |
optional | Return only the inactive clients. |
has_email |
optional | Return only the clients with an email. |
email |
optional | Return only clients with a given email. |
has_phone |
optional | Return only the clients with phone number. |
cpr |
optional | Return only the clients with a given CPR number. |
tag_id |
optional | Return only clients belonging to this tag ID. |
order_by_name |
optional | =[asc|desc] Order results by name. |
order_by_created |
optional | =[asc|desc] Order results by creation date. |
order_by_email |
optional | =[asc|desc] Order results by email. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Create client
Requires authentication
Creates a new client with the given data.
Scope : clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/clients", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "John Doe",
"email" => "john.doe@example.com",
"ean" => 5789012345678,
"phone" => "+44 7380111233",
"address" => "159 Bailey Brooks",
"address_line_2" => "123 Main Street",
"zip" => "M14 5PT",
"city" => "Manchester",
"zone" => "Northamptonshire",
"country" => "en",
"cpr" => "0123456789",
"date_of_birth" => "1991-01-20",
"notes" => "Some notes",
"tags" => [
[
"id" => 15,
],
[
"name" => "Gold clients",
],
],
"status" => "active",
"custom_attributes" => [
[
"identifier" => "birthday",
"value" => "1991-05-23",
],
],
"danmark_group" => 1,
"sync_to_mailchimp" => false,
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/clients" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"John Doe","email":"john.doe@example.com","ean":5789012345678,"phone":"+44 7380111233","address":"159 Bailey Brooks","address_line_2":"123 Main Street","zip":"M14 5PT","city":"Manchester","zone":"Northamptonshire","country":"en","cpr":"0123456789","date_of_birth":"1991-01-20","notes":"Some notes","tags":[{"id":15},{"name":"Gold clients"}],"status":"active","custom_attributes":[{"identifier":"birthday","value":"1991-05-23"}],"danmark_group":1,"sync_to_mailchimp":false}'
const url = new URL("http://localhost/api/v1/clients");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "John Doe",
"email": "john.doe@example.com",
"ean": 5789012345678,
"phone": "+44 7380111233",
"address": "159 Bailey Brooks",
"address_line_2": "123 Main Street",
"zip": "M14 5PT",
"city": "Manchester",
"zone": "Northamptonshire",
"country": "en",
"cpr": "0123456789",
"date_of_birth": "1991-01-20",
"notes": "Some notes",
"tags": [
{
"id": 15
},
{
"name": "Gold clients"
}
],
"status": "active",
"custom_attributes": [
{
"identifier": "birthday",
"value": "1991-05-23"
}
],
"danmark_group": 1,
"sync_to_mailchimp": false
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (201):
{
"message": "Created",
"data": {
"id": 123,
"name": "John Doe",
"email": "john.doe@example.com",
"ean": "5789012345678",
"phone": "+44 7380111233",
"address": "159 Bailey Brooks",
"address_line_2": "123 Main Street",
"zip": "M14 5PT",
"city": "Manchester",
"zone": "Northamptonshire",
"country": "en",
"alpha2": "GB",
"cpr": "0123456789",
"date_of_birth": "1991-01-20",
"notes": "Some notes",
"status": "active",
"tags": [],
"custom_attributes": [
{
"identifier": "birthday",
"value": "1991-05-23"
}
],
"danmark_group": 1
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"name": [
"The Name field is required."
]
}
}
HTTP Request
POST api/v1/clients
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | The Name of the client. |
email |
string | optional | The Email of the client. |
ean |
string | optional | The EAN-number of the client. |
phone |
string | optional | The Phone of the client with the country code. If the country code is omitted, the account's default country code is applied. |
address |
string | optional | The Address of the client. |
address_line_2 |
string | optional | The Address Line 2 of the client. |
zip |
string | optional | The Zip/Postcode of the client. |
city |
string | optional | The City of the client. |
zone |
string | optional | The State/Province/County of the client. |
country |
string | optional | The Country code of the client. |
cpr |
string | optional | The CPR of the client. |
date_of_birth |
The | optional | date of birth of the client in YYYY-MM-DD format. |
notes |
string | optional | The Notes of the client. |
tags |
array | optional | The tags associated to the client. It's possible to use the id or the name for each tag. |
status |
string | optional | The status of the client. Currently only two statuses are allowed: "active" and "inactive". |
custom_attributes |
array | optional | The custom fields and their values for the client. Must have "Custom Fields" app enabled. Non-existent fields will be ignored. See Client Custom Attributes for a list of available attributes on your account. |
danmark_group |
integer | optional | (Danish accounts only) The Sygeforsikring "danmark" group number for this client. Must be one of these values: null (not set), 0 (Ved ikke), 1 (Gruppe 1), 2 (Gruppe 2), 5 (Gruppe 5) or 6 (Gruppe 6). A valid CPR is required to assign a client to a "danmark" group. |
sync_to_mailchimp |
boolean | optional | (Requires Mailchimp app active) Whether to sync this client to Mailchimp. |
Show client
Requires authentication
Returns the client data for a given ID.
Scope : clients-read
or clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/clients/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "John Smith",
"email": "john@mydomain.dk",
"phone": "+45 61175736",
"address": "159 Bailey Brooks",
"address_line_2": "123 Main Street",
"zip": "W10 6DY",
"city": "Copenhagen",
"zone": "Region Sjælland",
"country": "da",
"alpha2": "DK",
"cpr": "1598431234",
"date_of_birth": "1991-01-20",
"notes": "Notes about John",
"profile_image_url": "https:\/\/www.gravatar.com\/avatar\/5ea799d8476cbe0b1965c39e7c7dbd99?d=mm&s=200",
"status": "active",
"created_at": "2019-04-16 11:54:42",
"tags": [],
"custom_attributes": [
{
"identifier": "birthday",
"value": "1991-05-23"
}
],
"danmark_group": 1
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/clients/{client}
Update client
Requires authentication
Updates the client.
Scope : clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/clients/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "John Doe",
"email" => "john.doe@example.com",
"ean" => 5789012345678,
"phone" => "+44 7380111233",
"address" => "159 Bailey Brooks",
"address_line_2" => "123 Main Street",
"zip" => "M14 5PT",
"city" => "Manchester",
"zone" => "Northamptonshire",
"country" => "en",
"cpr" => "0123456789",
"date_of_birth" => "1991-01-20",
"notes" => "Some notes",
"tags" => [
[
"id" => 15,
],
[
"name" => "Gold clients",
],
],
"status" => "active",
"custom_attributes" => [
[
"identifier" => "birthday",
"value" => "1991-05-23",
],
],
"danmark_group" => 1,
"sync_to_mailchimp" => false,
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/clients/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"John Doe","email":"john.doe@example.com","ean":5789012345678,"phone":"+44 7380111233","address":"159 Bailey Brooks","address_line_2":"123 Main Street","zip":"M14 5PT","city":"Manchester","zone":"Northamptonshire","country":"en","cpr":"0123456789","date_of_birth":"1991-01-20","notes":"Some notes","tags":[{"id":15},{"name":"Gold clients"}],"status":"active","custom_attributes":[{"identifier":"birthday","value":"1991-05-23"}],"danmark_group":1,"sync_to_mailchimp":false}'
const url = new URL("http://localhost/api/v1/clients/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "John Doe",
"email": "john.doe@example.com",
"ean": 5789012345678,
"phone": "+44 7380111233",
"address": "159 Bailey Brooks",
"address_line_2": "123 Main Street",
"zip": "M14 5PT",
"city": "Manchester",
"zone": "Northamptonshire",
"country": "en",
"cpr": "0123456789",
"date_of_birth": "1991-01-20",
"notes": "Some notes",
"tags": [
{
"id": 15
},
{
"name": "Gold clients"
}
],
"status": "active",
"custom_attributes": [
{
"identifier": "birthday",
"value": "1991-05-23"
}
],
"danmark_group": 1,
"sync_to_mailchimp": false
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Updated",
"data": {
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"ean": "5789012345678",
"phone": "+44 7380111233",
"address": "159 Bailey Brooks",
"address_line_2": "123 Main Street",
"zip": "M14 5PT",
"city": "Manchester",
"zone": "Northamptonshire",
"country": "en",
"alpha2": "GB",
"cpr": "0123456789",
"date_of_birth": "1991-01-20",
"notes": "Some notes",
"status": "active",
"tags": [],
"custom_attributes": [
{
"identifier": "birthday",
"value": "1991-05-23"
}
],
"danmark_group": 1
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"name": [
"The Name field is required."
]
}
}
HTTP Request
PUT api/v1/clients/{client}
PATCH api/v1/clients/{client}
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | The Name of the client. |
email |
string | optional | The Email of the client. |
ean |
string | optional | The EAN-number of the client. |
phone |
string | optional | The Phone of the client with the country code. If the country code is omitted, the account's default country code is applied. |
address |
string | optional | The Address of the client. |
address_line_2 |
string | optional | The Address Line 2 of the client. |
zip |
string | optional | The Zip/Postcode of the client. |
city |
string | optional | The City of the client. |
zone |
string | optional | The State/Province/County of the client. |
country |
string | optional | The Country code of the client. |
cpr |
string | optional | The CPR of the client. |
date_of_birth |
The | optional | date of birth of the client in YYYY-MM-DD format. |
notes |
string | optional | The Notes of the client. |
tags |
array | optional | The tags associated to the client. It's possible to use the id or the name for each tag. |
status |
string | optional | The status of the client. Currently only two statuses are allowed: "active" and "inactive". |
custom_attributes |
array | optional | The custom fields and their values for the client. Must have "Custom Fields" app enabled. Non-existent fields will be ignored. See Client Custom Attributes for a list of available attributes on your account. |
danmark_group |
integer | optional | (Danish accounts only) The Sygeforsikring "danmark" group number for this client. Must be one of these values: null (not set), 0 (Ved ikke), 1 (Gruppe 1), 2 (Gruppe 2), 5 (Gruppe 5) or 6 (Gruppe 6). A valid CPR is required to assign a client to a "danmark" group. |
sync_to_mailchimp |
boolean | optional | (Requires Mailchimp app active) Whether to sync this client to Mailchimp. |
Delete client
Requires authentication
Removes the client from the user's account and all of its associated data, such as bookings/journals/messages. Use with caution.
Scope : clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/clients/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "http://localhost/api/v1/clients/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/clients/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "DELETE",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Deleted"
}
HTTP Request
DELETE api/v1/clients/{client}
Client tags
List all client tags
Requires authentication
Returns all of user's clients tags. Use the filter options provided to order the results. For example: GET api/v1/clients?order_by_tag=asc
. Please note that this is an endpoint to administer the tags already created on the user. If you need to add/remove tags from clients, then use the Clients endpoint instead.
Scope: clients-read
or clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-tags", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"order_by_name" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/client-tags" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-tags");
let params = {
"order_by_name": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"name": "Premium clients",
"timestamp": "2019-09-30T17:55:00+02:00"
},
{
"id": 2,
"name": "Gold clients",
"timestamp": "2019-09-30T17:55:00+02:00"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/client-tags
Query Parameters
Parameter | Status | Description |
---|---|---|
order_by_name |
optional | =[asc|desc] Order results by name. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Create client tag
Requires authentication
Scope: clients-readwrite
Creates a new client tag with the given data.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/client-tags", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "Premium clients",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/client-tags" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"Premium clients"}'
const url = new URL("http://localhost/api/v1/client-tags");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "Premium clients"
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (201):
{
"message": "The new tag was created",
"data": {
"id": 123,
"name": "Premium clients",
"timestamp": "2019-09-30T17:55:00+02:00"
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"name": [
"The name field is required."
]
}
}
HTTP Request
POST api/v1/client-tags
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | The Name of the tag. |
Show client tag
Requires authentication
Returns the client tag data for a given ID.
Scope: clients-read
or clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-tags/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/client-tags/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-tags/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "Premium clients",
"timestamp": "2019-09-30T17:55:00+02:00"
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/client-tags/{client_tag}
Update client tag
Requires authentication
Updates the clients tag.
Scope: clients-readwrite`
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/client-tags/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "Premium clients",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/client-tags/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"Premium clients"}'
const url = new URL("http://localhost/api/v1/client-tags/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "Premium clients"
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "The tag was updated",
"data": {
"id": 1,
"name": "Premium clients",
"timestamp": "2019-09-30T17:55:00+02:00"
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"name": [
"The name field is required."
]
}
}
HTTP Request
PUT api/v1/client-tags/{client_tag}
PATCH api/v1/client-tags/{client_tag}
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | The Name of the tag. |
Delete client tag
Requires authentication
Removes the clients tag from the user's account.
Scope: clients-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/client-tags/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "http://localhost/api/v1/client-tags/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/client-tags/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "DELETE",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Deleted"
}
HTTP Request
DELETE api/v1/client-tags/{client_tag}
Discount Codes
List discount codes
Requires authentication
Returns all of user's discount codes. Data is only available if the app is active.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/discount-codes", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/discount-codes" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/discount-codes");
let params = {
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 122,
"code": "1000off",
"type": "value",
"value": 1000,
"value_formatted": "Value (DKK 1.000,00)",
"number_of_uses": null,
"client_use_limit": null,
"expires_at": null,
"is_expired": false,
"is_available": true,
"availability": {
"all_calendars": false,
"all_products": true,
"all_events": true,
"all_vouchers": false,
"all_digital_content_packages": true,
"all_gift_cards": false,
"events": [],
"event_groups": [],
"products": [],
"calendars": [
{
"id": 545,
"name": "Calendar 1",
"type": "standard"
}
],
"digital_content_packages": []
},
"created_at": "2022-09-14T12:30:37+02:00",
"updated_at": "2022-09-14T12:30:37+02:00"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
Example response (403):
{
"error": {
"message": "Discount codes app is not active.",
"status_code": 403
}
}
HTTP Request
GET api/v1/discount-codes
Query Parameters
Parameter | Status | Description |
---|---|---|
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show discount code
Requires authentication
Returns the discount code data for a given code. Data is only available if the app is active.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/discount-codes/1000off", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/discount-codes/1000off" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/discount-codes/1000off");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 122,
"code": "1000off",
"type": "value",
"value": 1000,
"value_formatted": "Value (DKK 1.000,00)",
"number_of_uses": null,
"client_use_limit": null,
"expires_at": null,
"is_expired": false,
"is_available": true,
"availability": {
"all_calendars": false,
"all_products": true,
"all_events": true,
"all_vouchers": false,
"all_digital_content_packages": true,
"all_gift_cards": false,
"events": [],
"event_groups": [],
"products": [],
"calendars": [
{
"id": 545,
"name": "Calendar 1",
"type": "standard"
}
],
"digital_content_packages": []
},
"created_at": "2022-09-14T12:30:37+02:00",
"updated_at": "2022-09-14T12:30:37+02:00"
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
Example response (403):
{
"error": {
"message": "Discount codes app is not active.",
"status_code": 403
}
}
HTTP Request
GET api/v1/discount-codes/{code}
URL Parameters
Parameter | Status | Description |
---|---|---|
code |
required | The discount code. |
EasyPay
List payments
Requires authentication
Returns all of user's easypay payments. Use the filter options provided to narrow down the results. For example: GET api/v1/easypay/payments?filter=paid
Scope : easypay-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/easypay/payments", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"filter" => "paid",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/easypay/payments" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/easypay/payments");
let params = {
"filter": "paid",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"amount": 100,
"payment_date": "021-05-05T14:01:21+02:00",
"status": "charged",
"client_id": 123,
"invoice_id": 123,
"booking_id": 123,
"transfer_id": 123,
"service_id": 123,
"invoice_number": 100002,
"payment_card_type": "visa",
"payment_card_last4": 1234,
"card_fee": 0.92000000000000004,
"card_fee_vat": 0.12,
"transaction_fee": 0.14999999999999999,
"transaction_fee_vat": 0.050000000000000003,
"total_fee": 1.24,
"currency": "GBP"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/easypay/payments
Query Parameters
Parameter | Status | Description |
---|---|---|
filter |
optional | Filter results by status. Available values: "charge_failed", "reserved", "charged", "in_transit", "paid", "refunded" |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show payment
Requires authentication
Returns the payment data for a given ID.
Scope : easypay-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/easypay/payments/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/easypay/payments/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/easypay/payments/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"amount": 100,
"payment_date": "021-05-05T14:01:21+02:00",
"status": "charged",
"client_id": 123,
"invoice_id": 123,
"booking_id": 123,
"transfer_id": 123,
"service_id": 123,
"invoice_number": 100002,
"payment_card_type": "visa",
"payment_card_last4": 1234,
"card_fee": 0.92000000000000004,
"card_fee_vat": 0.12,
"transaction_fee": 0.14999999999999999,
"transaction_fee_vat": 0.050000000000000003,
"total_fee": 1.24,
"currency": "GBP"
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/easypay/payments/{payment}
List transfers
Requires authentication
Returns all of user's easypay transfers. Use the filter options provided to narrow down the results. For example: GET api/v1/easypay/payments?filter=paid
Scope : easypay-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/easypay/transfers", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/easypay/transfers" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/easypay/transfers");
let params = {
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"status": "in_transit",
"amount": 200,
"transfer_id": 21342,
"transfer_date": "2021-04-03 10:04:20",
"payments": [
{
"id": 1,
"amount": 100,
"payment_date": "021-05-05T14:01:21+02:00",
"status": "charged",
"client_id": 123,
"invoice_id": 123,
"booking_id": 123,
"transfer_id": 123,
"service_id": 123,
"invoice_number": 100002,
"payment_card_type": "visa",
"payment_card_last4": 1234,
"card_fee": 0.92000000000000004,
"card_fee_vat": 0.12,
"transaction_fee": 0.14999999999999999,
"transaction_fee_vat": 0.050000000000000003,
"total_fee": 1.24,
"currency": "GBP"
}
]
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/easypay/transfers
Query Parameters
Parameter | Status | Description |
---|---|---|
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show transfer
Requires authentication
Returns the transfer data for a given ID.
Scope : easypay-read
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/easypay/transfers/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/easypay/transfers/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/easypay/transfers/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"status": "in_transit",
"amount": 200,
"transfer_id": 21342,
"transfer_date": "2021-04-03 10:04:20",
"payments": [
{
"id": 1,
"amount": 100,
"payment_date": "021-05-05T14:01:21+02:00",
"status": "charged",
"client_id": 123,
"invoice_id": 123,
"booking_id": 123,
"transfer_id": 123,
"service_id": 123,
"invoice_number": 100002,
"payment_card_type": "visa",
"payment_card_last4": 1234,
"card_fee": 0.92000000000000004,
"card_fee_vat": 0.12,
"transaction_fee": 0.14999999999999999,
"transaction_fee_vat": 0.050000000000000003,
"total_fee": 1.24,
"currency": "GBP"
}
]
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/easypay/transfers/{transfer}
Invoices
List invoices
Requires authentication
Returns all of user's invoices. Use the filter options provided to narrow down the results. For example: GET api/v1/invoices?client_id=123
Scope : invoices-read
or invoices-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/invoices", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"id" => "2135",
"number" => "20020",
"client_id" => "54347",
"paid" => "1",
"unpaid" => "1",
"order_by_number" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/invoices" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/invoices");
let params = {
"id": "2135",
"number": "20020",
"client_id": "54347",
"paid": "1",
"unpaid": "1",
"order_by_number": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"draft": false,
"client_id": 123,
"number": 454,
"date": "2019-04-20T00:00:00+01:00",
"due_date": "2019-04-20T00:00:00+01:00",
"executed_date": "2019-04-20T00:00:00+01:00",
"paid_date": "2019-04-20T00:00:00+01:00",
"sent": true,
"sent_via_ean": false,
"employee": null,
"paid": true,
"credited": false,
"status": "paid",
"client_name": "John Doe",
"client_cpr": "123456-7890",
"client_address": "54 Harry Lane",
"client_address_line_2": "Kastanievej 17",
"client_zip": "1234",
"client_city": "Copenhagen",
"client_zone": "Region Sjælland",
"client_country": "dk",
"note": "Lorem Ipsum",
"payment_type": "card",
"currency": "DKK",
"total": 625,
"lines": [
{
"id": 23,
"invoice_id": 1,
"product_id": 1,
"position": 0,
"amount": 1,
"price": 500,
"vat": true,
"vat_rate": 25,
"total_without_vat": 500,
"total": 625,
"text": "Client appointment",
"comment": "",
"booking_id": 2,
"booking_description": "Appointment Tuesday 16 April 2019, 16:05",
"event_signup_id": null,
"client_voucher_id": null
}
]
},
{
"id": 2,
"draft": false,
"client_id": 22,
"number": 455,
"date": "2019-05-01T00:00:00+01:00",
"due_date": "2019-05-01T00:00:00+01:00",
"executed_date": "2019-05-01T00:00:00+01:00",
"paid_date": "2019-05-01T00:00:00+01:00",
"sent": true,
"sent_via_ean": false,
"employee": {
"id": 12345,
"name": "Jane Doe",
"email": "janedoe@example.com",
"profile_image_url": "..."
},
"paid": true,
"credited": false,
"status": "paid",
"client_name": "Jaimes Armsworth",
"client_cpr": "121212-7890",
"client_address": "4 Snow Street",
"client_address_line_2": "Kastanievej 17",
"client_zip": "5454",
"client_city": "Copenhagen",
"client_zone": "Region Sjælland",
"client_country": "dk",
"note": "Lorem Ipsum",
"payment_type": "card",
"currency": "DKK",
"total": 1500,
"lines": [
{
"...": "..."
},
{
"...": "..."
}
]
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/invoices
Query Parameters
Parameter | Status | Description |
---|---|---|
id |
optional | Return only invoices with this specific ID. |
number |
optional | Return only invoices with this specific invoice number. |
client_id |
optional | Return only invoices belonging to this client ID. |
paid |
optional | Return only the paid invoices. |
unpaid |
optional | Return only the unpaid invoices. |
order_by_number |
optional | =[asc|desc] Order results by invoice number. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Mark an invoice as paid
Requires authentication
Scope : invoices-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/invoices/1/mark-as-paid", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"date" => "2019-05-16",
"payment_type" => "card",
"amount" => 1500,
"currency" => "DKK",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/invoices/1/mark-as-paid" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"date":"2019-05-16","payment_type":"card","amount":1500,"currency":"DKK"}'
const url = new URL("http://localhost/api/v1/invoices/1/mark-as-paid");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"date": "2019-05-16",
"payment_type": "card",
"amount": 1500,
"currency": "DKK"
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "The Invoice 123 was marked as paid on 2019-05-20 with the payment method Card"
}
Example response (400):
{
"error": {
"message": "The Invoice 123 is already paid.",
"status_code": 400
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"payment_type": [
"The selected Payment type is invalid."
]
}
}
HTTP Request
POST api/v1/invoices/{id}/mark-as-paid
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
date |
date | required | The Date of the payment. |
payment_type |
string | required | The Payment method used. Available values: 'transfer', 'cash', 'card', 'other', 'mobile_pay' (Denmark only), 'health_insurance', 'swish' (Sweden only) |
amount |
float | required | The Amount of the payment. |
currency |
string | required | The Currency of the payment. |
Send Invoice
Sends an invoice via e-mail. Tags are supported in the "text" field. See the "Email and SMS" settings page in the system to find out which tags are supported for invoice emails.
Scope : invoices-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/invoices/1/send", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"subject" => "Invoice",
"text" => "Hi, please see the attached invoice.",
"email" => "john.doe@example.com",
"as_attachment" => true,
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/invoices/1/send" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"subject":"Invoice","text":"Hi, please see the attached invoice.","email":"john.doe@example.com","as_attachment":1}'
const url = new URL("http://localhost/api/v1/invoices/1/send");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"subject": "Invoice",
"text": "Hi, please see the attached invoice.",
"email": "john.doe@example.com",
"as_attachment": 1
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Invoice 1 was sent to John Doe (Test klient) (john.doe@example.com)",
"data": {
"id": 1,
"draft": false,
"client_id": 123,
"number": 454,
"date": "2019-04-20T00:00:00+01:00",
"due_date": "2019-04-20T00:00:00+01:00",
"executed_date": "2019-04-20T00:00:00+01:00",
"paid_date": "2019-04-20T00:00:00+01:00",
"sent": true,
"sent_via_ean": false,
"employee": null,
"paid": true,
"credited": false,
"status": "paid",
"client_name": "John Doe",
"client_cpr": "123456-7890",
"client_address": "54 Harry Lane",
"client_address_line_2": "Kastanievej 17",
"client_zip": "1234",
"client_city": "Copenhagen",
"client_zone": "Region Sjælland",
"client_country": "dk",
"note": "Lorem Ipsum",
"payment_type": "card",
"currency": "DKK",
"total": 625,
"lines": [
{
"...": "..."
}
]
}
}
Example response (422):
{
"error": {
"message": "The given data is invalid",
"status_code": 422
},
"data": {
"email": [
"The email must be a valid email address."
]
}
}
HTTP Request
POST api/v1/invoices/{id}/send
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
subject |
string | required | The subject of the email. |
text |
string | required | The body of the email. |
email |
string | required | The email address. |
as_attachment |
boolean | optional | Whether to attach the invoice PDF to the email. |
Online Booking
List Available Dates
Requires authentication
Returns a list of Available dates based on a supplied date range, products and calendars. It does not return dates in the past, as they would never be available.
Scope: calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/online-booking/available-dates", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"from" => "2020-08-01",
"to" => "2020-09-01",
"product_ids" => "1",
"addon_ids" => "4",
"calendar_id" => "1",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/online-booking/available-dates" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/online-booking/available-dates");
let params = {
"from": "2020-08-01",
"to": "2020-09-01",
"product_ids": "1",
"addon_ids": "4",
"calendar_id": "1",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"date": "2020-08-21",
"available": true,
"available_in_calendars": [
{
"id": 1,
"name": "Test calendar",
"description": "",
"color": "#C3E1FF",
"type": "standard"
}
]
},
{
"date": "2020-08-22",
"available": false,
"reason": "closed_opening_time"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/online-booking/available-dates
Query Parameters
Parameter | Status | Description |
---|---|---|
from |
required | date_format:Y-m-d Return Available Dates from the start of the supplied date. |
to |
required | date_format:Y-m-d Return Available Dates to the end of the supplied date. |
product_ids |
required | array Return Available Dates/Times based on an array of product IDs. |
addon_ids |
optional | array Return Available Dates/Times based on an array of product addons that are allowed to be attached to the supplied product_ids. |
calendar_id |
optional | integer Return Available Dates/Times based on a specific Calendar. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
List Available Times
Requires authentication
Returns a list of Available times based on a supplied date, products and calendars. It does not return times in the past, as they would never be available.
Scope: calendars-read
or calendars-readwrite
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/online-booking/available-times", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"date" => "2020-09-01",
"product_ids" => "1",
"addon_ids" => "4",
"calendar_id" => "1",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/online-booking/available-times" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/online-booking/available-times");
let params = {
"date": "2020-09-01",
"product_ids": "1",
"addon_ids": "4",
"calendar_id": "1",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"date": "2020-08-30T09:00:00+01:00",
"available": true,
"available_in_calendars": [
{
"id": 1,
"name": "Test calendar",
"description": "",
"color": "#C3E1FF",
"type": "standard"
}
]
},
{
"date": "2020-08-30T10:00:00+01:00",
"available": false,
"reason": "overlapping_booking"
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/online-booking/available-times
Query Parameters
Parameter | Status | Description |
---|---|---|
date |
required | date_format:Y-m-d Return Available Times for the supplied date. |
product_ids |
required | array Return Available Dates/Times based on an array of product IDs. |
addon_ids |
optional | array Return Available Dates/Times based on an array of product addons that are allowed to be attached to the supplied product_ids. |
calendar_id |
optional | integer Return Available Dates/Times based on a specific Calendar. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Services
List service groups
Requires authentication
Returns all of user's service groups.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/service-groups", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/service-groups" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/service-groups");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
[
{
"id": 1,
"name": "Service Group Name 1"
},
{
"id": 2,
"name": "Service Group Name 2"
}
]
HTTP Request
GET api/v1/service-groups
List services
Requires authentication
Returns all of user's services. Use the order param to order the results. For example: GET api/v1/services?order_by_name=asc
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/services", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"order_by_name" => "asc",
"product_group_id" => "1",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/services" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/services");
let params = {
"order_by_name": "asc",
"product_group_id": "1",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"name": "Example of a service",
"description": "This is an example of your first service. You can either edit this service or delete it and create a new one to make if fit your practice",
"duration": 45,
"break_after_service": 15,
"currency": "DKK",
"price": 50,
"vat": true,
"vat_rate": 25,
"product_group_id": 1,
"product_group": {
"id": 1,
"name": "Service Group Name 1"
},
"is_available_in_online_booking": true,
"online_payment_enabled": true,
"reserve_online_payment": true,
"require_payment_in_advance": true,
"payment_rates_enabled": true,
"payment_rates_interval": "weekly",
"payment_rates_number": 4,
"order": 1,
"calendars": [
{
"id": 12,
"name": "Calendar",
"color": "#C3E1FF"
}
],
"addons": [
{
"id": 2,
"name": "Additional time"
}
]
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/services
Query Parameters
Parameter | Status | Description |
---|---|---|
order_by_name |
optional | =[asc|desc] Order results by name. |
product_group_id |
optional | (optional) Filter results by product group ID. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show service
Requires authentication
Returns the service data for a given ID.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/services/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/services/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/services/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "Example of a service",
"description": "This is an example of your first service. You can either edit this service or delete it and create a new one to make if fit your practice",
"duration": 45,
"break_after_service": 15,
"currency": "DKK",
"price": 50,
"vat": true,
"vat_rate": 25,
"product_group_id": 1,
"product_group": {
"id": 1,
"name": "Service Group Name 1"
},
"is_available_in_online_booking": true,
"online_payment_enabled": true,
"reserve_online_payment": true,
"require_payment_in_advance": true,
"payment_rates_enabled": true,
"payment_rates_interval": "weekly",
"payment_rates_number": 4,
"order": 1,
"calendars": [
{
"id": 12,
"name": "Calendar",
"color": "#C3E1FF"
}
],
"addons": [
{
"id": 2,
"name": "Additional time"
}
]
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/services/{product}
List addons
Requires authentication
Returns all of user's addons. Addons are similar to services, but have fewer properties and their functionality depends on the service it is attached to during the booking (Online Payment, Payment Rates, etc). Use the filter options provided to narrow down the results. For example: GET api/v1/addons?order_by_name=asc
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/addons", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"order_by_name" => "asc",
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/addons" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/addons");
let params = {
"order_by_name": "asc",
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 2,
"name": "Additional time",
"description": "",
"duration": 15,
"break_after_service": 0,
"currency": "DKK",
"price": 15,
"vat": true,
"vat_rate": 25,
"is_available_in_online_booking": true,
"services": [
{
"id": 1,
"name": "Example of a service"
}
]
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/addons
Query Parameters
Parameter | Status | Description |
---|---|---|
order_by_name |
optional | =[asc|desc] Order results by name. |
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show addon
Requires authentication
Returns the addon data for a given ID.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/addons/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/addons/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/addons/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 2,
"name": "Additional time",
"description": "",
"duration": 15,
"break_after_service": 0,
"currency": "DKK",
"price": 15,
"vat": true,
"vat_rate": 25,
"is_available_in_online_booking": true,
"services": [
{
"id": 1,
"name": "Example of a service"
}
]
}
Example response (404):
{
"error": {
"message": "Not Found",
"status_code": 404
}
}
HTTP Request
GET api/v1/addons/{addon}
User
Show user information
Requires authentication
Returns information about the authenticated user
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/user", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/user" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/user");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "Name of user",
"email": "E-mail of the user",
"phone": "Phone number of the user",
"country": "Country of the user",
"vat_number": "VAT number of the user",
"address": "Address of the user",
"zip_code": "Zip code of the user",
"city": "City of the user"
}
HTTP Request
GET api/v1/user
User Employees
List Employees
Requires authentication
Returns all of user's employees. For example: GET api/v1/employees
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/employees", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'query' => [
"page_size" => "20",
"page" => "4",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/employees" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/employees");
let params = {
"page_size": "20",
"page": "4",
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"data": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"type": "employee",
"profile_image_url": "https:\/\/www.gravatar.com\/avatar\/a6753b5d10e6a069e284cff387f94665?d=mm",
"profile_image_large_url": "https:\/\/www.gravatar.com\/avatar\/a6753b5d10e6a069e284cff387f94665?d=mm",
"2fa_enabled": false
},
{
"id": 2,
"name": "Jane Doe",
"email": "jane@example.com",
"type": "tenant",
"profile_image_url": "https:\/\/www.gravatar.com\/avatar\/a6753b5d10e6a069e284cff387f94665?d=mm",
"profile_image_large_url": "https:\/\/www.gravatar.com\/avatar\/a6753b5d10e6a069e284cff387f94665?d=mm",
"2fa_enabled": true
}
],
"links": {
"...": "..."
},
"meta": {
"...": "..."
}
}
HTTP Request
GET api/v1/employees
Query Parameters
Parameter | Status | Description |
---|---|---|
page_size |
optional | (default: 10) The number of items per page. |
page |
optional | (default: 1) The page number. |
Show Employee
Requires authentication
Returns an Employee. For example: GET api/v1/employees/1
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/employees/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/employees/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/employees/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"type": "employee",
"profile_image_url": "https:\/\/www.gravatar.com\/avatar\/a6753b5d10e6a069e284cff387f94665?d=mm",
"profile_image_large_url": "https:\/\/www.gravatar.com\/avatar\/a6753b5d10e6a069e284cff387f94665?d=mm",
"2fa_enabled": false
}
HTTP Request
GET api/v1/employees/{employee}
Webhooks
List webhooks
Requires authentication
Returns all webhooks
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/webhooks", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/webhooks" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/webhooks");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
[
{
"id": "1",
"name": "Example webhook",
"method": "POST",
"url": "http:\/\/test.example.com",
"events": [
"client-created",
"client-updated"
]
},
{
"id": "2",
"name": "Example webhook 2",
"method": "POST",
"url": "http:\/\/test.example2.com",
"events": [
"booking-created"
]
}
]
HTTP Request
GET api/v1/webhooks
Create a webhook
Requires authentication
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/webhooks", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "Example webhook",
"url" => "http://test.example.com",
"method" => "POST",
"events" => [
"0" => "client-created",
"1" => "client-updated",
],
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "http://localhost/api/v1/webhooks" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"Example webhook","url":"http:\/\/test.example.com","method":"POST","events":["client-created","client-updated"]}'
const url = new URL("http://localhost/api/v1/webhooks");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "Example webhook",
"url": "http:\/\/test.example.com",
"method": "POST",
"events": [
"client-created",
"client-updated"
]
}
fetch(url, {
method: "POST",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Created",
"data": {
"id": "1",
"name": "Example webhook",
"method": "POST",
"url": "http:\/\/test.example.com",
"events": [
"client-created",
"client-updated"
]
}
}
HTTP Request
POST api/v1/webhooks
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | Name of the webhook. |
url |
string | required | URL of the webhook. |
method |
string | required | Request method for the webhook. Currently only POST is supported. |
events |
array | required | An array of supported events, which will trigger this webhook: booking-created , booking-updated , booking-deleted , client-created , client-updated . |
Retrieve a webhook
Requires authentication
Return the webhook for given ID
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/webhooks/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/webhooks/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/webhooks/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"id": "1",
"name": "Example webhook",
"method": "POST",
"url": "http:\/\/test.example.com",
"events": [
"client-created",
"client-updated"
]
}
HTTP Request
GET api/v1/webhooks/{webhook}
URL Parameters
Parameter | Status | Description |
---|---|---|
id |
required | ID of the webhook. |
Delete a webhook
Requires authentication
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/webhooks/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "http://localhost/api/v1/webhooks/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/webhooks/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "DELETE",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
HTTP Request
DELETE api/v1/webhooks/{webhook}
URL Parameters
Parameter | Status | Description |
---|---|---|
id |
required | ID of the webhook |
Update a webhook
Requires authentication
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/webhooks/1", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
'json' => [
"name" => "Example webhook",
"url" => "http://test.example.com",
"method" => "POST",
"events" => [
"0" => "client-created",
"1" => "client-updated",
],
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "http://localhost/api/v1/webhooks/1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{"name":"Example webhook","url":"http:\/\/test.example.com","method":"POST","events":["client-created","client-updated"]}'
const url = new URL("http://localhost/api/v1/webhooks/1");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
let body = {
"name": "Example webhook",
"url": "http:\/\/test.example.com",
"method": "POST",
"events": [
"client-created",
"client-updated"
]
}
fetch(url, {
method: "PUT",
headers: headers,
body: body
})
.then(response => response.json())
.then(json => console.log(json));
Example response (200):
{
"message": "Updated",
"data": {
"id": "1",
"name": "Example webhook",
"method": "POST",
"url": "http:\/\/test.example.com",
"events": [
"client-created",
"client-updated"
]
}
}
HTTP Request
PUT api/v1/webhooks/{webhook}
URL Parameters
Parameter | Status | Description |
---|---|---|
id |
required | ID of the webhook. |
Body Parameters
Parameter | Type | Status | Description |
---|---|---|---|
name |
string | required | Name of the webhook. |
url |
string | required | URL of the webhook. |
method |
string | required | Request method for the webhook. Currently only POST is supported. |
events |
array | required | An array of supported events, which will trigger this webhook: booking-created , booking-updated , booking-deleted , client-created , client-updated . |
general
api/v1/online-booking/cancellation-settings
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/online-booking/cancellation-settings", [
'headers' => [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Authorization" => "Bearer {token}",
],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "http://localhost/api/v1/online-booking/cancellation-settings" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}"
const url = new URL("http://localhost/api/v1/online-booking/cancellation-settings");
let headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {token}",
}
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
Example response (500):
{
"error": {
"message": "Internal Error",
"status_code": 500
}
}
HTTP Request
GET api/v1/online-booking/cancellation-settings
Errors
The EasyPractice API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is malformed or otherwise invalid. Please double check our API documentation for allowed request parameters. |
401 | Unauthorized -- Your API key is incorrect or has been revoked. Check the Authentication section on how to get an API token. |
403 | Forbidden -- You do not have access rights to the resource. Your API key might be limited to what you can access. |
404 | Not Found -- The resource was not found. |
405 | Method Not Allowed -- The HTTP method you used was incorrect and unsupported for the specific endpoint. |
422 | Unprocessable Entity -- Some or all data provided is invalid for the type of request. Please see the response data for clues about which of the data provided is invalid and why. |
429 | Too Many Requests -- You are making too many requests. |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
Help
If you have any questions regarding our API, you can contact us at api@easypractice.net.
EasyPractice © 2021