Cliento API reference

Base URL: https://api.cliento.com

The Cliento API gives your own systems server-to-server access to your organisation's data in Cliento.

Everything in the API belongs to a location. A location is one place of business, such as one salon or one branch of a car wash. Start with GET /v1/locations to list the locations your key can use. Almost every other call takes a location id in its path. An item can also be read by its id, without its location; see "Identifiers".

This introduction covers what applies to every call. Each part of the reference describes its own API.

Industry-specific APIs

Most APIs are used by every organisation, whatever its industry. A few are made for one industry, such as the Recipes API for hair and beauty and the Vehicles API for automotive. The reference labels such an API with its industry. It can label a single field or value in the same way. The label is information only: the API does not check an organisation's industry, and no call is refused because of it.

Authentication

Create an API key for your organisation and send it on every request:

Authorization: Bearer cl_live_...

A key belongs to one organisation and is shown only once, when it is created. Keep it on your server; never ship it in a browser or mobile app. If a key leaks, revoke it and create a new one.

Each key carries scopes that decide what it may do, for example customers:read and customers:write. A call outside the key's scopes is answered with 403 and code forbidden.

Identifiers

Every id is an opaque string with a prefix that says what it identifies. Store ids as strings and do not parse them: their length and the characters after the prefix may change. An id from one host, such as our staging host, does not exist on another.

An id is enough to read the item it identifies. Every item has a path under its location, such as /v1/locations/{locationId}/persons/{personId}, and one without it, /v1/persons/{personId}. Use the second when you have an id and not its location: an id you stored, or one that another item refers to. It works for an item at any location your key can use, and the answer includes the item's locationId. An id at a location your key cannot use is answered like an id that does not exist, with entity_not_found.

PrefixIdentifiesExample
loc_A locationloc_4fK9xQ2mLr8TzB1vNc7HdW
per_A personper_2QCtWVSaVO7yCRYBj1zsbA
com_A companycom_6Tn3wRd8Kq1Vb5Xs9LmPyA
veh_A vehicleveh_3Ks7pQx2Wn9Tb4Vd6HyRcE
stf_A staff memberstf_7Qm2xLd9Kc4Vb1Ts8HpWzE
mer_A merchantmer_2Rk8sVh3Yq6Nf1Tz0JwUcM
gft_A gift cardgft_7Qm2xN0cT1kPz4Wb9LrEaD
prd_A productprd_5Tg8mPq1Xc7Jd2Ls9WbNrK
mov_A stock movementmov_9Bd2fHk4Mn7Pq1Sv6XzCtA
res_A resourceres_2QCtWVSaVO7yCRYBj1zsbA
rgr_A resource grouprgr_5Jk9wQe2Ty6Nb3Vx8MzLcA
svc_A servicesvc_3Gk8rTn5Ym1Wc7Zp2LdQxB
sgr_A service groupsgr_8Vc2nXd5Rt1Kq7Lm4HwYpZ
rcp_A recipercp_4Kd8sWn2Qy6Hb9Tf3LmVxA
bkg_A bookingbkg_5Rt8mKq2Wn7Xb4Vd9HyLcA
bks_A series of bookingsbks_6Wq2nYd8Rk4Tc9Xb3HmLzP
sal_A salesal_8Hd3kWq5Zn2Tb7Xc4LmPyR

Created and updated times

Persons, companies, vehicles, resources, services, products, gift cards and recipes have createdAt and updatedAt, both in UTC.

updatedAt is the time the stored item last changed. Use it to tell whether your copy of an item is current. createdAt is the time the item was created. It is left out where it is not known, such as for a service created before these times were kept.

A service's updatedAt also moves when one of its resource services is added, changed or removed, because a service is read with them.

Three things do not move updatedAt:

  • A value that changes with time alone, such as a gift card's status when the card expires.
  • A change to the location's own settings, such as its time zone.
  • A barcode that a supplier adds to the catalogue article a product is linked to.

Live and test keys

A key that starts with cl_live_ belongs to an organisation with real data, in production. Every other key starts with cl_test_. In production a cl_test_ key belongs to a sandbox: an organisation of its own on the same API and the same host, with data that is yours to create and throw away. A sandbox sends no SMS or email to customers and takes no payments. Outside production, such as on our staging host, all keys are cl_test_.

Updating

Updates use PATCH and change only what you send. A field you leave out keeps its value. To clear a field, send it as null. One request is applied as a whole or not at all.

Paging

Most lists are paged. Pass the nextCursor of one page as after to get the next, and go on until a page has none. Follow nextCursor even on a list that fits in one page today. Locations, staff and merchants are returned in one response.

A cursor names the last item you read. Some lists refuse a cursor whose item has been removed since, with validation_failed on after. Read the list again from the start when that happens.

Errors

Every non-2xx response has the same JSON body:

{ "code": "validation_failed", "message": "...", "details": { "fieldErrors": { "email": "..." } } }

Branch on code; message is for humans and may change. An id that does not exist, or that your key may not access, is answered with 400 and code entity_not_found. 404 is reserved for a URL that is not an endpoint at all.

Requests are validated strictly: an unknown JSON field is rejected with invalid_request rather than ignored.

Rate limits

Requests are limited per API key. When the limit is exceeded the answer is 429 with code rate_limited and a Retry-After header giving the number of seconds to wait.

A request body may be at most 1 MB, far more than any call needs. A larger one is answered with 413 and code invalid_request.

Versioning

The version is in the URL (/v1). Every operation in the reference is marked stable or preview.

  • A stable operation only changes in backwards-compatible ways: new optional request fields, new response fields and new values in open-ended enumerations. Your client must tolerate response fields and enumeration values it does not know. A breaking change to a stable operation means a new version, and the previous version keeps working during a published deprecation period.
  • A preview operation works and can be built against, but its fields, paths and answers may still change without a new version. Tell us when you build against one, so that we know to make it stable.

New operations can be added at any time.

Amounts

Money is a decimal string in the location's currency, such as "500.00", never a JSON number. Send at most two decimals.

Retrying safely

A timeout or a dropped connection can hide the answer to a request that did succeed. Every call that changes something can be made safe to send again.

Idempotency-Key is the general way. It is a header that every POST, PATCH and DELETE that changes something accepts, and it holds a value you make up for one request, such as a UUID. Send the same value when you retry. The first request runs. For 24 hours every repeat is answered with the first request's answer, marked with the header Idempotent-Replayed: true, and does not run again. A value belongs to the API key it was sent with: the same value sent with another key is a different request. Send one on every write.

  • Using an Idempotency-Key for a different request (another path or body) is refused with 422 and idempotency_key_reused.
  • A repeat that arrives while the first request is still running is refused with 409 and request_in_progress; wait a moment and send it again.
  • An answer of 500 or above is not kept, so a retry runs the request again.
  • A refusal such as validation_failed is kept like any other answer: correct the request and send it with a new Idempotency-Key.

externalReference is a second way, for a call that creates something. It is your own id for what you create, such as an order number or the id in your own system, sent in the body. When a call arrives with a reference that is already in use, nothing is created or changed: the existing item is returned as it is, with 200 instead of 201. A reference that belongs to a customer of another type is refused with duplicate instead. Unlike an Idempotency-Key, a reference lasts as long as the item does, and you can find the item by it later. Persons, companies, vehicles, gift cards and stock documents (the stock changes recorded in one call) take one. When you have an id of your own, send it as well as the header.