NAV
php bash javascript

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 {token} header. There are 2 ways to get the token:

Personal Access Tokens

  1. Log in to your EasyPractice account (or create a new account)
  2. Go to the Apps page and activate the API app.
  3. Go to the API Settings page
  4. In the Personal Access Tokens section click on the Create New Token button to generate a new token.
  5. 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.
  6. Add an Authorization header to your requests with the value of Bearer {token} where {token} is your token you copied earlier.

OAuth2 flow

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.

If you would like to set up OAuth2 flow with our API, please get in touch with us at support@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

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/bookings", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
    'query' => [
            "start" => "2019-03-25",
            "end" => "2019-03-25",
            "client_id" => "54347",
            "calendar_id" => "54347",
            "product_id" => "54347",
            "status" => "absent",
            "order_by_date" => "asc",
            "page_size" => "20",
            "page" => "4",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "https://system.easypractice.net/api/v1/bookings" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/bookings");

    let params = {
            "start": "2019-03-25",
            "end": "2019-03-25",
            "client_id": "54347",
            "calendar_id": "54347",
            "product_id": "54347",
            "status": "absent",
            "order_by_date": "asc",
            "page_size": "20",
            "page": "4",
        };
    Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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",
            "type": "client_booking",
            "status": "finished",
            "heading": "",
            "recurring": null,
            "until": null,
            "client_id": 1348,
            "client_name": "John Smith",
            "notify_email": 0,
            "notify_phone": 0,
            "products": [
                {
                    "id": 125,
                    "name": "Main service"
                }
            ]
        },
        {
            "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",
            "type": "Client appointment",
            "status": "finished",
            "heading": "",
            "recurring": null,
            "until": null,
            "client_id": 648,
            "client_name": "Mary Williams",
            "notify_email": 1,
            "notify_phone": 0,
            "products": [
                {
                    "id": 125,
                    "name": "Main service",
                    "addons": [
                        {
                            "id": 434,
                            "name": "Extra time"
                        }
                    ]
                },
                {
                    "id": 264,
                    "name": "Other service"
                }
            ]
        }
    ],
    "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.
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.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/bookings", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "start" => "2019-03-25T10:00:00+02:00",
        "end" => "2019-03-25T10:00:00+02:00",
        "calendar_id" => 54347,
        "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 "https://system.easypractice.net/api/v1/bookings" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"start":"2019-03-25T10:00:00+02:00","end":"2019-03-25T10:00:00+02:00","calendar_id":54347,"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("https://system.easypractice.net/api/v1/bookings");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

let body = {
    "start": "2019-03-25T10:00:00+02:00",
    "end": "2019-03-25T10:00:00+02:00",
    "calendar_id": 54347,
    "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",
        "type": "client_booking",
        "status": "finished",
        "heading": "",
        "recurring": null,
        "until": 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"
                    }
                ]
            }
        ]
    }
}

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/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.
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 notify the client by email.
notify_phone boolean optional Should we notify the client by SMS.
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.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/bookings/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "https://system.easypractice.net/api/v1/bookings/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/bookings/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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",
    "type": "client_booking",
    "status": "finished",
    "heading": "",
    "recurring": null,
    "until": 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"
                }
            ]
        }
    ]
}

Example response (404):

{
    "error": {
        "message": "Not Found",
        "status_code": 404
    }
}

HTTP Request

GET api/v1/bookings/{booking}

Update booking


Requires authentication Updates the booking.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/bookings/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "start" => "2019-03-25T10:00:00+02:00",
        "end" => "2019-03-25T10:00:00+02:00",
        "calendar_id" => 54347,
        "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 "https://system.easypractice.net/api/v1/bookings/1" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"start":"2019-03-25T10:00:00+02:00","end":"2019-03-25T10:00:00+02:00","calendar_id":54347,"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("https://system.easypractice.net/api/v1/bookings/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

let body = {
    "start": "2019-03-25T10:00:00+02:00",
    "end": "2019-03-25T10:00:00+02:00",
    "calendar_id": 54347,
    "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",
        "type": "client_booking",
        "status": "finished",
        "heading": "",
        "recurring": null,
        "until": 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"
                    }
                ]
            }
        ]
    }
}

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.
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 notify the client by email.
notify_phone boolean optional Should we notify the client by SMS.
products array optional The products associated to the appointment.

Delete booking


Requires authentication Deletes the booking.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/bookings/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "https://system.easypractice.net/api/v1/bookings/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/bookings/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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}

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

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
    'query' => [
            "active" => "1",
            "inactive" => "1",
            "has_email" => "1",
            "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 "https://system.easypractice.net/api/v1/clients" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/clients");

    let params = {
            "active": "1",
            "inactive": "1",
            "has_email": "1",
            "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 = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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": "61175736",
            "address": "159 Bailey Brooks",
            "zip": "W10 6DY",
            "city": "Copenhagen",
            "cpr": "1598431234",
            "notes": "Notes about John",
            "profile_image_url": "https:\/\/www.gravatar.com\/avatar\/5ea799d8476cbe0b1965c39e7c7dbd99?d=mm&s=200",
            "created_at": "2019-04-16 11:54:42",
            "tags": []
        },
        {
            "id": 2,
            "name": "Mary Williams",
            "email": "m.williams@mycompany.dk",
            "phone": "43612915",
            "address": "3 Mike Common",
            "zip": "NG34 9HJ",
            "city": "Copenhagen",
            "cpr": "3574261234",
            "notes": "",
            "profile_image_url": "https:\/\/www.gravatar.com\/avatar\/5ea799d8476cbe0b1965c39e7c7dbd99?d=mm&s=200",
            "created_at": "2019-04-20 08:14:21",
            "tags": []
        }
    ],
    "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.
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.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/clients", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "name" => "John Doe",
        "email" => "john.doe@example.com",
        "ean" => 5789012345678,
        "phone" => 7380111233,
        "zip" => "M14 5PT",
        "city" => "Manchester",
        "cpr" => "0123456789",
        "notes" => "Some notes",
        "tags" => [
            [
                "id" => 15,
            ],
            [
                "name" => "Gold clients",
            ],
        ],
    ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "https://system.easypractice.net/api/v1/clients" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"name":"John Doe","email":"john.doe@example.com","ean":5789012345678,"phone":7380111233,"zip":"M14 5PT","city":"Manchester","cpr":"0123456789","notes":"Some notes","tags":[{"id":15},{"name":"Gold clients"}]}'
const url = new URL("https://system.easypractice.net/api/v1/clients");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

let body = {
    "name": "John Doe",
    "email": "john.doe@example.com",
    "ean": 5789012345678,
    "phone": 7380111233,
    "zip": "M14 5PT",
    "city": "Manchester",
    "cpr": "0123456789",
    "notes": "Some notes",
    "tags": [
        {
            "id": 15
        },
        {
            "name": "Gold clients"
        }
    ]
}

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": "7380111233",
        "zip": "M14 5PT",
        "city": "Manchester",
        "cpr": "0123456789",
        "notes": "Some notes"
    }
}

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 without the country code.
zip string optional The Zip/Postcode of the client.
city string optional The City of the client.
cpr string optional The CPR of the client.
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.

Show client


Requires authentication Returns the client data for a given ID.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/clients/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "https://system.easypractice.net/api/v1/clients/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/clients/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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": "61175736",
    "address": "159 Bailey Brooks",
    "zip": "W10 6DY",
    "city": "Copenhagen",
    "cpr": "1598431234",
    "notes": "Notes about John",
    "profile_image_url": "https:\/\/www.gravatar.com\/avatar\/5ea799d8476cbe0b1965c39e7c7dbd99?d=mm&s=200",
    "created_at": "2019-04-16 11:54:42",
    "tags": []
}

Example response (404):

{
    "error": {
        "message": "Not Found",
        "status_code": 404
    }
}

HTTP Request

GET api/v1/clients/{client}

Update client


Requires authentication Updates the client.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/clients/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "name" => "John Doe",
        "email" => "john.doe@example.com",
        "ean" => 5789012345678,
        "phone" => 7380111233,
        "zip" => "M14 5PT",
        "city" => "Manchester",
        "cpr" => "0123456789",
        "notes" => "Some notes",
        "tags" => [
            [
                "id" => 15,
            ],
            [
                "name" => "Gold clients",
            ],
        ],
    ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "https://system.easypractice.net/api/v1/clients/1" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"name":"John Doe","email":"john.doe@example.com","ean":5789012345678,"phone":7380111233,"zip":"M14 5PT","city":"Manchester","cpr":"0123456789","notes":"Some notes","tags":[{"id":15},{"name":"Gold clients"}]}'
const url = new URL("https://system.easypractice.net/api/v1/clients/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

let body = {
    "name": "John Doe",
    "email": "john.doe@example.com",
    "ean": 5789012345678,
    "phone": 7380111233,
    "zip": "M14 5PT",
    "city": "Manchester",
    "cpr": "0123456789",
    "notes": "Some notes",
    "tags": [
        {
            "id": 15
        },
        {
            "name": "Gold clients"
        }
    ]
}

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": "7380111233",
        "zip": "M14 5PT",
        "city": "Manchester",
        "cpr": "0123456789",
        "notes": "Some notes",
        "tags": []
    }
}

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 without the country code.
zip string optional The Zip/Postcode of the client.
city string optional The City of the client.
cpr string optional The CPR of the client.
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.

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.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/clients/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "https://system.easypractice.net/api/v1/clients/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/clients/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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 clients 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.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-tags", [
    'headers' => [
            "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 "https://system.easypractice.net/api/v1/client-tags" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/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 = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

fetch(url, {
    method: "GET",
    headers: headers,
})
    .then(response => response.json())
    .then(json => console.log(json));

Example response (200):

{
    "data": [
        {
            "id": 1,
            "name": "Premium clients"
        },
        {
            "id": 2,
            "name": "Gold clients"
        }
    ],
    "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 clients tag.


Requires authentication Creates a new clients tag with the given data.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/client-tags", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "name" => "Premium clients",
    ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "https://system.easypractice.net/api/v1/client-tags" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"name":"Premium clients"}'
const url = new URL("https://system.easypractice.net/api/v1/client-tags");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

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"
    }
}

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 clients tag.


Requires authentication Returns the clients tag data for a given ID.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/client-tags/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "https://system.easypractice.net/api/v1/client-tags/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/client-tags/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

fetch(url, {
    method: "GET",
    headers: headers,
})
    .then(response => response.json())
    .then(json => console.log(json));

Example response (200):

{
    "id": 1,
    "name": "Premium clients"
}

Example response (404):

{
    "error": {
        "message": "Not Found",
        "status_code": 404
    }
}

HTTP Request

GET api/v1/client-tags/{client_tag}

Update clients tag.


Requires authentication Updates the clients tag.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->put("api/v1/client-tags/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "name" => "Premium clients",
    ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X PUT "https://system.easypractice.net/api/v1/client-tags/1" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"name":"Premium clients"}'
const url = new URL("https://system.easypractice.net/api/v1/client-tags/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

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"
    }
}

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 clients tag.


Requires authentication Removes the clients tag from the user's account.

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->delete("api/v1/client-tags/1", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X DELETE "https://system.easypractice.net/api/v1/client-tags/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/client-tags/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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}

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

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->get("api/v1/invoices", [
    'headers' => [
            "Authorization" => "Bearer {token}",
        ],
    'query' => [
            "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 "https://system.easypractice.net/api/v1/invoices" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/invoices");

    let params = {
            "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 = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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,
            "paid": true,
            "credited": false,
            "status": "paid",
            "clientname": "John Doe",
            "clientcpr": "123456-7890",
            "clientaddress": "54 Harry Lane",
            "clientzip": "1234",
            "clientcity": "Copenhagen",
            "payment_type": "card",
            "currency": "DKK",
            "total": 625,
            "lines": [
                {
                    "id": 23,
                    "invoice_id": 1,
                    "position": 0,
                    "amount": 1,
                    "price": 500,
                    "vat": true,
                    "vat_rate": 25,
                    "total_without_vat": 500,
                    "total": 625,
                    "text": "Client appointment",
                    "comment": "",
                    "booking_description": "Appointment Tuesday 16 April 2019, 16:05"
                }
            ]
        },
        {
            "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,
            "paid": true,
            "credited": false,
            "status": "paid",
            "clientname": "Jaimes Armsworth",
            "clientcpr": "121212-7890",
            "clientaddress": "4 Snow Street",
            "clientzip": "5454",
            "clientcity": "Copenhagen",
            "payment_type": "card",
            "currency": "DKK",
            "total": 1500,
            "lines": [
                {
                    "...": "..."
                },
                {
                    "...": "..."
                }
            ]
        }
    ],
    "links": {
        "...": "..."
    },
    "meta": {
        "...": "..."
    }
}

HTTP Request

GET api/v1/invoices

Query Parameters

Parameter Status Description
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

Example request:


$client = new \GuzzleHttp\Client();
$response = $client->post("api/v1/invoices/1/mark-as-paid", [
    'headers' => [
            "Authorization" => "Bearer {token}",
            "Content-Type" => "application/json",
        ],
    'json' => [
        "date" => "2019-05-16",
        "payment_type" => "card",
        "amount" => 1500,
        "currency" => "DKK",
    ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X POST "https://system.easypractice.net/api/v1/invoices/1/mark-as-paid" \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{"date":"2019-05-16","payment_type":"card","amount":1500,"currency":"DKK"}'
const url = new URL("https://system.easypractice.net/api/v1/invoices/1/mark-as-paid");

let headers = {
    "Authorization": "Bearer {token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

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 payed 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.

Services

List services


Requires authentication Returns all of user's services. Use the filter options provided to narrow down 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' => [
            "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 "https://system.easypractice.net/api/v1/services" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/services");

    let params = {
            "order_by_name": "asc",
            "page_size": "20",
            "page": "4",
        };
    Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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": 0,
            "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,
            "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.
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' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "https://system.easypractice.net/api/v1/services/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/services/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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": 0,
    "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,
    "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' => [
            "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 "https://system.easypractice.net/api/v1/addons" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/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 = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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' => [
            "Authorization" => "Bearer {token}",
        ],
]);
$body = $response->getBody();
print_r(json_decode((string) $body));
curl -X GET -G "https://system.easypractice.net/api/v1/addons/1" \
    -H "Authorization: Bearer {token}"
const url = new URL("https://system.easypractice.net/api/v1/addons/1");

let headers = {
    "Authorization": "Bearer {token}",
    "Accept": "application/json",
    "Content-Type": "application/json",
}

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}