Create a service
const url = 'https://api.keptslot.com/v1/services';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"Cut and finish","duration_minutes":45,"buffer_after_minutes":10,"min_lead_minutes":120,"max_advance_days":60,"min_cancel_notice_minutes":1440,"price_cents":4000}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.keptslot.com/v1/services \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "Cut and finish", "duration_minutes": 45, "buffer_after_minutes": 10, "min_lead_minutes": 120, "max_advance_days": 60, "min_cancel_notice_minutes": 1440, "price_cents": 4000 }'This endpoint adds a service. A new service is active.
If you send max_advance_days as 0, the API stores 60.
If you send category_id, the service goes in that category. A
category that is not in this workspace is a 404, and no service is
created.
Authorizations
Section titled “ Authorizations ”Request Body required
Section titled “ Request Body required ”The writable fields of a service. Create and replace use the same
shape. active is not here: use the activate and deactivate endpoints.
A service can be booked on its own, added to a visit as an extra, or
both; standalone and extra_scope say which. A write that leaves
both out makes a service that is booked on its own and is never an
extra. PUT /v1/services/{id} replaces the whole service, so a
replace that leaves them out turns an extra back into a plain service.
A barber’s beard trim is booked on its own and can be added to any
service: standalone: true, extra_scope: all. A salon’s gloss
treatment is only ever added to a colour: standalone: false,
extra_scope: selected, and offered_with_ids holding the colour
service’s id.
object
If you send 0, the API stores 60.
Plain text. It renders on a public page. Render it as text. Do not render it as markup.
Whether booking this service takes a payment. One of none,
full, deposit_fixed or deposit_percent. Left out, it is
none.
The other three fields must match the mode. full needs
price_cents and neither deposit field. deposit_fixed needs
deposit_amount_cents and no percent. deposit_percent needs
deposit_percent and price_cents. none needs neither deposit
field.
Whatever the mode charges must come to more than zero. A price or deposit of 0 is rejected: it would save a service that no customer could ever book, because the payment would be refused at booking time rather than here.
The fixed deposit, in the smallest currency unit. Required by
deposit_fixed and rejected by every other mode.
The deposit as a whole-number percentage of price_cents, from 1 to
100. Required by deposit_percent and rejected by every other mode.
We round the resulting amount half up.
A category of this workspace. POST /v1/services stores it; a
category from another workspace, or one that does not exist, is a
404. PUT /v1/services/{id} ignores it: use
PUT /v1/services/{id}/category.
Whether the service can be booked on its own. Left out, it is
true. When true, duration_minutes must be at least 1; an extra
that is not booked on its own may take 0 minutes.
Which services this one can be added to as an extra. Left out, it
is none. A service with standalone: false must not be none.
Required when extra_scope is selected. Each id must then be an
active service of this workspace that can be booked on its own,
and not this service; an id that is not is a 422 naming it. The
list replaces the one stored before.
Under all and none it is ignored and the stored list is kept,
so the list read from ServiceDetail can be sent back as it is.
Example
{ "name": "Cut and finish", "duration_minutes": 45, "buffer_after_minutes": 10, "min_lead_minutes": 120, "max_advance_days": 60, "min_cancel_notice_minutes": 1440, "price_cents": 4000}Responses
Section titled “ Responses ”The service is created.
The full service, with the rules that drive availability. The Service
schema is the smaller customer-facing view of the same row.
object
Free time held before the appointment.
Free time held after the appointment.
How far ahead a customer must book.
How far ahead a customer can book. If you send 0 on a write, the API stores 60.
How long before the start time cancellation closes. It binds customers only. A secret key cancels at any time. A value of 0 keeps cancellation open until the start time.
The category this service is in. Null means it is in none. Change
it with PUT /v1/services/{id}/category.
See ServiceWrite.
See ServiceWrite.
The services this extra can be added to when extra_scope is
selected. Always present, and [] when there are none. It is
returned under all and none too, so a client switching back to
selected can send the same list again. A service that has since
been deactivated, or can no longer be booked on its own, is left
out.
Example
{ "extra_scope": "none"}The key is missing, malformed or revoked.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}A plan limit refused the request. The fields in the body change with the key type. See the errors guide.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}This is a server route and you sent a publishable key. Send a secret
key from your server. The type field is secret_key_required.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}There is no such resource in this workspace.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}The request body or the query is not valid.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}A fault on our side. Do not retry the same request in a loop. The
type field is internal_error.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}Two writes contended and one was rolled back. The request did nothing.
Retry it. The type field is transient_failure.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}