Introduction
The Booqable API is a RESTful JSON API as such is designed to have predictable, resource-oriented URLs and to use HTTP response codes to indicate API errors. We use standard HTTP features, like HTTP authentication and HTTP verbs, which can be understood by off-the-shelf HTTP clients.
Endpoint
All API requests need to be directed to the correct company-specific endpoint. The format is as follows:
https://{company_slug}.booqable.com/api/4/
Response types
The Booqable API supports two response types jsonapi and json.
By default, the API returns jsonapi responses. These responses are designed to return graph data more efficiently and also include links to related resources.
You can, however, also request data in nested structure by appending .json to the path of each request.
A typical JSON API response:
GET /api/4/orders?include=customer
{
"data": [
{
"id": "54808378-a247-4715-89f6-0a8da2e7ad62",
"type": "orders",
"attributes": {
"starts_at": "2021-11-12T15:00:00+00:00",
"stops_at": "2021-11-13T15:00:00+00:00"
},
"relationships": {
"customer": {
"links": {
"related": "api/4/customers/24e54970-7473-49a9-a71a-8c07eb97e510"
},
"data": {
"type": "customers",
"id": "24e54970-7473-49a9-a71a-8c07eb97e510"
}
}
}
}
],
"included": [
{
"id": "24e54970-7473-49a9-a71a-8c07eb97e510",
"type": "customers",
"attributes": {
"name": "John Doe"
},
"relationships": {
"properties": {
"links": {
"related": "api/4/properties?filter[owner_id]=24e54970-7473-49a9-a71a-8c07eb97e510&filter[owner_type]=Customer"
}
}
}
}
],
"links": {
"self": "api/4/orders?fields%5Bcustomer%5D=name&fields%5Borders%5D=starts_at%2Cstops_at&include=customer&page%5Bnumber%5D=1&page%5Bsize%5D=25",
"first": "api/4/orders?fields%5Bcustomer%5D=name&fields%5Borders%5D=starts_at%2Cstops_at&include=customer&page%5Bnumber%5D=1&page%5Bsize%5D=25",
"last": "api/4/orders?fields%5Bcustomer%5D=name&fields%5Borders%5D=starts_at%2Cstops_at&include=customer&page%5Bnumber%5D=1&page%5Bsize%5D=25"
},
"meta": {}
}
A JSON response:
GET /api/4/orders.json?include=customer
{
"data": [
{
"id": "30d35575-c8d1-4f5c-b4c6-cc0abc32c6ed",
"starts_at": "2021-11-12T15:15:00+00:00",
"stops_at": "2021-11-13T15:15:00+00:00",
"customer": {
"id": "92ec8fee-423e-4f7e-8565-3e6028a0f437",
"name": "John Doe"
}
}
]
}
Fields
For every resource, fields can be written, read, filtered, sorted, and aggregated. The behavior of fields is described for each resource.
On every request, you can specify fields to be returned in the response. Note that you can also specify fields of included resources.
Including specific fields can be done like this:
?fields[orders]=starts_at,stops_at&fields[plannings]=reserved_from,reserved_till
Filtering
Collections returned in list requests can be filtered on specific fields; filters support the following operators:
| Type | Operators |
|---|---|
| String | eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
| Uuid | eq, not_eq |
| Enum | eq, not_eq |
| Integer | eq, not_eq, gt, gte, lt, lte |
| Integer | eq, not_eq, gt, gte, lt, lte |
| Big Decimal | eq, not_eq, gt, gte, lt, lte |
| Float | eq, not_eq, gt, gte, lt, lte |
| Boolean | eq |
| Date | eq, not_eq, gt, gte, lt, lte |
| DateTime | eq, not_eq, gt, gte, lt, lte |
| Hash | eq |
| Array | eq |
How to filter a request:
/api/4/orders?filter[starts_at][gte]=1980-11-16T09:00:00+00:00&filter[starts_at][lte]=1990-11-16T09:00:00+00:00&filter[status]=reserved
Includes
The Booqable API consists of many resources related to each other. Therefore the API supports loading associated resources in a single request. Use the dot-syntax to deeply nest includes.
Including associated data:
GET api/4/orders?include=customer,customer.properties
{
"data": {
"id": "f2afdb0e-55bd-4993-b9c2-4f04b569419d",
"type": "orders",
"attributes": {
"starts_at": "2021-11-12T16:00:00+00:00",
"stops_at": "2021-11-13T16:00:00+00:00"
},
"relationships": {
"customer": {
"links": {
"related": "api/4/customers/404021af-c889-4d72-9296-481640f4c750"
},
"data": {
"type": "customers",
"id": "404021af-c889-4d72-9296-481640f4c750"
}
},
}
},
"included": [
{
"id": "404021af-c889-4d72-9296-481640f4c750",
"type": "customers",
"attributes": {
"name": "John Doe"
},
"relationships": {
"properties": {
"links": {
"related": "api/4/properties?filter[owner_id]=404021af-c889-4d72-9296-481640f4c750&filter[owner_type]=Customer"
},
"data": [
{
"type": "properties",
"id": "9625bd15-732e-4301-8c1c-f5b3e03c1bed"
}
]
},
}
},
{
"id": "9625bd15-732e-4301-8c1c-f5b3e03c1bed",
"type": "properties",
"attributes": {
"name": "Phone",
"value": "+31600000000"
},
"relationships": {
"owner": {
"links": {
"related": "api/4/customers/404021af-c889-4d72-9296-481640f4c750"
}
}
}
}
],
"meta": {}
}
Stats
Results from list requests can be aggregated by providing stats. These stats are always computed over the unpaginated filtered collection. The following aggregations are supported: count, count_each, average, sum, maximum, minimum. You can supply multiple types for each field.
Example of how to request stats:
?stats[to_be_paid_in_cents][]=sum&stats[grand_total_in_cents][]=average&stats[grand_total_in_cents][]=sum&stats[total]=count&stats[payment_status]=count
"meta": {
"stats": {
"to_be_paid_in_cents": {
"sum": 79000
},
"grand_total_in_cents": {
"average": 25000,
"sum": 1198000
},
"total": {
"count": 237
},
"payment_status": {
"count": {
"payment_due": 161,
"paid": 51,
"partially_paid": 13,
"overpaid": 11,
"process_deposit": 1
}
}
}
}
Sideposting
Due to the nature of actions in the API, the API does not support official JSON API compliant side posting. Instead, actions are designed in a way that related resources are managed automatically.
There are a few exceptions though, in these cases, resources can be created or associated by setting:
{resource_name}_attributesarray of resources to create, update and associate.{resource_name}_idsarray of resources to associate.{resource_name}_idid off the resource to associate.
When side posting is supported, it will be mentioned in the resource-specific documentation.
Advanced search
The following resources support advanced searching with POST requests:
- Order
- Item
- Bundle
- ProductGroup
- Product
- Document
- Planning
- Customer
With advanced search you can make logical filter groups with and/or operators. The example on the right yields:
(starts_at >= date AND starts_at <= date) OR (stops_at >= date AND stops_at <= date)
{
"filter": {
"conditions": {
"operator": "or",
"attributes": [
{
"operator": "and",
"attributes": [
{
"starts_at": {
"gte": "2022-04-27T12:54:37Z"
}
},
{
"starts_at": {
"lte": "2022-04-30T12:54:37Z"
}
}
]
},
{
"operator": "and",
"attributes": [
{
"stops_at": {
"gte": "2022-04-27T12:54:37Z"
}
},
{
"stops_at": {
"lte": "2022-04-30T12:54:37Z"
}
}
]
}
]
}
}
}
Authentication
To interact with the Booqable API, first, you have to have a means of authentification, here's how to setup authentication.
Access Token
- Go to your account settings page
{company-name-here}.booqable.com/employees/current - Name your new token
- Click "Create new authentication method"
You can manage your Access Tokens from your account. You can have multiple Access Tokens active at one time.
Example of an authorized request
curl --request GET \
--url 'https://example.booqable.com/api/4/customers' \
--header 'Authorization: Bearer 9bcabeaa827810ad6383d2e15feab2d0c7d039093e22fdd955f11fe83437a32a'
You authenticate to the Booqable API by providing on of your Access Tokens in the request.
Request signing
Single-Use Tokens to sign requests are generated on the client and can only be used once for one particular request. The Booqable API supports the following signing algorithms:
ES256RS256HS256
- Go to your account settings page
{company-name-here}.booqable.com/employees/current - Name your new authentication method
- Insert your public key (for
ES256andRS256only) - Click "Create new authentication method"
You can manage your authentication methods from your account. You can have multiple authentication methods active at one time.
Signing a request (in Ruby, other languages should work like this as well)
# To prevent tampering with the request (making a DELETE from a GET, or posting different params with
# the same signature) we include all request data in the data value. Note that we generate a SHA256 from it.
request_method = 'POST'
# Encoded request params
fullpath = '/api/4/orders/?filter%5Bcreated_at%5D%5Bgte%5D%3D1231232131132'
# Base64 encoded SHA256 body
body = '{"note":"Let me in!"}'
encoded_body = Base64.strict_encode64(::OpenSSL::Digest::SHA256.new(body).digest)
# Compute data value
data = Base64.strict_encode64(
::OpenSSL::Digest::SHA256.new([request_method, fullpath, encoded_body].join('.').join('.')).digest
)
# Generate a unique request identifier (can be anything unique)
uuid = Digest::UUID.uuid_v4
# We define the authentication method id (which you have obtained in a previous step) and kind in the header
headers = { kid: authentication_method_id, kind: 'single_use' }
payload = {
iss: 'http://company-name.booqable.com',
sub: employee_id,
aud: company_id,
exp: (Time.current + 10.minutes).to_i, # Can not exceed 10 minutes
iat: Time.current.to_i,
jti: "#{uuid}.#{data}"
}
# Note that with HS256 you don't have to supply a public key but a secret is generated for you.
token = JWT.encode payload, private_key, 'ES256', headers
token #=> eyJraWQiOiIwZTJkM2I2YS00OTU0LTQyZTItYTAyNS1kYjMzODE1ZDU2YzUiLCJraW5kIjoic2luZ2xlX3VzZSIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwOi8vY29tcGFueS1uYW1lLmJvb3FhYmxlLmNvbSIsInN1YiI6IjVlMWViZmFmLWM5YmEtNDMyOC1hM2U1LThlNzNmZGQ1NGNiOSIsImF1ZCI6IjE4ZGI4YTE0LThhYzctNDE1OS05NmJkLTMxMzI0NmRhYTExMCIsImV4cCI6MTYzNTk0ODk3MiwiaWF0IjoxNjM1OTQ4MzcyLCJqdGkiOiJmMTNkZjNlOC0zMWNjLTQxYTUtOWVlNy1mZjgzMTdmNWQ0Y2EuVUU5VFZDNHZQMlpwYkhSbGNpVTFRbU55WldGMFpXUmZZWFFsTlVRbE5VSm5kR1VsTlVRbE0wUXhNak14TWpNeU1UTXhNVE15TGpWemNGcEhSak5IZFdVeVoycFZRVVZ3ZUhsVll6VTVVbTlIZW5sb2NHMXNWbVo0WlVGNVRrSlZUazA5In0.7S2eI3R6meFPPgZ5iyZQOsTDBHRCihKozKMjvIrNHeYoEsxzKltQhGjb2rnfSlpGrCL38-ub-FTs5EXP39rJfw
The algorithm to generate the data value in the payload looks like this:
Base64(
SHA256(
[
request_method,
encoded_request_fullpath_with_paramaters,
Base64(
SHA256(request_body)
)
].join('.')
)
)
Example of an authorized request
curl --request GET \
--url 'https://example.booqable.com/api/4/customers' \
--header 'Authorization: Bearer eyJraWQiOiIwZTJkM2I2YS00OTU0LTQyZTItYTAyNS1kYjMzODE1ZDU2YzUiLCJraW5kIjoic2luZ2xlX3VzZSIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwOi8vY29tcGFueS1uYW1lLmJvb3FhYmxlLmNvbSIsInN1YiI6IjVlMWViZmFmLWM5YmEtNDMyOC1hM2U1LThlNzNmZGQ1NGNiOSIsImF1ZCI6IjE4ZGI4YTE0LThhYzctNDE1OS05NmJkLTMxMzI0NmRhYTExMCIsImV4cCI6MTYzNTk0ODk3MiwiaWF0IjoxNjM1OTQ4MzcyLCJqdGkiOiJmMTNkZjNlOC0zMWNjLTQxYTUtOWVlNy1mZjgzMTdmNWQ0Y2EuVUU5VFZDNHZQMlpwYkhSbGNpVTFRbU55WldGMFpXUmZZWFFsTlVRbE5VSm5kR1VsTlVRbE0wUXhNak14TWpNeU1UTXhNVE15TGpWemNGcEhSak5IZFdVeVoycFZRVVZ3ZUhsVll6VTVVbTlIZW5sb2NHMXNWbVo0WlVGNVRrSlZUazA5In0.7S2eI3R6meFPPgZ5iyZQOsTDBHRCihKozKMjvIrNHeYoEsxzKltQhGjb2rnfSlpGrCL38-ub-FTs5EXP39rJfw
You authenticate to the Booqable API by signing the request.
Errors
The Booqable API uses the following error codes:
| Error Code | Meaning |
|---|---|
| 400 | Bad Request -- Your request is invalid. |
| 401 | Unauthorized -- You are not authenticated. |
| 403 | Forbidden -- The resource requested is hidden for administrators only. |
| 404 | Not Found -- The specified resource could not be found. |
| 405 | Method Not Allowed -- You tried to access a resource with an invalid method. |
| 406 | Not Acceptable -- You requested a format that isn't json. |
| 410 | Gone -- The resource requested has been removed from our servers. |
| 418 | I'm a teapot. |
| 422 | Unprocessible Entity -- Something wen't wrong saving your data. |
| 429 | Too Many Requests -- You're doing too many requests! Slow down! |
| 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. |
Resources
Authentication methods
Authentication methods define ways to authenticate with the API. They are always scoped to the currently signed-in employee.
See Authentication for more information on authenticating with the API.
Relationships
| Name | Description |
|---|---|
company |
Company requiredThe company this authentication method belongs to. |
employee |
Employee requiredThe employee this authentication method belongs to. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
algorithm |
enum Algorithm used for signing. One of: ES256, RS256, HS256. |
company_id |
uuid readonlyThe company this authentication method belongs to. |
created_at |
datetime readonlyWhen this authentication method was created. |
employee_id |
uuid readonlyThe employee this authentication method belongs to. |
id |
uuid readonlyPrimary key. |
key |
string extraKey that is being used for authentication strategy. Because this key is supposed to be kept secret (depending on kind), its value is only returned when explicitly requested. |
kind |
enum Kind of strategy used for authentication. One of: token, single_use, oauth. |
name |
string Name of the key (for identification by user). |
List authentication methods
How to fetch a list of authentication methods:
curl --get 'https://example.booqable.com/api/4/authentication_methods'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "63e16d3e-a24d-4137-8fc5-dc94f18a5068",
"type": "authentication_methods",
"attributes": {
"created_at": "2019-09-26T20:08:02.000000+00:00",
"updated_at": "2019-09-26T20:08:02.000000+00:00",
"name": "Segment integration",
"kind": "single_use",
"algorithm": "ES256",
"employee_id": "ca0083cb-ea69-4e2b-8270-e691e0599f5e",
"company_id": "b5c213f3-bf74-40ee-825d-3fd6219fc0a0"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/authentication_methods
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[authentication_methods]=key |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[authentication_methods]=created_at,name,kind |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
algorithm |
enum eq |
company_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
employee_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
kind |
enum eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch an authentication method
How to fetch an authentication method:
curl --get 'https://example.booqable.com/api/4/authentication_methods/874482c4-c602-4605-8e8f-bdd68bc4e0fe'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "874482c4-c602-4605-8e8f-bdd68bc4e0fe",
"type": "authentication_methods",
"attributes": {
"created_at": "2014-12-11T10:59:01.000000+00:00",
"updated_at": "2014-12-11T10:59:01.000000+00:00",
"name": "Segment integration",
"kind": "single_use",
"algorithm": "ES256",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEDRq3Sua6NyUU0WusNISEcchCLBL\nShY0rPpRLfU+Y96OcMiSWaKazYmQDKq4zyIVLlnGiHjv4lwEfhe3Psr39A==\n-----END PUBLIC KEY-----\n",
"employee_id": "24cc151b-daa4-48f0-8535-f63d7ec20fe7",
"company_id": "84e60c43-023a-4c37-809c-a941cbac102a"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/authentication_methods/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[authentication_methods]=key |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[authentication_methods]=created_at,name,kind |
Includes
This request does not accept any includes
Create an authentication method
How to create a token authentication method:
curl --request POST
--url 'https://example.booqable.com/api/4/authentication_methods'
--header 'content-type: application/json'
--data '{
"data": {
"type": "authentication_methods",
"attributes": {
"name": "Segment integration"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "220c0989-a7b1-4962-884e-01ee74df46dc",
"type": "authentication_methods",
"attributes": {
"created_at": "2027-11-18T02:17:01.000000+00:00",
"updated_at": "2027-11-18T02:17:01.000000+00:00",
"name": "Segment integration",
"kind": "token",
"algorithm": null,
"key": "821465b1c39ad8d8584eee99c158868d986e7291281dfbedf3855cc9142c197a",
"employee_id": "d6313cd4-52d0-4f71-87e9-0a5fbd855b19",
"company_id": "d79aa57f-76cb-483a-8e40-c25404c26a5d"
},
"relationships": {}
},
"meta": {}
}
How to create a single_use authentication method (with ES256 strategy):
curl --request POST
--url 'https://example.booqable.com/api/4/authentication_methods'
--header 'content-type: application/json'
--data '{
"data": {
"type": "authentication_methods",
"attributes": {
"name": "Segment integration",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEDRq3Sua6NyUU0WusNISEcchCLBL\nShY0rPpRLfU+Y96OcMiSWaKazYmQDKq4zyIVLlnGiHjv4lwEfhe3Psr39A==\n-----END PUBLIC KEY-----\n",
"kind": "single_use",
"algorithm": "ES256"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "e53a56a3-0f4e-4bd6-8bab-dad967b320b3",
"type": "authentication_methods",
"attributes": {
"created_at": "2021-04-10T18:40:01.000000+00:00",
"updated_at": "2021-04-10T18:40:01.000000+00:00",
"name": "Segment integration",
"kind": "single_use",
"algorithm": "ES256",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEDRq3Sua6NyUU0WusNISEcchCLBL\nShY0rPpRLfU+Y96OcMiSWaKazYmQDKq4zyIVLlnGiHjv4lwEfhe3Psr39A==\n-----END PUBLIC KEY-----\n",
"employee_id": "75a59189-d0d6-4668-8c8b-83903cf22d08",
"company_id": "031ece0d-d2c2-4b5a-86ac-e2eb24560de5"
},
"relationships": {}
},
"meta": {}
}
How to create a single_use authentication method (with RS256 strategy):
curl --request POST
--url 'https://example.booqable.com/api/4/authentication_methods'
--header 'content-type: application/json'
--data '{
"data": {
"type": "authentication_methods",
"attributes": {
"name": "Segment integration",
"key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtRuZD4X3MhIz1ntbxpkp\njVFUTdH7mspUNXmE0bcQ3bJrgWYZmtPm64+lpo7KWqQIL28dhtNAjImJmzcr04ve\nRAxxyQT0f0uwe3zUBEqaxKim1aCJV60c71cPKJVfhXElnjhMkBW6ftIEgf7J4bwe\n7kPCK/NfdiOuFlMjfaY+5WmaA1lAZ/SSetwglSaHPPQKaix3LW4ocHtHUd7OBKNC\nIU/DO3baUDAkymF7ZCnMaf3F9Le9sGSpgUA8Fof69rH1EdagQFmIkftflj/IlJiC\nPDEoc1x7b4opEuGp287S+DsRRgr6vzVZi4CPQcJJsG+07jZQN5K3wboBlx8LW2jT\nfQIDAQAB\n-----END PUBLIC KEY-----\n",
"kind": "single_use",
"algorithm": "RS256"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "f8a49c93-c272-4014-82f7-aaee9e656a32",
"type": "authentication_methods",
"attributes": {
"created_at": "2014-10-08T04:38:01.000000+00:00",
"updated_at": "2014-10-08T04:38:01.000000+00:00",
"name": "Segment integration",
"kind": "single_use",
"algorithm": "RS256",
"key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtRuZD4X3MhIz1ntbxpkp\njVFUTdH7mspUNXmE0bcQ3bJrgWYZmtPm64+lpo7KWqQIL28dhtNAjImJmzcr04ve\nRAxxyQT0f0uwe3zUBEqaxKim1aCJV60c71cPKJVfhXElnjhMkBW6ftIEgf7J4bwe\n7kPCK/NfdiOuFlMjfaY+5WmaA1lAZ/SSetwglSaHPPQKaix3LW4ocHtHUd7OBKNC\nIU/DO3baUDAkymF7ZCnMaf3F9Le9sGSpgUA8Fof69rH1EdagQFmIkftflj/IlJiC\nPDEoc1x7b4opEuGp287S+DsRRgr6vzVZi4CPQcJJsG+07jZQN5K3wboBlx8LW2jT\nfQIDAQAB\n-----END PUBLIC KEY-----\n",
"employee_id": "bc3373ee-ee17-4d83-8c01-3b200bf8bdb3",
"company_id": "faf47d6b-8d0b-4ac5-8892-c0590faa0054"
},
"relationships": {}
},
"meta": {}
}
How to create a single_use authentication method (with HS256 strategy):
curl --request POST
--url 'https://example.booqable.com/api/4/authentication_methods'
--header 'content-type: application/json'
--data '{
"data": {
"type": "authentication_methods",
"attributes": {
"name": "Segment integration",
"kind": "single_use",
"algorithm": "HS256"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "29c57921-3618-445f-89ac-84463b0ae952",
"type": "authentication_methods",
"attributes": {
"created_at": "2028-10-03T00:29:01.000000+00:00",
"updated_at": "2028-10-03T00:29:01.000000+00:00",
"name": "Segment integration",
"kind": "single_use",
"algorithm": "HS256",
"key": "cb991b0f11304f313a1487b2cb22a067eb4b03da8499bd2f833df79d83045110",
"employee_id": "777ef44e-2bce-40e3-85dc-63792f9f0c22",
"company_id": "61df6c42-088c-4fa3-8860-b75b9c114770"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/authentication_methods
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[authentication_methods]=key |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[authentication_methods]=created_at,name,kind |
include |
string List of comma seperated relationships to sideload. ?include=employee,company |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][algorithm] |
enum Algorithm used for signing. One of: ES256, RS256, HS256. |
data[attributes][key] |
string Key that is being used for authentication strategy. Because this key is supposed to be kept secret (depending on kind), its value is only returned when explicitly requested. |
data[attributes][kind] |
enum Kind of strategy used for authentication. One of: token, single_use, oauth. |
data[attributes][name] |
string Name of the key (for identification by user). |
Includes
This request accepts the following includes:
companyemployee
Delete an authentication method
How to delete an authentication method:
curl --request DELETE
--url 'https://example.booqable.com/api/4/authentication_methods/ef2b6529-43ac-4e66-8ab9-bd2950729b50'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "ef2b6529-43ac-4e66-8ab9-bd2950729b50",
"type": "authentication_methods",
"attributes": {
"created_at": "2021-11-06T06:35:01.000000+00:00",
"updated_at": "2021-11-06T06:35:01.000000+00:00",
"name": "Segment integration",
"kind": "single_use",
"algorithm": "ES256",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEDRq3Sua6NyUU0WusNISEcchCLBL\nShY0rPpRLfU+Y96OcMiSWaKazYmQDKq4zyIVLlnGiHjv4lwEfhe3Psr39A==\n-----END PUBLIC KEY-----\n",
"employee_id": "792a5596-9c55-46ab-8317-6c0651512e04",
"company_id": "5da72e2c-3b67-4d80-88c1-6e96acba5c58"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/authentication_methods/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[authentication_methods]=key |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[authentication_methods]=created_at,name,kind |
Includes
This request does not accept any includes
Barcodes
You can assign Barcodes to Product (variations), individually tracked StockItems, and Customers (for use on a customer card, for example).
A QR code is always generated for each Order. This QR code can be included in emails for speedy pickup and printed on packing slips for easier logistics.
Barcodes cannot be added to ProductGroups. Instead Barcodes can be added to individual Products within the ProductGroup. This is also true when a ProductGroup does not have variations enabled. In that case a Barcode is added to the single Product in the group.
Supported formats
Booqable supports the following barcode formats:
- QR code: QR codes are flexible in size, have high fault tolerance, and fast readability.
- EAN-8: Ideal for identifying small items, stores eight digits.
- EAN-13: Can store a relatively large amount of data (13 digits) in a small area.
- Code 39: Stores both digits and characters. The size of the barcode makes them unsuitable to use on small items.
- Code 93: A more compact alternative to Code 39 (about 25% shorter).
- Code 128: A high-density barcode that can store any character of the ASCII 128 character set.
Note that when using URLs as numbers, it's advised to base64 encode the number before filtering.
Relationships
| Name | Description |
|---|---|
owner |
Customer, Product, Order, Stock item requiredThe resource pointed to by this Barcode. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
barcode_type |
enum Barcode format. See resource description above for pros/cons of each format. One of: code39, code93, code128, ean8, ean13, qr_code. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
image_url |
string readonlyA link to an image of the Barcode. |
number |
string The barcode data, can be a number, code or url. Leave blank to let Booqable create one. When using a URL, it's advised to base64 encode the number before filtering. |
owner_id |
uuid readonly-after-createThe resource pointed to by this Barcode. |
owner_type |
enum readonly-after-createThe resource type of the owner. One of: customers, products, orders, stock_items. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List barcodes
How to fetch a list of barcodes:
curl --get 'https://example.booqable.com/api/4/barcodes'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "c3fbfdf6-d756-4d88-89c7-974df32dc31f",
"type": "barcodes",
"attributes": {
"created_at": "2026-11-20T19:16:00.000000+00:00",
"updated_at": "2026-11-20T19:16:00.000000+00:00",
"number": "http://bqbl.it/c3fbfdf6-d756-4d88-89c7-974df32dc31f",
"barcode_type": "qr_code",
"image_url": "http://company-name-28.lvh.me/barcodes/c3fbfdf6-d756-4d88-89c7-974df32dc31f/image",
"owner_id": "2318a321-06f9-4303-8d23-b46cfb189aeb",
"owner_type": "customers"
},
"relationships": {}
}
],
"meta": {}
}
How to find an owner by a barcode number:
curl --get 'https://example.booqable.com/api/4/barcodes'
--header 'content-type: application/json'
--data-urlencode 'filter[number]=http://bqbl.it/9882a0de-d425-4c34-8a53-f65dd35dd375'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": [
{
"id": "9882a0de-d425-4c34-8a53-f65dd35dd375",
"type": "barcodes",
"attributes": {
"created_at": "2021-09-12T13:49:00.000000+00:00",
"updated_at": "2021-09-12T13:49:00.000000+00:00",
"number": "http://bqbl.it/9882a0de-d425-4c34-8a53-f65dd35dd375",
"barcode_type": "qr_code",
"image_url": "http://company-name-29.lvh.me/barcodes/9882a0de-d425-4c34-8a53-f65dd35dd375/image",
"owner_id": "48f38dad-4082-4377-8d28-c793e2d1c814",
"owner_type": "customers"
},
"relationships": {
"owner": {
"data": {
"type": "customers",
"id": "48f38dad-4082-4377-8d28-c793e2d1c814"
}
}
}
}
],
"included": [
{
"id": "48f38dad-4082-4377-8d28-c793e2d1c814",
"type": "customers",
"attributes": {
"created_at": "2021-09-12T13:49:00.000000+00:00",
"updated_at": "2021-09-12T13:49:00.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
How to find an owner by a barcode number containing a url:
curl --get 'https://example.booqable.com/api/4/barcodes'
--header 'content-type: application/json'
--data-urlencode 'filter[number]=aHR0cDovL2JxYmwuaXQvZTBlYmNmODgtZjhlZS00NmQ3LWJjZWUtMDRhZTQ0OWYzZTU5'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": [
{
"id": "78a5e268-fca0-450a-855f-49f29ef29ef3",
"type": "barcodes",
"attributes": {
"created_at": "2023-09-26T19:48:00.000000+00:00",
"updated_at": "2023-09-26T19:48:00.000000+00:00",
"number": "http://bqbl.it/78a5e268-fca0-450a-855f-49f29ef29ef3",
"barcode_type": "qr_code",
"image_url": "http://company-name-30.lvh.me/barcodes/78a5e268-fca0-450a-855f-49f29ef29ef3/image",
"owner_id": "ab6232e0-b056-4bf8-8bc7-99c41f2782de",
"owner_type": "customers"
},
"relationships": {
"owner": {
"data": {
"type": "customers",
"id": "ab6232e0-b056-4bf8-8bc7-99c41f2782de"
}
}
}
}
],
"included": [
{
"id": "ab6232e0-b056-4bf8-8bc7-99c41f2782de",
"type": "customers",
"attributes": {
"created_at": "2023-09-26T19:48:00.000000+00:00",
"updated_at": "2023-09-26T19:48:00.000000+00:00",
"archived": false,
"archived_at": null,
"number": 2,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/barcodes
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[barcodes]=created_at,updated_at,number |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=owner |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
barcode_type |
enum eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
number |
string eq |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
-
ownerphoto-
productphoto
Fetch a barcode
How to fetch a barcode:
curl --get 'https://example.booqable.com/api/4/barcodes/60d46666-056c-4072-8fd0-cae57d7a90ff'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": {
"id": "60d46666-056c-4072-8fd0-cae57d7a90ff",
"type": "barcodes",
"attributes": {
"created_at": "2023-11-26T10:01:03.000000+00:00",
"updated_at": "2023-11-26T10:01:03.000000+00:00",
"number": "http://bqbl.it/60d46666-056c-4072-8fd0-cae57d7a90ff",
"barcode_type": "qr_code",
"image_url": "http://company-name-31.lvh.me/barcodes/60d46666-056c-4072-8fd0-cae57d7a90ff/image",
"owner_id": "9a08fa5a-eddb-4502-8e1e-60dbd303cb58",
"owner_type": "customers"
},
"relationships": {
"owner": {
"data": {
"type": "customers",
"id": "9a08fa5a-eddb-4502-8e1e-60dbd303cb58"
}
}
}
},
"included": [
{
"id": "9a08fa5a-eddb-4502-8e1e-60dbd303cb58",
"type": "customers",
"attributes": {
"created_at": "2023-11-26T10:01:03.000000+00:00",
"updated_at": "2023-11-26T10:01:03.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/barcodes/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[barcodes]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
-
ownerphoto-
productphoto
Create a barcode
How to create a barcode:
curl --request POST
--url 'https://example.booqable.com/api/4/barcodes'
--header 'content-type: application/json'
--data '{
"data": {
"type": "barcodes",
"attributes": {
"barcode_type": "qr_code",
"owner_id": "9d177e60-f890-4d0a-8dc6-44d61d8cca22",
"owner_type": "customers"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "954b9fd3-271d-4ab4-8a7e-87e89b15c0a0",
"type": "barcodes",
"attributes": {
"created_at": "2019-09-24T03:44:00.000000+00:00",
"updated_at": "2019-09-24T03:44:00.000000+00:00",
"number": "http://bqbl.it/954b9fd3-271d-4ab4-8a7e-87e89b15c0a0",
"barcode_type": "qr_code",
"image_url": "http://company-name-32.lvh.me/barcodes/954b9fd3-271d-4ab4-8a7e-87e89b15c0a0/image",
"owner_id": "9d177e60-f890-4d0a-8dc6-44d61d8cca22",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/barcodes
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[barcodes]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][barcode_type] |
enum Barcode format. See resource description above for pros/cons of each format. One of: code39, code93, code128, ean8, ean13, qr_code. |
data[attributes][number] |
string The barcode data, can be a number, code or url. Leave blank to let Booqable create one. When using a URL, it's advised to base64 encode the number before filtering. |
data[attributes][owner_id] |
uuid The resource pointed to by this Barcode. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: customers, products, orders, stock_items. |
Includes
This request accepts the following includes:
-
ownerphoto-
productphoto
Update a barcode
How to update a barcode:
curl --request PUT
--url 'https://example.booqable.com/api/4/barcodes/d4f58d8f-2318-44f4-8097-9dbe2a9ddaf2'
--header 'content-type: application/json'
--data '{
"data": {
"id": "d4f58d8f-2318-44f4-8097-9dbe2a9ddaf2",
"type": "barcodes",
"attributes": {
"number": "https://myfancysite.com"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "d4f58d8f-2318-44f4-8097-9dbe2a9ddaf2",
"type": "barcodes",
"attributes": {
"created_at": "2021-10-11T03:09:01.000000+00:00",
"updated_at": "2021-10-11T03:09:01.000000+00:00",
"number": "https://myfancysite.com",
"barcode_type": "qr_code",
"image_url": "http://company-name-33.lvh.me/barcodes/d4f58d8f-2318-44f4-8097-9dbe2a9ddaf2/image",
"owner_id": "a8f4104c-a6da-44d0-8505-a590b71bb780",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/barcodes/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[barcodes]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][barcode_type] |
enum Barcode format. See resource description above for pros/cons of each format. One of: code39, code93, code128, ean8, ean13, qr_code. |
data[attributes][number] |
string The barcode data, can be a number, code or url. Leave blank to let Booqable create one. When using a URL, it's advised to base64 encode the number before filtering. |
data[attributes][owner_id] |
uuid The resource pointed to by this Barcode. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: customers, products, orders, stock_items. |
Includes
This request accepts the following includes:
-
ownerphoto-
productphoto
Destroy a barcode
How to delete a barcode:
curl --request DELETE
--url 'https://example.booqable.com/api/4/barcodes/ac988a7e-ebdc-45af-8638-9783aeb4594e'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "ac988a7e-ebdc-45af-8638-9783aeb4594e",
"type": "barcodes",
"attributes": {
"created_at": "2023-03-27T06:20:00.000000+00:00",
"updated_at": "2023-03-27T06:20:00.000000+00:00",
"number": "http://bqbl.it/ac988a7e-ebdc-45af-8638-9783aeb4594e",
"barcode_type": "qr_code",
"image_url": "http://company-name-34.lvh.me/barcodes/ac988a7e-ebdc-45af-8638-9783aeb4594e/image",
"owner_id": "20fbc832-70a9-45dd-84fd-848ee269b502",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/barcodes/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[barcodes]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
-
ownerphoto-
productphoto
Bundles
Bundles allow for a single product to be made up of multiple other products. This makes it possible to offer customers a set of products that logically go together as a single package, for a single price, and with a combined availability.
Bundles are composed from BundleItems, which describe which products are included, how many of them, and the discount for each product.
There are two types of bundles:
"fixed" or "specified": The products are fixed, and the customer does not get to choose.
"unspecified": One or more of the products in the bundle has multiple product variations, and the customer gets to choose from them. In this case, pricing and availability of the bundle depends on the customer's selected product variation.
Relationships
| Name | Description |
|---|---|
bundle_items |
Bundle items hasmanyThe bundle items that make up this bundle. |
inventory_levels |
Inventory levels hasmanyAvailability of this bundle. Because bundles do not exist on a physical level (they are a collection of products), the returned availability will be the maximum number of bundles that can be made from the available products (bundle availability is restricted by the least available product). |
photo |
Photo optionalPrimary photo of this bundle. |
photos |
Photos hasmanyAll photos of this bundle. The primary photo must be selected from this set. |
tax_category |
Tax category optionalTax category for tax calculations. When present, this tax category overrides the tax category of the individual products. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the bundle is archived. |
archived_at |
datetime readonly nullableWhen the bundle was archived. |
bundle_items_attributes |
array writeonlyWriting to this attribute allows to create or update bundle items at the same time as the bundle itself. |
created_at |
datetime readonlyWhen the resource was created. |
description |
string nullableDescription used in the online store. |
discountable |
boolean Whether discounts should be applied to items in this bundle. |
excerpt |
string nullableExcerpt used in the online store. |
extra_information |
string nullableExtra information about the bundle, shown on orders and documents. |
id |
uuid readonlyPrimary key. |
name |
string Name of the bundle. |
photo_base64 |
string writeonlyBase64 encoded photo, use this field to store a main photo. |
photo_id |
uuid readonly nullablePrimary photo of this bundle. |
photo_url |
string readonlyMain photo URL. |
product_type |
enum readonlyAlways bundle. This attribute exists because bundles are a kind of Item.Always bundle |
remote_photo_url |
string writeonlyURL to an image on the web. |
seo_description |
string nullableSEO meta description tag. |
seo_title |
string nullableSEO title tag. |
show_in_store |
boolean Whether to show this item in the online store. |
slug |
string Slug of the bundle. |
sorting_weight |
integer Defines sort order in the online store, the lower the weight - the higher it shows up in lists. |
tag_list |
array List of tags. |
tax_category_id |
uuid nullableTax category for tax calculations. When present, this tax category overrides the tax category of the individual products. |
taxable |
boolean Whether this bundle is taxable. |
type |
string readonlyAlways bundles. This attribute exists because bundles are a kind of Item. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List bundles
How to fetch a list of bundles:
curl --get 'https://example.booqable.com/api/4/bundles'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "18ffd1b4-8468-4bad-82c1-1e7f370f600f",
"type": "bundles",
"attributes": {
"created_at": "2020-11-21T17:08:01.000000+00:00",
"updated_at": "2020-11-21T17:08:01.000000+00:00",
"archived": false,
"archived_at": null,
"type": "bundles",
"name": "iPad Bundle",
"slug": "ipad-bundle",
"product_type": "bundle",
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"photo_id": null,
"tax_category_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/bundles
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundles]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=photo,inventory_levels |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
product_type |
enum eq |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
show_in_store |
boolean eq |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
discountable |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
Includes
This request accepts the following includes:
inventory_levelsphoto
Search bundles
Use advanced search to make logical filter groups with and/or operators.
How to search for bundles:
curl --request POST
--url 'https://example.booqable.com/api/4/bundles/search'
--header 'content-type: application/json'
--data '{
"fields": {
"bundles": "id"
},
"filter": {
"conditions": {
"operator": "or",
"attributes": [
{
"operator": "and",
"attributes": [
{
"discountable": true
},
{
"taxable": true
}
]
},
{
"operator": "and",
"attributes": [
{
"show_in_store": true
},
{
"taxable": true
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "ea409533-a730-4d13-8149-036b51248925"
},
{
"id": "16552c0c-85c9-4d79-81d8-862b15da8a16"
},
{
"id": "714cbc42-5133-4ee2-8945-1fb6391bfbc8"
}
]
}
HTTP Request
POST /api/4/bundles/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundles]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=photo,inventory_levels |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
product_type |
enum eq |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
show_in_store |
boolean eq |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
discountable |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
Includes
This request accepts the following includes:
inventory_levelsphoto
Fetch a bundle
How to fetch a bundle:
curl --get 'https://example.booqable.com/api/4/bundles/7a7aeed9-35dd-40fe-8ece-5551e24ce953'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "7a7aeed9-35dd-40fe-8ece-5551e24ce953",
"type": "bundles",
"attributes": {
"created_at": "2027-01-01T09:13:00.000000+00:00",
"updated_at": "2027-01-01T09:13:00.000000+00:00",
"archived": false,
"archived_at": null,
"type": "bundles",
"name": "iPad Bundle",
"slug": "ipad-bundle",
"product_type": "bundle",
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"photo_id": null,
"tax_category_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/bundles/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundles]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=photo,bundle_items,tax_category |
Includes
This request accepts the following includes:
-
bundle_items-
productphoto
-
product_groupphoto-
productsphoto
-
phototax_category
Create a bundle
How to create a bundle with bundle items:
curl --request POST
--url 'https://example.booqable.com/api/4/bundles'
--header 'content-type: application/json'
--data '{
"include": "bundle_items",
"data": {
"type": "bundles",
"attributes": {
"name": "iPad Pro Bundle",
"bundle_items_attributes": [
{
"quantity": 2,
"discount_percentage": 10,
"product_group_id": "1a247a34-c748-422e-8f6e-1a6d3992c656",
"product_id": "ca3c0fbf-03ac-4a05-8a65-d5bab132b59d"
},
{
"quantity": 2,
"discount_percentage": 15,
"product_group_id": "bf793cc3-ff25-497e-8a92-6cf9a8d99fa0",
"product_id": "07b0cf35-6809-4bec-8350-2dbe5a39a565"
}
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "2f4b77bd-2e6d-4454-8933-babc61ed151f",
"type": "bundles",
"attributes": {
"created_at": "2020-05-21T17:38:00.000000+00:00",
"updated_at": "2020-05-21T17:38:00.000000+00:00",
"archived": false,
"archived_at": null,
"type": "bundles",
"name": "iPad Pro Bundle",
"slug": "ipad-pro-bundle",
"product_type": "bundle",
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"photo_id": null,
"tax_category_id": null
},
"relationships": {
"bundle_items": {
"data": [
{
"type": "bundle_items",
"id": "df0b9888-284d-4211-8aa3-7c4bd3922ad5"
},
{
"type": "bundle_items",
"id": "f6e42e06-fab0-4f46-8f8e-ea8a9422304b"
},
{
"type": "bundle_items",
"id": "ae082f3d-ff30-456b-8adb-5b4919c8417a"
},
{
"type": "bundle_items",
"id": "0a030633-4d84-4191-8e44-c52eb68d811a"
}
]
}
}
},
"included": [
{
"id": "df0b9888-284d-4211-8aa3-7c4bd3922ad5",
"type": "bundle_items",
"attributes": {
"created_at": "2020-05-21T17:38:00.000000+00:00",
"updated_at": "2020-05-21T17:38:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 10.0,
"position": 1,
"bundle_id": "2f4b77bd-2e6d-4454-8933-babc61ed151f",
"product_group_id": "1a247a34-c748-422e-8f6e-1a6d3992c656",
"product_id": "ca3c0fbf-03ac-4a05-8a65-d5bab132b59d"
},
"relationships": {}
},
{
"id": "f6e42e06-fab0-4f46-8f8e-ea8a9422304b",
"type": "bundle_items",
"attributes": {
"created_at": "2020-05-21T17:38:00.000000+00:00",
"updated_at": "2020-05-21T17:38:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 2,
"bundle_id": "2f4b77bd-2e6d-4454-8933-babc61ed151f",
"product_group_id": "bf793cc3-ff25-497e-8a92-6cf9a8d99fa0",
"product_id": "07b0cf35-6809-4bec-8350-2dbe5a39a565"
},
"relationships": {}
},
{
"id": "ae082f3d-ff30-456b-8adb-5b4919c8417a",
"type": "bundle_items",
"attributes": {
"created_at": "2020-05-21T17:38:00.000000+00:00",
"updated_at": "2020-05-21T17:38:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 10.0,
"position": 3,
"bundle_id": "2f4b77bd-2e6d-4454-8933-babc61ed151f",
"product_group_id": "1a247a34-c748-422e-8f6e-1a6d3992c656",
"product_id": "ca3c0fbf-03ac-4a05-8a65-d5bab132b59d"
},
"relationships": {}
},
{
"id": "0a030633-4d84-4191-8e44-c52eb68d811a",
"type": "bundle_items",
"attributes": {
"created_at": "2020-05-21T17:38:00.000000+00:00",
"updated_at": "2020-05-21T17:38:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 4,
"bundle_id": "2f4b77bd-2e6d-4454-8933-babc61ed151f",
"product_group_id": "bf793cc3-ff25-497e-8a92-6cf9a8d99fa0",
"product_id": "07b0cf35-6809-4bec-8350-2dbe5a39a565"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/bundles
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundles]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=photo,bundle_items,tax_category |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][bundle_items_attributes][] |
array Writing to this attribute allows to create or update bundle items at the same time as the bundle itself. |
data[attributes][discountable] |
boolean Whether discounts should be applied to items in this bundle. |
data[attributes][excerpt] |
string Excerpt used in the online store. |
data[attributes][extra_information] |
string Extra information about the bundle, shown on orders and documents. |
data[attributes][name] |
string Name of the bundle. |
data[attributes][photo_base64] |
string Base64 encoded photo, use this field to store a main photo. |
data[attributes][remote_photo_url] |
string URL to an image on the web. |
data[attributes][seo_description] |
string SEO meta description tag. |
data[attributes][seo_title] |
string SEO title tag. |
data[attributes][show_in_store] |
boolean Whether to show this item in the online store. |
data[attributes][slug] |
string Slug of the bundle. |
data[attributes][sorting_weight] |
integer Defines sort order in the online store, the lower the weight - the higher it shows up in lists. |
data[attributes][tag_list][] |
array List of tags. |
data[attributes][tax_category_id] |
uuid Tax category for tax calculations. When present, this tax category overrides the tax category of the individual products. |
data[attributes][taxable] |
boolean Whether this bundle is taxable. |
Includes
This request accepts the following includes:
-
bundle_items-
productphoto
-
product_groupphoto
-
phototax_category
Update a bundle
How to update a bundle with bundle items:
curl --request PUT
--url 'https://example.booqable.com/api/4/bundles/ed81707b-f578-4a6e-82e8-062f3b5ae2d9'
--header 'content-type: application/json'
--data '{
"include": "bundle_items",
"data": {
"id": "ed81707b-f578-4a6e-82e8-062f3b5ae2d9",
"type": "bundles",
"attributes": {
"name": "iPad Pro Bundle",
"bundle_items_attributes": [
{
"id": "3357b030-9385-4491-843f-9bd93e88723a",
"_destroy": true
},
{
"quantity": 2,
"discount_percentage": 15,
"product_group_id": "a9609021-9ac0-45e8-8bfa-03c58a577154",
"product_id": "abff6839-af87-4377-857e-2b217552945d"
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "ed81707b-f578-4a6e-82e8-062f3b5ae2d9",
"type": "bundles",
"attributes": {
"created_at": "2023-01-20T01:56:00.000000+00:00",
"updated_at": "2023-01-20T01:56:00.000000+00:00",
"archived": false,
"archived_at": null,
"type": "bundles",
"name": "iPad Pro Bundle",
"slug": "ipad-bundle",
"product_type": "bundle",
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"photo_id": null,
"tax_category_id": null
},
"relationships": {
"bundle_items": {
"data": [
{
"type": "bundle_items",
"id": "ddfe9f02-abf5-48bd-8fba-334decb8c339"
},
{
"type": "bundle_items",
"id": "d5abce78-6f6d-46ef-8e46-876a07eb7133"
}
]
}
}
},
"included": [
{
"id": "ddfe9f02-abf5-48bd-8fba-334decb8c339",
"type": "bundle_items",
"attributes": {
"created_at": "2023-01-20T01:56:00.000000+00:00",
"updated_at": "2023-01-20T01:56:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 2,
"bundle_id": "ed81707b-f578-4a6e-82e8-062f3b5ae2d9",
"product_group_id": "a9609021-9ac0-45e8-8bfa-03c58a577154",
"product_id": "abff6839-af87-4377-857e-2b217552945d"
},
"relationships": {}
},
{
"id": "d5abce78-6f6d-46ef-8e46-876a07eb7133",
"type": "bundle_items",
"attributes": {
"created_at": "2023-01-20T01:56:00.000000+00:00",
"updated_at": "2023-01-20T01:56:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 3,
"bundle_id": "ed81707b-f578-4a6e-82e8-062f3b5ae2d9",
"product_group_id": "a9609021-9ac0-45e8-8bfa-03c58a577154",
"product_id": "abff6839-af87-4377-857e-2b217552945d"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
PUT /api/4/bundles/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundles]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=photo,bundle_items,tax_category |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][bundle_items_attributes][] |
array Writing to this attribute allows to create or update bundle items at the same time as the bundle itself. |
data[attributes][discountable] |
boolean Whether discounts should be applied to items in this bundle. |
data[attributes][excerpt] |
string Excerpt used in the online store. |
data[attributes][extra_information] |
string Extra information about the bundle, shown on orders and documents. |
data[attributes][name] |
string Name of the bundle. |
data[attributes][photo_base64] |
string Base64 encoded photo, use this field to store a main photo. |
data[attributes][remote_photo_url] |
string URL to an image on the web. |
data[attributes][seo_description] |
string SEO meta description tag. |
data[attributes][seo_title] |
string SEO title tag. |
data[attributes][show_in_store] |
boolean Whether to show this item in the online store. |
data[attributes][slug] |
string Slug of the bundle. |
data[attributes][sorting_weight] |
integer Defines sort order in the online store, the lower the weight - the higher it shows up in lists. |
data[attributes][tag_list][] |
array List of tags. |
data[attributes][tax_category_id] |
uuid Tax category for tax calculations. When present, this tax category overrides the tax category of the individual products. |
data[attributes][taxable] |
boolean Whether this bundle is taxable. |
Includes
This request accepts the following includes:
-
bundle_items-
productphoto
-
product_groupphoto
-
phototax_category
Archive a bundle
How to delete a bundle:
curl --request DELETE
--url 'https://example.booqable.com/api/4/bundles/ec090d58-5e64-4db7-89ae-80f6bcdd3d22'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "ec090d58-5e64-4db7-89ae-80f6bcdd3d22",
"type": "bundles",
"attributes": {
"created_at": "2023-08-27T09:39:03.000000+00:00",
"updated_at": "2023-08-27T09:39:03.000000+00:00",
"archived": true,
"archived_at": "2023-08-27T09:39:03.000000+00:00",
"type": "bundles",
"name": "iPad Bundle",
"slug": "ec090d58-5e64-4db7-89ae-80f6bcdd3d22",
"product_type": "bundle",
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"photo_id": null,
"tax_category_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/bundles/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundles]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Bundle items
Bundle items define which products (variations) and product groups are included in a Bundle. When bundles are booked on an order, the quantity and discount percentage defined in a bundle item will be applied.
There are two types of bundle items:
"fixed" or "specified": The
product_idis set and fixed, and the customer does not get to choose. These BundleItems do not need to be specified when booking a bundle."unspecified": The
product_idisnull, and the customer gets to choose one of the product variations. These BundleItems must to be specified when booking a bundle.
Relationships
| Name | Description |
|---|---|
bundle |
Bundle requiredThe Bundle this BundleItem is part of. |
product |
Product optionalWhen non-null, then this is the prespecified Product that will be booked. When null, then the user has to choose a product variation from the product_group. This relation is required when product_group does not have variations. |
product_group |
Product group requiredWhen the product relation is non-null, then this is the ProductGroup that the Product belongs to. When the product relation is null, then this is the ProductGroup that the user has to choose a product variation from. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the bundle item is archived. |
archived_at |
datetime readonly nullableWhen the bundle item was archived. |
bundle_id |
uuid readonly-after-createThe Bundle this BundleItem is part of. |
created_at |
datetime readonlyWhen the resource was created. |
discount_percentage |
float The discount percentage for this product when rented out as part of a bundle. |
id |
uuid readonlyPrimary key. |
position |
integer Position of this bundle item within the bundle. I.e sorting relative to other bundle items. |
product_group_id |
uuid readonly-after-createWhen the product relation is non-null, then this is the ProductGroup that the Product belongs to. When the product relation is null, then this is the ProductGroup that the user has to choose a product variation from. |
product_id |
uuid nullableWhen non-null, then this is the prespecified Product that will be booked. When null, then the user has to choose a product variation from the product_group. This relation is required when product_group does not have variations. |
quantity |
integer The quantity of the product included in the bundle. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List bundle items
How to fetch a list of bundle items:
curl --get 'https://example.booqable.com/api/4/bundle_items'
--header 'content-type: application/json'
--data-urlencode 'filter[bundle_id]=b484afb9-abf3-4598-8fce-44d5d5c62784'
A 200 status response looks like this:
{
"data": [
{
"id": "3e60cc8c-7215-4b14-8a74-8fe96f550d33",
"type": "bundle_items",
"attributes": {
"created_at": "2019-11-14T16:12:00.000000+00:00",
"updated_at": "2019-11-14T16:12:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 1,
"bundle_id": "b484afb9-abf3-4598-8fce-44d5d5c62784",
"product_group_id": "935f7965-5c06-44eb-8472-f9aa3f1e036e",
"product_id": "567ad7e5-6130-401e-84a8-d966a6ae6717"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/bundle_items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundle_items]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=bundle,product,product_group |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
bundle_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
position |
integer eq, not_eq, gt, gte, lt, lte |
product_group_id |
uuid eq, not_eq |
product_id |
uuid eq, not_eq |
quantity |
integer eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
bundle-
productphoto
-
product_groupphoto
Fetch a bundle item
How to fetch a bundle item:
curl --get 'https://example.booqable.com/api/4/bundle_items/613a8167-828e-4728-8f62-810a41cd2ba5'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "613a8167-828e-4728-8f62-810a41cd2ba5",
"type": "bundle_items",
"attributes": {
"created_at": "2015-08-13T03:51:01.000000+00:00",
"updated_at": "2015-08-13T03:51:01.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 1,
"bundle_id": "2201586a-dcc4-4803-8d2c-2e6d02541f2b",
"product_group_id": "08475ef9-150e-4113-8035-9a10812b06e9",
"product_id": "56cf4f31-b9ac-4968-8899-b81f09e246a6"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/bundle_items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundle_items]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=bundle,product,product_group |
Includes
This request accepts the following includes:
bundle-
productphoto
-
product_groupphoto
Create a bundle item
How to create a bundle item:
curl --request POST
--url 'https://example.booqable.com/api/4/bundle_items'
--header 'content-type: application/json'
--data '{
"data": {
"type": "bundle_items",
"attributes": {
"bundle_id": "aadf38b5-6d5e-4c54-8d7b-7cce2b00801a",
"product_group_id": "9bc50456-e92e-4162-8610-8f8ca7323b5b",
"product_id": "6fb4ee32-8b29-439a-856d-9847696afb13",
"quantity": 2,
"discount_percentage": 15
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "3b9d771b-6d67-42d8-83b3-289dedbb7a1e",
"type": "bundle_items",
"attributes": {
"created_at": "2018-09-16T12:53:01.000000+00:00",
"updated_at": "2018-09-16T12:53:01.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 2,
"discount_percentage": 15.0,
"position": 2,
"bundle_id": "aadf38b5-6d5e-4c54-8d7b-7cce2b00801a",
"product_group_id": "9bc50456-e92e-4162-8610-8f8ca7323b5b",
"product_id": "6fb4ee32-8b29-439a-856d-9847696afb13"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/bundle_items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundle_items]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=bundle,product,product_group |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][bundle_id] |
uuid The Bundle this BundleItem is part of. |
data[attributes][discount_percentage] |
float The discount percentage for this product when rented out as part of a bundle. |
data[attributes][position] |
integer Position of this bundle item within the bundle. I.e sorting relative to other bundle items. |
data[attributes][product_group_id] |
uuid When the product relation is non-null, then this is the ProductGroup that the Product belongs to. When the product relation is null, then this is the ProductGroup that the user has to choose a product variation from. |
data[attributes][product_id] |
uuid When non-null, then this is the prespecified Product that will be booked. When null, then the user has to choose a product variation from the product_group. This relation is required when product_group does not have variations. |
data[attributes][quantity] |
integer The quantity of the product included in the bundle. |
Includes
This request accepts the following includes:
bundle-
productphoto
-
product_groupphoto
Update a bundle item
How to update a bundle item:
curl --request PUT
--url 'https://example.booqable.com/api/4/bundle_items/b19d7917-4360-464c-8add-3d8003786467'
--header 'content-type: application/json'
--data '{
"data": {
"id": "b19d7917-4360-464c-8add-3d8003786467",
"type": "bundle_items",
"attributes": {
"quantity": 3,
"discount_percentage": 20
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "b19d7917-4360-464c-8add-3d8003786467",
"type": "bundle_items",
"attributes": {
"created_at": "2015-01-21T01:26:00.000000+00:00",
"updated_at": "2015-01-21T01:26:00.000000+00:00",
"archived": false,
"archived_at": null,
"quantity": 3,
"discount_percentage": 20.0,
"position": 1,
"bundle_id": "f53691b2-481e-4f06-8b42-70a8260e0bea",
"product_group_id": "997ec012-e358-4a2c-8bb9-97674479ed4f",
"product_id": "73f4eef3-b748-4cd0-8f75-0e013f461872"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/bundle_items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundle_items]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=bundle,product,product_group |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][bundle_id] |
uuid The Bundle this BundleItem is part of. |
data[attributes][discount_percentage] |
float The discount percentage for this product when rented out as part of a bundle. |
data[attributes][position] |
integer Position of this bundle item within the bundle. I.e sorting relative to other bundle items. |
data[attributes][product_group_id] |
uuid When the product relation is non-null, then this is the ProductGroup that the Product belongs to. When the product relation is null, then this is the ProductGroup that the user has to choose a product variation from. |
data[attributes][product_id] |
uuid When non-null, then this is the prespecified Product that will be booked. When null, then the user has to choose a product variation from the product_group. This relation is required when product_group does not have variations. |
data[attributes][quantity] |
integer The quantity of the product included in the bundle. |
Includes
This request accepts the following includes:
bundle-
productphoto
-
product_groupphoto
Delete a bundle item
How to delete a bundle item:
curl --request DELETE
--url 'https://example.booqable.com/api/4/bundle_items/791f0c17-84d2-4362-8ad5-b097d71cf9e6'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "791f0c17-84d2-4362-8ad5-b097d71cf9e6",
"type": "bundle_items",
"attributes": {
"created_at": "2021-05-16T17:50:00.000000+00:00",
"updated_at": "2021-05-16T17:50:00.000000+00:00",
"archived": true,
"archived_at": "2021-05-16T17:50:00.000000+00:00",
"quantity": 2,
"discount_percentage": 15.0,
"position": 1,
"bundle_id": "04391a33-673f-4548-89e1-44e58bdfb28a",
"product_group_id": "bb5d0ce6-7858-4bcf-8875-352bd5587852",
"product_id": "98855843-4132-4178-8120-0393eaf5604f"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/bundle_items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[bundle_items]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Clusters
A cluster is a group of locations that share their inventory (and availability). Stock can move between locations within the same cluster, meaning they can be picked up at one location and returned to another.
Relationships
| Name | Description |
|---|---|
locations |
Locations hasmanyThe Locations that make up this cluster. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
location_ids |
array readonly-after-createThe Locations that belong to this cluster. |
name |
string Name of the cluster. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List clusters
How to fetch clusters:
curl --get 'https://example.booqable.com/api/4/clusters'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "c85988b4-e5f9-4b7b-8e84-59dc91306d07",
"type": "clusters",
"attributes": {
"created_at": "2017-04-19T16:54:00.000000+00:00",
"updated_at": "2017-04-19T16:54:00.000000+00:00",
"name": "Main",
"location_ids": []
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/clusters
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[clusters]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=locations |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
location_id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
locations
Fetch a cluster
How to fetch a single cluster:
curl --get 'https://example.booqable.com/api/4/clusters/242d27bb-1ff5-41ca-80d5-dd4a2c675525'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "242d27bb-1ff5-41ca-80d5-dd4a2c675525",
"type": "clusters",
"attributes": {
"created_at": "2014-08-27T15:06:00.000000+00:00",
"updated_at": "2014-08-27T15:06:00.000000+00:00",
"name": "Main",
"location_ids": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/clusters/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[clusters]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=locations |
Includes
This request accepts the following includes:
locations
Create a cluster
How to create a cluster:
curl --request POST
--url 'https://example.booqable.com/api/4/clusters'
--header 'content-type: application/json'
--data '{
"data": {
"type": "clusters",
"attributes": {
"name": "Amsterdam"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "a4eb298e-c8b8-4b40-85cf-ec9dbbf68a92",
"type": "clusters",
"attributes": {
"created_at": "2024-06-20T05:57:00.000000+00:00",
"updated_at": "2024-06-20T05:57:00.000000+00:00",
"name": "Amsterdam",
"location_ids": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/clusters
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[clusters]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=locations |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][location_ids][] |
array The Locations that belong to this cluster. |
data[attributes][name] |
string Name of the cluster. |
Includes
This request accepts the following includes:
locations
Update a cluster
How to update a cluster:
curl --request PUT
--url 'https://example.booqable.com/api/4/clusters/df280d1c-34d7-4b2d-89d8-289bf254f317'
--header 'content-type: application/json'
--data '{
"data": {
"id": "df280d1c-34d7-4b2d-89d8-289bf254f317",
"type": "clusters",
"attributes": {
"name": "Rotterdam"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "df280d1c-34d7-4b2d-89d8-289bf254f317",
"type": "clusters",
"attributes": {
"created_at": "2020-06-22T20:42:09.000000+00:00",
"updated_at": "2020-06-22T20:42:09.000000+00:00",
"name": "Rotterdam",
"location_ids": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/clusters/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[clusters]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=locations |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][location_ids][] |
array The Locations that belong to this cluster. |
data[attributes][name] |
string Name of the cluster. |
Includes
This request accepts the following includes:
locations
Delete a cluster
To delete a cluster make sure no active locations are associated with it anymore.
How to delete a cluster:
curl --request DELETE
--url 'https://example.booqable.com/api/4/clusters/79f093e1-f668-4a70-8e91-6f10c351314a'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "79f093e1-f668-4a70-8e91-6f10c351314a",
"type": "clusters",
"attributes": {
"created_at": "2019-06-18T06:27:00.000000+00:00",
"updated_at": "2019-06-18T06:27:00.000000+00:00",
"name": "Main",
"location_ids": []
},
"relationships": {}
},
"meta": {}
}
A failure due to a cluster still being associated with locations:
curl --request DELETE
--url 'https://example.booqable.com/api/4/clusters/475d542a-ad19-4eea-87be-bdc3a2726baf'
--header 'content-type: application/json'
A 422 status response looks like this:
{
"errors": [
{
"code": "cluster_has_locations",
"status": "422",
"title": "Cluster has locations",
"detail": "This cluster has 1 or more active locations",
"meta": {
"location_ids": [
"cfa08864-2479-40cd-81ac-e6426c3c303a"
]
}
}
]
}
HTTP Request
DELETE /api/4/clusters/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[clusters]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=locations |
Includes
This request accepts the following includes:
locations
Collections
Collections are used to create a hierarchy of products.
To change the ordering of items within a collection, use Sortings.
Relationships
| Name | Description |
|---|---|
collection_items |
Collection items hasmanyAll items that make up this collection. Each collection item adds either a ProductGroup or a Bundle to this collection. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
all_children |
array readonly extraAll child collections. |
all_parents |
array readonly extraAll parent collections. |
collection_type |
enum readonly-after-createDynamic collections are automatically updated. Static collections are defined by the user. One of: static, dynamic. |
created_at |
datetime readonlyWhen the resource was created. |
depth |
integer readonlyHow deep this collection sits in the hierarchy. Depth 1 represents top-level collections, depth 2 represents children, and depth 3 represents grandchildren. Nesting is limited to 3 levels. |
description |
string A description of this collection. |
external_image_url |
string writeonlyURL to an image on the web, use this field to add a photo. |
hierarchical_name |
array[string] readonly extraNames of all parents, with the name of this collection as last. |
id |
uuid readonlyPrimary key. |
image_base64 |
string writeonlyBase64 encoded photo, use this field to add a photo. |
image_large_url |
string readonlyURL of the large image for this collection. |
image_url |
string readonlyURL of the image for this collection. |
item_count |
integer Number of collection items in this collection that are visible in the store. Only includes items where show_in_store is true. Includes collection items in this collection, but not in nested collections.This count is automatically recalculated when items are added, removed, or when their show_in_store status changes. |
name |
string Name of this collection. |
parent_id |
uuid The ID of the parent collection. |
position |
integer readonlyRelative position of this collection among its siblings within the same parent collection. |
remote_image_url |
string writeonlyURL to an image on the web, use this field to add a photo. |
remove_image |
boolean writeonlyRemove the current image. |
seo_description |
string SEO description. |
seo_title |
string SEO title. |
show_in_store |
boolean Whether to show this collection in the online store. |
slug |
string Slug used in online store URLs. |
system |
boolean When true, this collection is generated and maintained automatically by Booqable. System collections cannot be updated or deleted. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List collections
How to fetch collections:
curl --get 'https://example.booqable.com/api/4/collections'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "e8b928ec-172a-4655-80f9-eea1a1be9c89",
"type": "collections",
"attributes": {
"created_at": "2015-11-17T02:13:02.000000+00:00",
"updated_at": "2015-11-17T02:13:02.000000+00:00",
"name": "All Seasons",
"slug": "all-seasons",
"description": null,
"seo_title": null,
"seo_description": null,
"collection_type": "manual",
"system": false,
"item_count": 0,
"show_in_store": true,
"parent_id": null,
"depth": 1,
"position": null,
"image_url": null,
"image_large_url": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/collections
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collections]=all_parents,all_children,hierarchical_name |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collections]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
collection_type |
enum eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
depth |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
hierarchical_q |
string eq |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
parent_id |
uuid eq, not_eq |
position |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
show_in_store |
boolean eq |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
system |
boolean eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a collection
How to fetch a single collection:
curl --get 'https://example.booqable.com/api/4/collections/e747596e-eb84-4e15-8b4e-9b160d64633c'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "e747596e-eb84-4e15-8b4e-9b160d64633c",
"type": "collections",
"attributes": {
"created_at": "2021-12-02T10:21:01.000000+00:00",
"updated_at": "2021-12-02T10:21:01.000000+00:00",
"name": "All Seasons",
"slug": "all-seasons",
"description": null,
"seo_title": null,
"seo_description": null,
"collection_type": "manual",
"system": false,
"item_count": 0,
"show_in_store": true,
"parent_id": null,
"depth": 1,
"position": null,
"image_url": null,
"image_large_url": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/collections/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collections]=all_parents,all_children,hierarchical_name |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collections]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=collection_items |
Includes
This request accepts the following includes:
-
collection_items-
itemphoto
-
Create a collection
How to create a collection:
curl --request POST
--url 'https://example.booqable.com/api/4/collections'
--header 'content-type: application/json'
--data '{
"data": {
"type": "collections",
"attributes": {
"name": "Spring Collection"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "067fbd40-bc13-4aec-8426-a75cc1a273f8",
"type": "collections",
"attributes": {
"created_at": "2019-04-23T15:23:58.000000+00:00",
"updated_at": "2019-04-23T15:23:58.000000+00:00",
"name": "Spring Collection",
"slug": "spring-collection",
"description": null,
"seo_title": null,
"seo_description": null,
"collection_type": null,
"system": false,
"item_count": 0,
"show_in_store": true,
"parent_id": null,
"depth": 1,
"position": null,
"image_url": null,
"image_large_url": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/collections
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collections]=all_parents,all_children,hierarchical_name |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collections]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=collection_items |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][collection_type] |
enum Dynamic collections are automatically updated. Static collections are defined by the user. One of: static, dynamic. |
data[attributes][external_image_url] |
string URL to an image on the web, use this field to add a photo. |
data[attributes][image_base64] |
string Base64 encoded photo, use this field to add a photo. |
data[attributes][item_count] |
integer Number of collection items in this collection that are visible in the store. Only includes items where show_in_store is true. Includes collection items in this collection, but not in nested collections.This count is automatically recalculated when items are added, removed, or when their show_in_store status changes. |
data[attributes][name] |
string Name of this collection. |
data[attributes][parent_id] |
uuid The ID of the parent collection. |
data[attributes][remote_image_url] |
string URL to an image on the web, use this field to add a photo. |
data[attributes][remove_image] |
boolean Remove the current image. |
data[attributes][seo_description] |
string SEO description. |
data[attributes][seo_title] |
string SEO title. |
data[attributes][show_in_store] |
boolean Whether to show this collection in the online store. |
data[attributes][slug] |
string Slug used in online store URLs. |
data[attributes][system] |
boolean When true, this collection is generated and maintained automatically by Booqable. System collections cannot be updated or deleted. |
Includes
This request accepts the following includes:
-
collection_items-
itemphoto
-
Update a collection
How to update a collection:
curl --request PUT
--url 'https://example.booqable.com/api/4/collections/6ee95651-79a3-47df-875d-6bceb66cb4e6'
--header 'content-type: application/json'
--data '{
"data": {
"id": "6ee95651-79a3-47df-875d-6bceb66cb4e6",
"type": "collections",
"attributes": {
"name": "Fall Collection"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "6ee95651-79a3-47df-875d-6bceb66cb4e6",
"type": "collections",
"attributes": {
"created_at": "2026-04-06T17:47:00.000000+00:00",
"updated_at": "2026-04-06T17:47:00.000000+00:00",
"name": "Fall Collection",
"slug": "all-seasons",
"description": null,
"seo_title": null,
"seo_description": null,
"collection_type": "manual",
"system": false,
"item_count": 0,
"show_in_store": true,
"parent_id": null,
"depth": 1,
"position": null,
"image_url": null,
"image_large_url": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/collections/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collections]=all_parents,all_children,hierarchical_name |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collections]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=collection_items |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][collection_type] |
enum Dynamic collections are automatically updated. Static collections are defined by the user. One of: static, dynamic. |
data[attributes][external_image_url] |
string URL to an image on the web, use this field to add a photo. |
data[attributes][image_base64] |
string Base64 encoded photo, use this field to add a photo. |
data[attributes][item_count] |
integer Number of collection items in this collection that are visible in the store. Only includes items where show_in_store is true. Includes collection items in this collection, but not in nested collections.This count is automatically recalculated when items are added, removed, or when their show_in_store status changes. |
data[attributes][name] |
string Name of this collection. |
data[attributes][parent_id] |
uuid The ID of the parent collection. |
data[attributes][remote_image_url] |
string URL to an image on the web, use this field to add a photo. |
data[attributes][remove_image] |
boolean Remove the current image. |
data[attributes][seo_description] |
string SEO description. |
data[attributes][seo_title] |
string SEO title. |
data[attributes][show_in_store] |
boolean Whether to show this collection in the online store. |
data[attributes][slug] |
string Slug used in online store URLs. |
data[attributes][system] |
boolean When true, this collection is generated and maintained automatically by Booqable. System collections cannot be updated or deleted. |
Includes
This request accepts the following includes:
-
collection_items-
itemphoto
-
Delete a collection
To delete a collection make sure there are no nested collections anymore.
How to delete a collection:
curl --request DELETE
--url 'https://example.booqable.com/api/4/collections/df45847d-b793-411a-82a7-2344685a75df'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "df45847d-b793-411a-82a7-2344685a75df",
"type": "collections",
"attributes": {
"created_at": "2022-02-26T11:23:14.000000+00:00",
"updated_at": "2022-02-26T11:23:14.000000+00:00",
"name": "All Seasons",
"slug": "all-seasons",
"description": null,
"seo_title": null,
"seo_description": null,
"collection_type": "manual",
"system": false,
"item_count": 0,
"show_in_store": true,
"parent_id": null,
"depth": 1,
"position": null,
"image_url": null,
"image_large_url": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/collections/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collections]=all_parents,all_children,hierarchical_name |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collections]=created_at,updated_at,name |
Includes
This request does not accept any includes
Collection items
An item in a Collection.
CollectionItems cannot be changed directly, but their position can be updated through the Sortings resource.
When a CollectionItem is created or destroyed, the parent Collection
item_count is automatically recalculated to reflect only items that are visible
in the store (show_in_store: true).
Relationships
| Name | Description |
|---|---|
collection |
Collection requiredThe Collection this CollectionItem is part of. |
item |
Item requiredThe item. Can be a ProductGroup or a Bundle. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
collection_id |
uuid readonly-after-createThe Collection this CollectionItem is part of. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
implicit |
boolean readonlyA value of true indicates that this item was not added explicitly, but instead is included in one of the child Collections. |
item_id |
uuid readonly-after-createThe item. Can be a ProductGroup or a Bundle. |
position |
integer readonlyPosition of this item within the Collection. I.e sorting relative to other CollectionItems. |
source_collections |
array readonly extraThe child Collection(s) which explicitly include the ProductGroup/Bundle, and are the source(s) for this CollectionItem. |
List collection items
How to fetch collection items:
curl --get 'https://example.booqable.com/api/4/collection_items'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "c1cd76e1-4623-455e-8573-566ce1ce6c28",
"type": "collection_items",
"attributes": {
"created_at": "2023-01-20T16:48:01.000000+00:00",
"updated_at": "2023-01-20T16:48:01.000000+00:00",
"item_id": "33763613-da95-4e0a-89fd-1394814769da",
"collection_id": "80277708-d325-42a0-87a1-7e45bb3167ec",
"position": null,
"implicit": false
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/collection_items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collection_items]=source_collections |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collection_items]=created_at,item_id,collection_id |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=item,collection |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
collection_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
exclude_system_collections |
boolean eq |
id |
uuid eq, not_eq |
implicit |
boolean eq |
item_id |
uuid eq, not_eq |
position |
integer eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
collection-
itemphoto
Create a collection item
How to create a collection item:
curl --request POST
--url 'https://example.booqable.com/api/4/collection_items'
--header 'content-type: application/json'
--data '{
"data": {
"type": "collection_items",
"attributes": {
"item_id": "facd8ef7-5f11-4dae-8318-f3a59f73560e",
"collection_id": "d9c4b730-729f-4e5d-8809-1be451f56dac"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "2f9668f0-65ed-4b5c-865d-f8e91d0b51cd",
"type": "collection_items",
"attributes": {
"created_at": "2025-05-23T01:55:00.000000+00:00",
"updated_at": "2025-05-23T01:55:00.000000+00:00",
"item_id": "facd8ef7-5f11-4dae-8318-f3a59f73560e",
"collection_id": "d9c4b730-729f-4e5d-8809-1be451f56dac",
"position": null,
"implicit": false
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/collection_items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collection_items]=source_collections |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collection_items]=created_at,item_id,collection_id |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][collection_id] |
uuid The Collection this CollectionItem is part of. |
data[attributes][item_id] |
uuid The item. Can be a ProductGroup or a Bundle. |
Includes
This request does not accept any includes
Delete a collection item
How to delete a collection item:
curl --request DELETE
--url 'https://example.booqable.com/api/4/collection_items/ec034cc0-89e0-42f0-8a00-b2a59de8c98a'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "ec034cc0-89e0-42f0-8a00-b2a59de8c98a",
"type": "collection_items",
"attributes": {
"created_at": "2018-01-04T10:28:00.000000+00:00",
"updated_at": "2018-01-04T10:28:00.000000+00:00",
"item_id": "cdb92bdf-3a07-413f-8f82-69cb2d3ea2b1",
"collection_id": "fc597631-ca5b-4fcb-83eb-2b59c0f54073",
"position": null,
"implicit": false
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/collection_items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[collection_items]=source_collections |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[collection_items]=created_at,item_id,collection_id |
Includes
This request does not accept any includes
Collection trees
Allows making multiple changes to the tree of collections at once.
Fields
| Name | Description |
|---|---|
collections |
array writeonlyArray of hashes, which each describe an update to make. |
id |
uuid readonlyPrimary key. |
Update the tree
How to update the tree:
curl --request POST
--url 'https://example.booqable.com/api/4/collection_trees'
--header 'content-type: application/json'
--data '{
"data": {
"type": "collection_trees",
"attributes": {
"collections": [
{
"id": "7ee0b635-bd10-4ade-835f-08e7a341e36d",
"parent_id": "786ce8ea-70d2-46b4-8a1c-f59a62784714",
"position": 3
},
{
"id": "be1d0d57-55e2-47ed-8bd9-7aef1ccdc47d",
"parent_id": "f773a180-793f-4c5e-8640-a794e8b7a3b9",
"position": 4
}
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "4583bb5e-28c4-4e74-8610-06c05f98a464",
"type": "collection_trees"
},
"meta": {}
}
HTTP Request
POST /api/4/collection_trees
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][collections][] |
array Array of hashes, which each describe an update to make. |
Includes
This request does not accept any includes
Companies
Every action performed in a Booqable account is scoped to a company. A company holds information and configuration about an account.
Fields
| Name | Description |
|---|---|
address |
string readonlyThe full address. |
address_line_1 |
string First address line. |
address_line_2 |
string Second address line. |
billing_address |
hash readonlyA hash with the company billing address fields. Use it when fetching the company. See address property type for more information. |
billing_address_attributes |
hash writeonlyA hash with the company billing address fields. Use it when updating the company billing address. See address property type for more information. |
billing_address_city |
string City (used for invoices received from Booqable). |
billing_address_country |
string Country (used for invoices received from Booqable). |
billing_address_line_1 |
string First address line (used for invoices received from Booqable). |
billing_address_line_2 |
string Second address line (used for invoices received from Booqable). |
billing_address_region |
string Region (used for invoices received from Booqable). |
billing_address_zipcode |
string Zipcode (used for invoices received from Booqable). |
billing_company |
string Company name (used for invoices received from Booqable). |
billing_email |
string Used to send billing emails to. |
city |
string City. |
continent |
string readonlyContinent the company is situated. |
country |
string Country. |
country_code |
string Two-letter country code (ISO 3166-1 alpha-2). |
created_at |
datetime readonlyWhen the resource was created. |
currency |
string Currency of the company. |
custom_domain |
string Custom domain to use for hosted store and checkout. |
custom_domain_validation |
hash Validation details for the custom domain. |
default_timezone |
string Company's default timezone. |
development |
boolean readonlyWhether this is a development account. |
email |
string Used in customer communication, on documents and as the reply-to address for emails that are being sent. |
favicon_base64 |
string writeonlyTo upload a favicon send it as a base64 encoded string. |
favicon_url |
string readonlyCompany favicon URL. |
financial_line_1 |
string First extra financial information line (like bank account) used in customer communication, on documents, and as the reply-to address for emails that are being sent. |
financial_line_2 |
string Second extra financial information line (like bank account) used in customer communication, on documents, and as the reply-to address for emails that are being sent. |
has_to_pay_vat |
boolean readonlyWhether the company has to pay VAT. |
id |
uuid readonlyPrimary key. |
in_europe |
boolean readonlyWhether company is situated in Europe. |
installed_online_store |
boolean readonlyIf the online store is installed, this boolean will return true. |
logo_base64 |
string writeonlyTo update a logo send it as base64 encoded string. |
logo_url |
string readonlyURL of the uploaded logo. |
main_address |
hash readonlyA hash with the company main address fields. Use it when fetching the company. See address property type for more information. |
main_address_attributes |
hash writeonlyA hash with the company main address fields. Use it when updating the company main address. See address property type for more information. |
market |
string The market the company operates in. |
medium |
string readonlyUTM medium present during signup. |
name |
string Name of the company. |
pending_subscription |
boolean readonlyWhether the company has a pending subscription. |
phone |
string Phone number. |
region |
string Region. |
remove_favicon |
boolean writeonlyRemove current favicon. |
remove_logo |
boolean writeonlyRemove current logo. |
revenue_last_year |
string readonlyRevenue last year given during signup. |
shop_theme_id |
uuid ID of installed shop theme. |
slug |
string readonlyCompany's slug, the part of the domain name before booqable.com. |
source |
string readonlyUTM source present during signup. |
subscription |
hash readonly extraDetails about the subscription. |
team_size |
string readonlyTeam size given during signup. |
tenant_token |
string readonlyToken. |
third_party_id |
string ID used for third party tools. |
updated_at |
datetime readonlyWhen the resource was last updated. |
use_billing_address |
boolean Whether to use billing address on invoices received from Booqable. |
vat_number |
string Company's VAT number, used in customer communication and to define tax exempts. |
website |
string Website. |
year_business_start |
string readonlyYear when company started, given during signup. |
zipcode |
string Zipcode. |
Fetch a company
How to fetch a company:
curl --get 'https://example.booqable.com/api/4/companies/current'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "9391cc27-0209-4fb5-8077-0e7af94f571d",
"type": "companies",
"attributes": {
"created_at": "2025-12-03T02:00:00.000000+00:00",
"updated_at": "2025-12-03T02:00:00.000000+00:00",
"name": "iRent",
"slug": "irent",
"email": "[email protected]",
"billing_email": null,
"phone": null,
"website": "www.booqable.com",
"address_line_1": "Blokhuispoort",
"address_line_2": "Leeuwarden",
"zipcode": "8900AB",
"city": "Leeuwarden",
"region": null,
"country": "Netherlands",
"country_code": null,
"market": "AV / Camera",
"use_billing_address": false,
"billing_company": null,
"billing_address_line_1": null,
"billing_address_line_2": null,
"billing_address_zipcode": null,
"billing_address_city": null,
"billing_address_region": null,
"billing_address_country": null,
"logo_url": null,
"favicon_url": null,
"default_timezone": "UTC",
"currency": "usd",
"financial_line_1": "Blokhuispoort",
"financial_line_2": "Leeuwarden",
"vat_number": null,
"in_europe": null,
"has_to_pay_vat": false,
"continent": null,
"custom_domain": null,
"custom_domain_validation": null,
"development": false,
"shop_theme_id": null,
"installed_online_store": false,
"source": null,
"medium": null,
"tenant_token": "e08844f444c33fcafbe78fef211e194c",
"pending_subscription": false,
"team_size": null,
"revenue_last_year": null,
"year_business_start": null,
"address": "Blokhuispoort\nLeeuwarden\n8900AB Leeuwarden\nNetherlands",
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuispoort",
"address2": "Leeuwarden",
"city": "Leeuwarden",
"region": null,
"zipcode": "8900AB",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "52.521918",
"longitude": "13.413215",
"value": "Blokhuispoort\nLeeuwarden\n8900AB Leeuwarden\nNetherlands"
},
"billing_address": null,
"third_party_id": "9391cc27-0209-4fb5-8077-0e7af94f571d"
}
},
"meta": {}
}
HTTP Request
GET /api/4/companies/current
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[companies]=subscription |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[companies]=created_at,updated_at,name |
Includes
This request does not accept any includes
Fetch subscription details
The subscription has the following fields:
| Name | Description |
|---|---|
trial_ends_at |
Datetime readonlyWhen the trial ends |
activated |
Boolean readonlyWhether subscription is active |
suspended |
Boolean readonlyWhether account is suspended |
canceled |
Boolean readonlyWhether subscription is canceled |
canceled_at |
Datetime readonlyWhen the subscription is canceled (can also be in the future) |
on_hold |
Boolean readonlyWhether account is on-hold |
needs_activation |
Boolean readonlyWhether account needs to activate a subscription |
legacy |
Datetime readonlyWhether it's a legacy subscription |
product |
String readonlyWhich product is active, one of Essential, Pro, Premium, Legacy |
plan_id |
String readonlyID of the product (used internally by Booqable) |
interval |
String readonlyBilling interval, one of month, year |
current_period_end |
Datetime readonlyWhen the current billing period ends |
quantity |
Integer readonlyQuantity of the subscription (used for legacy subscriptions to buy seats) |
extra_employees |
Integer readonlyExtra employees billed for |
extra_locations |
Integer readonlyExtra locations billed for |
amount_in_cents |
Integer readonlyAmount in cents |
discount_in_cents |
Integer readonlyDiscount in cents |
balance_in_cents |
Integer readonlyBalance in cents, will be deducted from the next invoice(s) |
coupon |
String readonlyCoupon that's currently active |
coupon_percent_off |
String* readonly Percentage of discount on the current active coupon |
coupon_duration |
String* readonly Duration type of the current active coupon, one of forever, once, repeating |
coupon_duration_in_months |
String* readonly Amount of months the coupon is active. Only present when coupon duration is repeating. |
strategy |
String readonlyBilling strategy, one of send_invoice, charge_automatically |
source |
Hash readonlyInformation about the payment source |
enabled_features |
Hash readonlyBeta features that are currently enabled |
allowed_features |
Hash readonlyList of allowed features for plan |
restrictions |
Hash readonlyRestrictions applied to this account |
How to fetch details about the company its subscription:
curl --get 'https://example.booqable.com/api/4/companies/current'
--header 'content-type: application/json'
--data-urlencode 'extra_fields[companies]=subscription'
--data-urlencode 'fields[companies]=subscription'
A 200 status response looks like this:
{
"data": {
"id": "b962f1eb-9fbc-42f9-81ac-a12d0b5a2174",
"type": "companies",
"attributes": {
"subscription": {
"trial_ends_at": "2019-05-03T10:16:00.000000+00:00",
"activated": true,
"active_subscription": true,
"suspended": false,
"canceled": false,
"canceled_at": null,
"on_hold": false,
"plan_identifier": "scale",
"active_subscription_plan_and_interval": "scale_month",
"interval": "month",
"current_period_end": null,
"extra_employees": 0,
"extra_employees_left": 14,
"extra_locations": 0,
"addons": [
"online_bookings",
"website_builder",
"mobile_app",
"sso",
"ip_restrictions",
"2fa_enforcing",
"barcodes"
],
"checkout_settings": {},
"amount_in_cents": 59200,
"discount_in_cents": 0,
"balance_in_cents": 0,
"coupon": null,
"coupon_intervals": null,
"coupon_plans": null,
"coupon_percent_off": null,
"coupon_duration": null,
"coupon_duration_in_months": null,
"strategy": "charge_automatically",
"source": null,
"pricing_strategy": "small_medium_large_scale",
"enabled_features": [],
"allowed_features": [
"destroy_bundles",
"mobile_app",
"zapier",
"advanced_pricing",
"sales_items",
"bundles",
"buffer_times",
"prevent_last_minute_reservations",
"packing_slips",
"notes",
"manual_email_templates",
"away_mode",
"customer_discount_percentage",
"product_security_deposit",
"coupons",
"invoice_due_dates",
"reports",
"availability_reports",
"product_history",
"downtimes",
"api",
"permissions",
"product_shortage_limits",
"exports",
"remove_powered_by",
"custom_domain",
"custom_scripts",
"website_integration",
"website_builder",
"tap_to_pay",
"sso",
"iprestrictions",
"2fa_enforcing",
"barcodes"
],
"restrictions": {
"employees": 15,
"email_max_recipients": 2000,
"rate_limit_max": 250,
"rate_limit_period": 60,
"locations": 1,
"allow_extra_locations": true,
"allow_extra_employees": true,
"manual_email_templates": null,
"custom_fields": null,
"tags": null,
"away_modes": null
},
"currency": "usd"
}
}
},
"meta": {}
}
HTTP Request
GET /api/4/companies/current
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[companies]=subscription |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[companies]=created_at,updated_at,name |
Includes
This request does not accept any includes
Update a company
How to update a company:
curl --request PUT
--url 'https://example.booqable.com/api/4/companies/current'
--header 'content-type: application/json'
--data '{
"data": {
"id": "39b6d9bd-03cc-4869-8a7a-9e3ca8f59712",
"type": "companies",
"attributes": {
"name": "iRent LLC"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "39b6d9bd-03cc-4869-8a7a-9e3ca8f59712",
"type": "companies",
"attributes": {
"created_at": "2020-02-19T10:28:01.000000+00:00",
"updated_at": "2020-02-19T10:28:01.000000+00:00",
"name": "iRent LLC",
"slug": "irent",
"email": "[email protected]",
"billing_email": null,
"phone": null,
"website": "www.booqable.com",
"address_line_1": "Blokhuispoort",
"address_line_2": "Leeuwarden",
"zipcode": "8900AB",
"city": "Leeuwarden",
"region": null,
"country": "Netherlands",
"country_code": null,
"market": "AV / Camera",
"use_billing_address": false,
"billing_company": null,
"billing_address_line_1": null,
"billing_address_line_2": null,
"billing_address_zipcode": null,
"billing_address_city": null,
"billing_address_region": null,
"billing_address_country": null,
"logo_url": null,
"favicon_url": null,
"default_timezone": "UTC",
"currency": "usd",
"financial_line_1": "Blokhuispoort",
"financial_line_2": "Leeuwarden",
"vat_number": null,
"in_europe": null,
"has_to_pay_vat": false,
"continent": null,
"custom_domain": null,
"custom_domain_validation": null,
"development": false,
"shop_theme_id": null,
"installed_online_store": false,
"source": null,
"medium": null,
"tenant_token": "7a1067c6345a05d4627e8ec7bdeadbe6",
"pending_subscription": false,
"team_size": null,
"revenue_last_year": null,
"year_business_start": null,
"address": "Blokhuispoort\nLeeuwarden\n8900AB Leeuwarden\nNetherlands",
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuispoort",
"address2": "Leeuwarden",
"city": "Leeuwarden",
"region": null,
"zipcode": "8900AB",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "52.521918",
"longitude": "13.413215",
"value": "Blokhuispoort\nLeeuwarden\n8900AB Leeuwarden\nNetherlands"
},
"billing_address": null,
"third_party_id": "39b6d9bd-03cc-4869-8a7a-9e3ca8f59712"
}
},
"meta": {}
}
HTTP Request
PUT /api/4/companies/current
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[companies]=subscription |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[companies]=created_at,updated_at,name |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address_line_1] |
string First address line. |
data[attributes][address_line_2] |
string Second address line. |
data[attributes][billing_address_attributes] |
hash A hash with the company billing address fields. Use it when updating the company billing address. See address property type for more information. |
data[attributes][billing_address_city] |
string City (used for invoices received from Booqable). |
data[attributes][billing_address_country] |
string Country (used for invoices received from Booqable). |
data[attributes][billing_address_line_1] |
string First address line (used for invoices received from Booqable). |
data[attributes][billing_address_line_2] |
string Second address line (used for invoices received from Booqable). |
data[attributes][billing_address_region] |
string Region (used for invoices received from Booqable). |
data[attributes][billing_address_zipcode] |
string Zipcode (used for invoices received from Booqable). |
data[attributes][billing_company] |
string Company name (used for invoices received from Booqable). |
data[attributes][billing_email] |
string Used to send billing emails to. |
data[attributes][city] |
string City. |
data[attributes][country] |
string Country. |
data[attributes][country_code] |
string Two-letter country code (ISO 3166-1 alpha-2). |
data[attributes][currency] |
string Currency of the company. |
data[attributes][custom_domain] |
string Custom domain to use for hosted store and checkout. |
data[attributes][custom_domain_validation] |
hash Validation details for the custom domain. |
data[attributes][default_timezone] |
string Company's default timezone. |
data[attributes][email] |
string Used in customer communication, on documents and as the reply-to address for emails that are being sent. |
data[attributes][favicon_base64] |
string To upload a favicon send it as a base64 encoded string. |
data[attributes][financial_line_1] |
string First extra financial information line (like bank account) used in customer communication, on documents, and as the reply-to address for emails that are being sent. |
data[attributes][financial_line_2] |
string Second extra financial information line (like bank account) used in customer communication, on documents, and as the reply-to address for emails that are being sent. |
data[attributes][logo_base64] |
string To update a logo send it as base64 encoded string. |
data[attributes][main_address_attributes] |
hash A hash with the company main address fields. Use it when updating the company main address. See address property type for more information. |
data[attributes][market] |
string The market the company operates in. |
data[attributes][name] |
string Name of the company. |
data[attributes][phone] |
string Phone number. |
data[attributes][region] |
string Region. |
data[attributes][remove_favicon] |
boolean Remove current favicon. |
data[attributes][remove_logo] |
boolean Remove current logo. |
data[attributes][shop_theme_id] |
uuid ID of installed shop theme. |
data[attributes][third_party_id] |
string ID used for third party tools. |
data[attributes][use_billing_address] |
boolean Whether to use billing address on invoices received from Booqable. |
data[attributes][vat_number] |
string Company's VAT number, used in customer communication and to define tax exempts. |
data[attributes][website] |
string Website. |
data[attributes][zipcode] |
string Zipcode. |
Includes
This request does not accept any includes
Countries
The Country resource describes countries,
including the information required to validate the format of addresses.
Relationships
| Name | Description |
|---|---|
provinces |
Provinces hasmanyThe provinces/states of this country (or any other administrative subdivision). |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
alpha2 |
string readonlyISO 3166-1 alpha-2 code. |
city_autofill |
string readonlyThe value to use for the city when autofilling. |
created_at |
datetime readonlyWhen the resource was created. |
form_layout |
string readonlyThe layout of the address form. |
id |
uuid readonlyPrimary key. |
name |
string readonlyName of the country. |
province_required |
boolean readonlyWhether a province is required for addresses in this country. |
province_type |
string readonlyThe province type of this country. |
show_layout |
string readonlyThe layout of the address when shown. |
updated_at |
datetime readonlyWhen the resource was last updated. |
zipcode_autofill |
string readonlyThe value to use for the ZIP code when autofilling. |
zipcode_format |
string readonlyThe format of the ZIP code, as a regular expression. |
zipcode_placeholder |
string readonlyThe placeholder to use for the ZIP code. |
zipcode_required |
boolean readonlyWhether a ZIP code is required for addresses in this country. |
zipcode_type |
string readonlyThe ZIP code type of this country. |
List countries
How to fetch a list of countries:
curl --get 'https://example.booqable.com/api/4/countries'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "adafbcae-49c4-4209-8932-8b822acb8924",
"type": "countries",
"attributes": {
"created_at": "2028-11-04T19:33:00.000000+00:00",
"updated_at": "2028-11-04T19:33:00.000000+00:00",
"name": "Netherlands",
"alpha2": "NL",
"province_required": false,
"province_type": "province",
"form_layout": "{country}\n{first_name}{last_name}\n{address1}\n{address2}\n{zipcode}{city}",
"show_layout": "{first_name} {last_name}\n{address1}\n{address2}\n{zipcode} {city}\n{country}",
"zipcode_required": true,
"zipcode_autofill": null,
"zipcode_format": "\\d{4} ?[A-Z]{2}",
"zipcode_placeholder": "1234 AB",
"zipcode_type": "postcode",
"city_autofill": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/countries
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[countries]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=provinces |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
alpha2 |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
city_autofill |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
form_layout |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
province_required |
boolean eq |
province_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
show_layout |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
zipcode_autofill |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
zipcode_format |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
zipcode_placeholder |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
zipcode_required |
boolean eq |
zipcode_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
provinces
Coupons
Create codes to discount orders by a fixed amount or a percentage. Customers can redeem the codes online at checkout. Coupons can also be added to orders in the back office.
Fields
| Name | Description |
|---|---|
active |
boolean Whether coupon can be redeemed at the moment. |
archived |
boolean readonlyWhether coupon is archived. |
archived_at |
datetime readonly nullableWhen the coupon was archived. |
coupon_type |
string How the discount is calculated. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
identifier |
string The code that customers need to type in. |
updated_at |
datetime readonlyWhen the resource was last updated. |
value |
integer A percentage for type percentage or a value in cents for cents. |
List coupons
How to fetch a list of coupons:
curl --get 'https://example.booqable.com/api/4/coupons'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "631bea2b-3cb8-4bbd-819d-7cb0257b110e",
"type": "coupons",
"attributes": {
"created_at": "2021-07-21T18:25:00.000000+00:00",
"updated_at": "2021-07-21T18:25:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "SUMMER20OFF",
"coupon_type": "percentage",
"value": 20,
"active": true
}
}
],
"meta": {}
}
HTTP Request
GET /api/4/coupons
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[coupons]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
active |
boolean eq |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
coupon_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
value |
integer eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a coupon
How to fetch a coupon:
curl --get 'https://example.booqable.com/api/4/coupons/2a057098-ccb5-4179-800a-0d295431eaa3'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "2a057098-ccb5-4179-800a-0d295431eaa3",
"type": "coupons",
"attributes": {
"created_at": "2026-09-19T23:57:00.000000+00:00",
"updated_at": "2026-09-19T23:57:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "SUMMER20OFF",
"coupon_type": "percentage",
"value": 20,
"active": true
}
},
"meta": {}
}
HTTP Request
GET /api/4/coupons/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[coupons]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Create a coupon
How to create a coupon:
curl --request POST
--url 'https://example.booqable.com/api/4/coupons'
--header 'content-type: application/json'
--data '{
"data": {
"type": "coupons",
"attributes": {
"identifier": "WINTERDISCOUNT",
"coupon_type": "cents",
"value": 2000,
"active": true
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "e2ba40bf-54f7-422e-844e-5d36bacd5bfa",
"type": "coupons",
"attributes": {
"created_at": "2020-12-12T20:49:00.000000+00:00",
"updated_at": "2020-12-12T20:49:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "WINTERDISCOUNT",
"coupon_type": "cents",
"value": 2000,
"active": true
}
},
"meta": {}
}
HTTP Request
POST /api/4/coupons
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[coupons]=created_at,updated_at,archived |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][active] |
boolean Whether coupon can be redeemed at the moment. |
data[attributes][coupon_type] |
string How the discount is calculated. |
data[attributes][identifier] |
string The code that customers need to type in. |
data[attributes][value] |
integer A percentage for type percentage or a value in cents for cents. |
Includes
This request does not accept any includes
Update a coupon
When updating a coupon the existing one is archived and a new one gets created:
How to update a coupon:
curl --request PUT
--url 'https://example.booqable.com/api/4/coupons/90aa7e25-800f-4f23-84c2-1f077eaea4dd'
--header 'content-type: application/json'
--data '{
"data": {
"id": "90aa7e25-800f-4f23-84c2-1f077eaea4dd",
"type": "coupons",
"attributes": {
"identifier": "SUMMER30OFF",
"coupon_type": "percentage",
"value": 30
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "f3f44405-c4fe-424e-8fe4-bfdfe6a7f761",
"type": "coupons",
"attributes": {
"created_at": "2021-03-12T23:40:01.000000+00:00",
"updated_at": "2021-03-12T23:40:01.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "SUMMER30OFF",
"coupon_type": "percentage",
"value": 30,
"active": false
}
},
"meta": {}
}
How to deactivate a coupon:
curl --request PUT
--url 'https://example.booqable.com/api/4/coupons/8c0f8005-b948-4ddc-855b-6825e4159246'
--header 'content-type: application/json'
--data '{
"data": {
"id": "8c0f8005-b948-4ddc-855b-6825e4159246",
"type": "coupons",
"attributes": {
"active": false
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "aa069e77-af42-4e2c-862a-53a56308bcc0",
"type": "coupons",
"attributes": {
"created_at": "2022-08-10T18:19:00.000000+00:00",
"updated_at": "2022-08-10T18:19:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "SUMMER20OFF",
"coupon_type": "percentage",
"value": 20,
"active": false
}
},
"meta": {}
}
HTTP Request
PUT /api/4/coupons/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[coupons]=created_at,updated_at,archived |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][active] |
boolean Whether coupon can be redeemed at the moment. |
data[attributes][coupon_type] |
string How the discount is calculated. |
data[attributes][identifier] |
string The code that customers need to type in. |
data[attributes][value] |
integer A percentage for type percentage or a value in cents for cents. |
Includes
This request does not accept any includes
Archive a coupon
How to archive a coupon:
curl --request DELETE
--url 'https://example.booqable.com/api/4/coupons/48f7032a-1017-4616-82e3-be69134a1685'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "48f7032a-1017-4616-82e3-be69134a1685",
"type": "coupons",
"attributes": {
"created_at": "2015-09-09T21:54:00.000000+00:00",
"updated_at": "2015-09-09T21:54:00.000000+00:00",
"archived": true,
"archived_at": "2015-09-09T21:54:00.000000+00:00",
"identifier": "SUMMER20OFF",
"coupon_type": "percentage",
"value": 20,
"active": true
}
},
"meta": {}
}
HTTP Request
DELETE /api/4/coupons/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[coupons]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Customers
Customers are an essential part of your business.
Stored customer information like addresses, customer tax profiles, discounts, and customized security deposits are applied to an order when created or when assigned a new customer.
Relationships
| Name | Description |
|---|---|
barcode |
Barcode optionalThe barcode pointing to this customer. |
merge_suggestion_customer |
Customer requiredHolds the customer this customer is a possible duplicate of. |
notes |
Notes hasmanyNotes added about (and invisible for) customers. |
payment_methods |
Payment methods hasmanyPaymentMethods associated with the customer. |
properties |
Properties hasmanyCustom structured data about this customer, based on DefaultProperties. Properties of customers can be updated in bulk by writing to the properties_attributes attribute. |
tax_region |
Tax region optionalTax region assigned to new orders for this customer. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether customer is archived. |
archived_at |
datetime readonly nullableWhen the customer was archived. |
created_at |
datetime readonlyWhen the resource was created. |
deposit_type |
string The deposit added to new orders of this customer by default. |
deposit_value |
float The value to use for deposit_type. |
discount_percentage |
float Default discount applied to each new order for this customer. |
email |
string nullableEmail address used for communication. |
email_marketing_consent_updated_at |
datetime readonlyWhen the email marketing consent was last updated. |
email_marketing_consented |
boolean Whether the customer has consented to receive email marketing. |
id |
uuid readonlyPrimary key. |
legal_type |
string Either person or commercial. |
merge_suggestion_customer_id |
uuid Holds the customer this customer is a possible duplicate of. |
name |
string Person or Company name. |
number |
integer readonlyThe assigned number. |
properties |
hash readonlyA hash containing all basic property values. This is a simplified representation; sideload the properties relation if you need more detailed information of properties. |
properties_attributes |
array writeonlyCreate or update multiple properties to be associated with this customer. |
stripe_id |
string The Stripe customer ID. |
tag_list |
array[string] Case insensitive tag list. |
tax_region_id |
uuid nullableTax region assigned to new orders for this customer. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List customers
How to fetch a list of customers:
curl --get 'https://example.booqable.com/api/4/customers'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "b047cd19-e6ec-4914-8ddb-960e2ed984fa",
"type": "customers",
"attributes": {
"created_at": "2018-06-02T01:12:12.000000+00:00",
"updated_at": "2018-06-02T01:12:12.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/customers
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[customers]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=barcode,properties,tax_region |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
conditions |
hash eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
deposit_value |
float eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
email |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
email_marketing_consented |
boolean eq |
id |
uuid eq, not_eq, gt |
legal_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
merge_suggestion_customer_id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
number |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
stripe_id |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
tag_list |
string eq |
tax_region_id |
uuid eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
discount_percentage |
array maximum, minimum, average |
legal_type |
array count |
tag_list |
array count |
tax_region_id |
array count |
total |
array count |
Includes
This request accepts the following includes:
barcodepayment_methodspropertiestax_region
Search customers
Use advanced search to make logical filter groups with and/or operators.
How to search for customers:
curl --request POST
--url 'https://example.booqable.com/api/4/customers/search'
--header 'content-type: application/json'
--data '{
"fields": {
"customers": "id"
},
"filter": {
"conditions": {
"operator": "and",
"attributes": [
{
"operator": "or",
"attributes": [
{
"name": "john"
},
{
"name": "jane"
}
]
},
{
"operator": "and",
"attributes": [
{
"discount_percentage": {
"gte": 50
}
},
{
"deposit_type": "none"
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "fc31d64f-c136-4d37-8a09-e821bf52af93"
},
{
"id": "987d8eb5-6236-4d00-8f7b-308f06d36519"
}
]
}
HTTP Request
POST /api/4/customers/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[customers]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=barcode,properties,tax_region |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
conditions |
hash eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
deposit_value |
float eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
email |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
email_marketing_consented |
boolean eq |
id |
uuid eq, not_eq, gt |
legal_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
merge_suggestion_customer_id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
number |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
stripe_id |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
tag_list |
string eq |
tax_region_id |
uuid eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
discount_percentage |
array maximum, minimum, average |
legal_type |
array count |
tag_list |
array count |
tax_region_id |
array count |
total |
array count |
Includes
This request accepts the following includes:
barcodepayment_methodspropertiestax_region
Fetch a customer
How to fetch a customers:
curl --get 'https://example.booqable.com/api/4/customers/2270a849-1797-436e-8b18-ef3fd6058a01'
--header 'content-type: application/json'
--data-urlencode 'include=barcode,properties'
A 200 status response looks like this:
{
"data": {
"id": "2270a849-1797-436e-8b18-ef3fd6058a01",
"type": "customers",
"attributes": {
"created_at": "2028-05-22T08:53:00.000000+00:00",
"updated_at": "2028-05-22T08:53:00.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {
"properties": {
"data": []
},
"barcode": {
"data": null
}
}
},
"meta": {}
}
HTTP Request
GET /api/4/customers/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[customers]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=barcode,properties,tax_region |
Includes
This request accepts the following includes:
barcodepayment_methodspropertiestax_region
Create a customer
How to create a customer:
curl --request POST
--url 'https://example.booqable.com/api/4/customers'
--header 'content-type: application/json'
--data '{
"data": {
"type": "customers",
"attributes": {
"name": "John Doe",
"email": "[email protected]"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "81f21c77-e757-43d7-842f-41c5c184945e",
"type": "customers",
"attributes": {
"created_at": "2015-09-14T16:31:01.000000+00:00",
"updated_at": "2015-09-14T16:31:01.000000+00:00",
"archived": false,
"archived_at": null,
"number": 2,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/customers
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[customers]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=barcode,properties,tax_region |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][deposit_type] |
string The deposit added to new orders of this customer by default. |
data[attributes][deposit_value] |
float The value to use for deposit_type. |
data[attributes][discount_percentage] |
float Default discount applied to each new order for this customer. |
data[attributes][email] |
string Email address used for communication. |
data[attributes][email_marketing_consented] |
boolean Whether the customer has consented to receive email marketing. |
data[attributes][legal_type] |
string Either person or commercial. |
data[attributes][merge_suggestion_customer_id] |
uuid Holds the customer this customer is a possible duplicate of. |
data[attributes][name] |
string Person or Company name. |
data[attributes][properties_attributes][] |
array Create or update multiple properties to be associated with this customer. |
data[attributes][stripe_id] |
string The Stripe customer ID. |
data[attributes][tag_list] |
array[string] Case insensitive tag list. |
data[attributes][tax_region_id] |
uuid Tax region assigned to new orders for this customer. |
Includes
This request accepts the following includes:
barcodepayment_methodspropertiestax_region
Update a customer
How to update a customer:
curl --request PUT
--url 'https://example.booqable.com/api/4/customers/7eaf3c75-3143-4090-8ccf-32b899f324c9'
--header 'content-type: application/json'
--data '{
"data": {
"id": "7eaf3c75-3143-4090-8ccf-32b899f324c9",
"type": "customers",
"attributes": {
"name": "Jane Doe"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "7eaf3c75-3143-4090-8ccf-32b899f324c9",
"type": "customers",
"attributes": {
"created_at": "2014-02-18T23:31:00.000000+00:00",
"updated_at": "2014-02-18T23:31:00.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "Jane Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/customers/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[customers]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=barcode,properties,tax_region |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][deposit_type] |
string The deposit added to new orders of this customer by default. |
data[attributes][deposit_value] |
float The value to use for deposit_type. |
data[attributes][discount_percentage] |
float Default discount applied to each new order for this customer. |
data[attributes][email] |
string Email address used for communication. |
data[attributes][email_marketing_consented] |
boolean Whether the customer has consented to receive email marketing. |
data[attributes][legal_type] |
string Either person or commercial. |
data[attributes][merge_suggestion_customer_id] |
uuid Holds the customer this customer is a possible duplicate of. |
data[attributes][name] |
string Person or Company name. |
data[attributes][properties_attributes][] |
array Create or update multiple properties to be associated with this customer. |
data[attributes][stripe_id] |
string The Stripe customer ID. |
data[attributes][tag_list] |
array[string] Case insensitive tag list. |
data[attributes][tax_region_id] |
uuid Tax region assigned to new orders for this customer. |
Includes
This request accepts the following includes:
barcodepayment_methodspropertiestax_region
Archive a customer
How to archive a customer:
curl --request DELETE
--url 'https://example.booqable.com/api/4/customers/7a496d55-729c-43e0-8a6b-8d505e0f3c70'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "7a496d55-729c-43e0-8a6b-8d505e0f3c70",
"type": "customers",
"attributes": {
"created_at": "2020-05-21T12:16:00.000000+00:00",
"updated_at": "2020-05-21T12:16:00.000000+00:00",
"archived": true,
"archived_at": "2020-05-21T12:16:00.000000+00:00",
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/customers/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[customers]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Default properties
Booqable comes with standard fields but you can also add custom properties to capture additional data.
Default properties show up in forms within Booqable and can be connected to checkout fields.
Default properties are searchable, show up in exports and can be used in email templates. The actual values of those properties are stored in the Property resource.
Properties inherit their configuration from a default property when they are connected.
When creating properties they are connected with their default when one of the following fields match:
- name
- identifier
- default_property_id
Fields
| Name | Description |
|---|---|
can_change_property_type |
boolean readonlyWhether the property_type can be changed for this default property.Returns true for new records. For persisted records this is false when:- derived properties already exist that reference this default property, or - one-off properties exist for the same owner that would be linked by matching identifier or case-insensitive name. |
created_at |
datetime readonlyWhen the resource was created. |
editable |
boolean readonlyWhether this property is editable. |
id |
uuid readonlyPrimary key. |
identifier |
string Key that will be used in exports, responses and custom field variables in templates. |
name |
string Name of the property (used as label and to compute identifier if left blank). |
owner_type |
string readonly-after-createThe type of resource this default property is intended for and derived properties can be added to. |
position |
integer Which position the property has. |
property_type |
enum Determines how the data is rendered and the kind of input shown to the user. One of: address, date_field, email, phone, select, text_area, text_field. |
select_options |
array For type select. The select options as array. |
show_on |
array[string] Array of items to show this custom field on. Zero or more from contract, invoice, packing, quote. |
updated_at |
datetime readonlyWhen the resource was last updated. |
validation_required |
boolean Whether this property has to be validated. |
List default properties
How to fetch a list of default properties:
curl --get 'https://example.booqable.com/api/4/default_properties'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": [
{
"id": "5d959acd-b782-4ee2-858b-d53452746abe",
"type": "default_properties",
"attributes": {
"created_at": "2016-08-06T16:53:03.000000+00:00",
"updated_at": "2016-08-06T16:53:03.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 1,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"can_change_property_type": true,
"owner_type": "customers",
"select_options": [],
"editable": true
}
}
],
"meta": {}
}
HTTP Request
GET /api/4/default_properties
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[default_properties]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
editable |
boolean eq |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
owner_type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
validation_required |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a default property
How to fetch a default property:
curl --get 'https://example.booqable.com/api/4/default_properties/e579fd95-e66a-48b3-8954-a1303f0d4543'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": {
"id": "e579fd95-e66a-48b3-8954-a1303f0d4543",
"type": "default_properties",
"attributes": {
"created_at": "2016-06-28T12:50:01.000000+00:00",
"updated_at": "2016-06-28T12:50:01.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 1,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"can_change_property_type": true,
"owner_type": "customers",
"select_options": [],
"editable": true
}
},
"meta": {}
}
HTTP Request
GET /api/4/default_properties/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[default_properties]=created_at,updated_at,name |
Includes
This request does not accept any includes
Create a default property
How to create a default property and assign it to an owner:
curl --request POST
--url 'https://example.booqable.com/api/4/default_properties'
--header 'content-type: application/json'
--data '{
"data": {
"type": "default_properties",
"attributes": {
"name": "Mobile phone",
"property_type": "phone",
"owner_type": "customers"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "0be37be8-1023-49f4-838a-f1f4a10954ef",
"type": "default_properties",
"attributes": {
"created_at": "2019-06-17T18:28:00.000000+00:00",
"updated_at": "2019-06-17T18:28:00.000000+00:00",
"name": "Mobile phone",
"identifier": "mobile_phone",
"position": 2,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"can_change_property_type": true,
"owner_type": "customers",
"select_options": [],
"editable": true
}
},
"meta": {}
}
HTTP Request
POST /api/4/default_properties
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[default_properties]=created_at,updated_at,name |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][identifier] |
string Key that will be used in exports, responses and custom field variables in templates. |
data[attributes][name] |
string Name of the property (used as label and to compute identifier if left blank). |
data[attributes][owner_type] |
string The type of resource this default property is intended for and derived properties can be added to. |
data[attributes][position] |
integer Which position the property has. |
data[attributes][property_type] |
enum Determines how the data is rendered and the kind of input shown to the user. One of: address, date_field, email, phone, select, text_area, text_field. |
data[attributes][select_options][] |
array For type select. The select options as array. |
data[attributes][show_on] |
array[string] Array of items to show this custom field on. Zero or more from contract, invoice, packing, quote. |
data[attributes][validation_required] |
boolean Whether this property has to be validated. |
Includes
This request does not accept any includes
Update a default property
How to update a default property:
curl --request PUT
--url 'https://example.booqable.com/api/4/default_properties/1d9d3f48-7bac-4b62-8f42-8018003cc95b'
--header 'content-type: application/json'
--data '{
"data": {
"id": "1d9d3f48-7bac-4b62-8f42-8018003cc95b",
"type": "default_properties",
"attributes": {
"property_type": "text_field"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "1d9d3f48-7bac-4b62-8f42-8018003cc95b",
"type": "default_properties",
"attributes": {
"created_at": "2014-07-12T02:01:00.000000+00:00",
"updated_at": "2014-07-12T02:01:00.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 1,
"property_type": "text_field",
"show_on": [],
"validation_required": false,
"can_change_property_type": true,
"owner_type": "customers",
"select_options": [],
"editable": true
}
},
"meta": {}
}
HTTP Request
PUT /api/4/default_properties/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[default_properties]=created_at,updated_at,name |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][identifier] |
string Key that will be used in exports, responses and custom field variables in templates. |
data[attributes][name] |
string Name of the property (used as label and to compute identifier if left blank). |
data[attributes][owner_type] |
string The type of resource this default property is intended for and derived properties can be added to. |
data[attributes][position] |
integer Which position the property has. |
data[attributes][property_type] |
enum Determines how the data is rendered and the kind of input shown to the user. One of: address, date_field, email, phone, select, text_area, text_field. |
data[attributes][select_options][] |
array For type select. The select options as array. |
data[attributes][show_on] |
array[string] Array of items to show this custom field on. Zero or more from contract, invoice, packing, quote. |
data[attributes][validation_required] |
boolean Whether this property has to be validated. |
Includes
This request does not accept any includes
Delete a default property
How to delete a default property:
curl --request DELETE
--url 'https://example.booqable.com/api/4/default_properties/8d8ff086-4c54-40aa-84dd-28fc56d8b3dd'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "8d8ff086-4c54-40aa-84dd-28fc56d8b3dd",
"type": "default_properties",
"attributes": {
"created_at": "2025-03-13T08:57:00.000000+00:00",
"updated_at": "2025-03-13T08:57:00.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 1,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"can_change_property_type": true,
"owner_type": "customers",
"select_options": [],
"editable": true
}
},
"meta": {}
}
HTTP Request
DELETE /api/4/default_properties/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[default_properties]=created_at,updated_at,name |
Includes
This request does not accept any includes
Delivery distance calculations
It calculates the distance (the route length) between the given locations and the delivery address.
Fields
| Name | Description |
|---|---|
distance |
float readonlyThe distance between the location and the delivery address. |
distance_unit |
enum readonlyThe unit of the distance. One of: metric, imperial. |
id |
uuid readonlyPrimary key. |
location_id |
uuid readonlyThe location ID. |
Calculate delivery distances
How to fetch a list of delivery distance calculations:
curl --get 'https://example.booqable.com/api/4/delivery_distance_calculations'
--header 'content-type: application/json'
--data-urlencode 'filter[delivery_address_property_id]=2e70e73b-04ee-4e00-835e-13ad1d52e6fc'
--data-urlencode 'filter[location_ids][]=df2395bd-72f3-4078-8c07-4c1f636a1a03'
--data-urlencode 'filter[location_ids][]=acea1410-5c2a-412d-8910-e48a9224a44d'
A 200 status response looks like this:
{
"data": [
{
"id": "f8d4975d-f633-4703-8e3d-8c7c36951675",
"type": "delivery_distance_calculations",
"attributes": {
"distance": 10.0,
"distance_unit": "km",
"location_id": "df2395bd-72f3-4078-8c07-4c1f636a1a03"
}
},
{
"id": "8dc19268-75fd-4a1c-88e5-4a0bf08fb148",
"type": "delivery_distance_calculations",
"attributes": {
"distance": 20.0,
"distance_unit": "km",
"location_id": "acea1410-5c2a-412d-8910-e48a9224a44d"
}
}
],
"meta": {}
}
HTTP Request
GET /api/4/delivery_distance_calculations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[delivery_distance_calculations]=distance,distance_unit,location_id |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
delivery_address_property_id |
uuid eq |
location_ids |
array eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Deposit holds
A deposit hold is the resource responsible for managing the held deposit on an order.
Relationships
| Name | Description |
|---|---|
deposit_line |
Line requiredThe Line that was created or updated to hold the deposit. |
order |
Order requiredThe Order a new deposit needs to be added to. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
amount_in_cents |
integer writeonlyAmount to hold. If the order already has a hold, the amount will be added to the previous one. The hold is clamped to order.deposit_in_cents. |
deposit_line_id |
uuid readonlyThe Line that was created or updated to hold the deposit. |
id |
uuid readonlyPrimary key. |
order_id |
uuid The Order a new deposit needs to be added to. |
reason |
string writeonlyReason for the hold. If the order already has a hold, the reason will overwrite the previous one. |
Create
Hold a deposit:
curl --request POST
--url 'https://example.booqable.com/api/4/deposit_holds'
--header 'content-type: application/json'
--data '{
"data": {
"type": "deposit_holds",
"attributes": {
"order_id": "f20704d5-8868-46c8-8d43-4eb95a96ec2e",
"amount_in_cents": 5000,
"reason": "damages"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "d785af99-53ec-4230-819f-c65f4fb7da9d",
"type": "deposit_holds",
"attributes": {
"order_id": "f20704d5-8868-46c8-8d43-4eb95a96ec2e",
"deposit_line_id": "e98315a1-7fbe-48ac-810a-c0823f8a663a"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/deposit_holds
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[deposit_holds]=order_id,deposit_line_id |
include |
string List of comma seperated relationships to sideload. ?include=deposit_line,order |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer Amount to hold. If the order already has a hold, the amount will be added to the previous one. The hold is clamped to order.deposit_in_cents. |
data[attributes][order_id] |
uuid The Order a new deposit needs to be added to. |
data[attributes][reason] |
string Reason for the hold. If the order already has a hold, the reason will overwrite the previous one. |
Includes
This request accepts the following includes:
-
deposit_linetax_categorytax_values
-
ordertax_values
Documents
Documents hold financial and or legal information about an order.
There are three types of documents: quote, contract, invoice.
When creating quotes and contracts, the following data is copied from the current state of the order:
- Customer information (when present)
- Pricing and deposit
- Lines
- Rental dates (starts_at, stops_at)
- Pickup and return locations
Quotes and contracts are always finalized; to make a revision, archive the document, make changes to the order, and create a new one.
Invoices are automatically generated and updated based on changes made to an order. When an invoice is finalized, and further changes are made to the order, a new invoice is created with prorated changes.
The payment status of the invoice is automatically updated when payments are made for the associated order.
Relationships
| Name | Description |
|---|---|
coupon |
Coupon optionalThe associated coupon. |
customer |
Customer optionalThe associated customer. |
lines |
Lines hasmanyThe lines of this document. |
order |
Order requiredThe order this document is for. |
properties |
Properties hasmanyCustom properties associated with this document. |
tax_region |
Tax region optionalThe associated tax region. |
tax_values |
Tax values hasmanyThe calculated taxes, one value for each applicable tax rate. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
address |
string Customer Address. If left blank, automatically populated with the customer address of the associated order. |
archived |
boolean readonlyWhether document is archived. |
archived_at |
datetime readonly nullableWhen the document was archived. |
body |
string Custom content displayed on a document, agreement details on a contract, for instance. Applicable to quote and contract. Populated with setting {document_type}.body, but can also be overridden for a specific document. |
confirmed |
boolean Whether document is confirmed, applies to quote and contract. |
coupon_discount_in_cents |
integer readonlyCoupon discount (incl. or excl. taxes based on tax_strategy). |
coupon_id |
uuid nullableThe associated coupon. |
created_at |
datetime readonlyWhen the resource was created. |
customer_id |
uuid nullableThe associated customer. |
date |
date Date the document was finalized. |
delivery_address |
string readonlyDelivery address. |
delivery_carrier_name |
string readonlyName of the delivery carrier. |
delivery_label |
string readonlyLabel for delivery. |
delivery_price_in_cents |
integer readonlyDelivery price. |
deposit_held_in_cents |
integer readonlyAmount of deposit held. |
deposit_in_cents |
integer readonlyDeposit. |
deposit_paid_in_cents |
integer readonlyHow much of the deposit is paid. |
deposit_refunded_in_cents |
integer readonlyHow much of the deposit is refunded. |
deposit_to_refund_in_cents |
integer readonlyAmount of deposit (still) to be refunded. |
deposit_type |
enum nullableKind of deposit added. One of: none, percentage_total, percentage, fixed. |
deposit_value |
float The value to use for deposit_type. |
discount_in_cents |
integer readonlyDiscount (incl. or excl. taxes based on tax_strategy). |
discount_percentage |
float The discount percentage applied to this order. |
discount_type |
string readonlyType of discount. |
document_type |
enum readonly-after-createType of document. One of: invoice, contract, quote. |
due_date |
date The latest date by which the invoice must be fully paid. |
finalized |
boolean Whether document is finalized ( quote and contract are always finalized). |
footer |
string The footer of a document. Populated with setting {document_type}.footer, but can also be overridden for a specific document. |
fulfillment_type |
enum readonly-after-create nullableType of fulfillment. One of: pickup, delivery. |
grand_total_in_cents |
integer readonlyTotal excl. taxes (excl. deposit). |
grand_total_with_tax_in_cents |
integer readonlyAmount incl. taxes (excl. deposit). |
id |
uuid readonlyPrimary key. |
name |
string Customer name. If left blank, automatically populated with the customer name of the associated order. |
number |
integer The document number, must be unique per type. Automatically generated if left blank. |
order_id |
uuid readonly-after-createThe order this document is for. |
paid_in_cents |
integer readonlyHow much was paid. |
prefix |
string Add a prefix to document numbers to make it easier to identify different documents. You can add dynamic values (like a year or order number) and custom prefixes e.g. {year}-{customer_number}. |
prefix_with_number |
string readonlyRendered prefix with document number. |
price_in_cents |
integer readonlySubtotal excl. taxes (excl. deposit). |
reference |
string A project number or other reference. |
revised |
boolean Whether document is revised (applies only to invoice). |
revision |
string readonlyRevision number. Only applicable to invoices. Automatically generated when revising an invoice. |
sent |
boolean Whether document is sent (with Booqable). |
signature_url |
string readonlyURL where the signature is stored. |
start_location_id |
uuid readonlyThe ID of the pickup location. |
starts_at |
datetime readonlyThe start date and time of the rental. |
status |
enum Status (possible values depend on document type). One of: confirmed, unconfirmed, revised, partially_paid, payment_due, paid, process_deposit, overpaid. |
stop_location_id |
uuid readonlyThe ID of the return location. |
stops_at |
datetime readonlyThe end date and time of the rental. |
tag_list |
array Case insensitive tag list. |
tax_in_cents |
integer readonlyTotal tax. |
tax_region_id |
uuid nullableThe associated tax region. |
to_be_paid_in_cents |
integer readonlyAmount that (still) has to be paid. |
total_discount_in_cents |
integer readonlyTotal discount (incl. or excl. taxes based on tax_strategy). |
updated_at |
datetime readonlyWhen the resource was last updated. |
List documents
How to fetch a list of documents:
curl --get 'https://example.booqable.com/api/4/documents'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "a216b9f8-4f61-4eda-8672-3c6e94c9fbe2",
"type": "documents",
"attributes": {
"created_at": "2027-05-20T13:53:01.000000+00:00",
"updated_at": "2027-05-20T13:53:01.000000+00:00",
"archived": false,
"archived_at": null,
"document_type": "invoice",
"number": null,
"prefix": null,
"prefix_with_number": null,
"revision": null,
"date": null,
"due_date": null,
"name": "John Doe",
"address": null,
"body": null,
"footer": "",
"reference": null,
"starts_at": null,
"stops_at": null,
"start_location_id": null,
"stop_location_id": null,
"revised": false,
"finalized": false,
"sent": false,
"confirmed": false,
"status": "payment_due",
"signature_url": null,
"deposit_type": "percentage",
"deposit_value": 10.0,
"tag_list": [],
"price_in_cents": 80250,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"total_discount_in_cents": 8025,
"deposit_in_cents": 10000,
"deposit_paid_in_cents": 0,
"deposit_refunded_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"to_be_paid_in_cents": 97392,
"paid_in_cents": 0,
"tax_in_cents": 15167,
"discount_type": "percentage",
"discount_percentage": 10.0,
"fulfillment_type": "pickup",
"delivery_label": null,
"delivery_price_in_cents": 0,
"delivery_carrier_name": null,
"delivery_address": null,
"order_id": "e10da0d6-7881-4991-851f-ef302c712dea",
"customer_id": "6b39f922-ebba-4e73-841c-563dd37107d7",
"tax_region_id": null,
"coupon_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/documents
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[documents]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=customer,order |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
address |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
conditions |
hash eq |
confirmed |
boolean eq |
coupon_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
coupon_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
date |
date eq, not_eq, gt, gte, lt, lte |
date_or_created_at |
datetime eq, not_eq, gt, gte, lt, lte, between |
deposit_held_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_refunded_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_to_refund_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_type |
enum eq |
discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
discount_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
document_type |
enum eq, not_eq |
due_date |
date eq, not_eq, gt, gte, lt, lte |
finalized |
boolean eq |
fulfillment_type |
string eq |
grand_total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
grand_total_with_tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
number |
integer eq, not_eq, gt, gte, lt, lte |
order_id |
uuid eq, not_eq |
paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
prefix |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
prefix_with_number |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
revised |
boolean eq |
revision |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sent |
boolean eq |
start_location_id |
uuid eq, not_eq |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
stop_location_id |
uuid eq, not_eq |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
tax_region_id |
uuid eq, not_eq |
to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
coupon_discount_in_cents |
array sum, maximum, minimum, average |
currency |
array count |
deposit_held_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
deposit_paid_in_cents |
array sum, maximum, minimum, average |
deposit_refunded_in_cents |
array sum, maximum, minimum, average |
deposit_to_refund_in_cents |
array sum, maximum, minimum, average |
deposit_type |
array count |
discount_in_cents |
array sum, maximum, minimum, average |
discount_percentage |
array maximum, minimum, average |
fulfillment_type |
array count |
grand_total_in_cents |
array sum, maximum, minimum, average |
grand_total_with_tax_in_cents |
array sum, maximum, minimum, average |
paid_in_cents |
array sum, maximum, minimum, average |
price_in_cents |
array sum, maximum, minimum, average |
status |
array count |
tag_list |
array count |
tax_in_cents |
array sum, maximum, minimum, average |
tax_strategy |
array count |
to_be_paid_in_cents |
array sum, maximum, minimum, average |
total |
array count |
total_discount_in_cents |
array sum, maximum, minimum, average |
Includes
This request accepts the following includes:
customerorder
Search documents
Use advanced search to make logical filter groups with and/or operators.
How to search for documents:
curl --request POST
--url 'https://example.booqable.com/api/4/documents/search'
--header 'content-type: application/json'
--data '{
"fields": {
"documents": "id"
},
"filter": {
"conditions": {
"operator": "and",
"attributes": [
{
"operator": "or",
"attributes": [
{
"status": "paid"
},
{
"deposit_type": "none"
}
]
},
{
"operator": "and",
"attributes": [
{
"date": {
"gte": "2028-11-16T15:29:00.000000+00:00"
}
},
{
"date": {
"lte": "2028-11-22T15:29:00.000000+00:00"
}
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "c9fa6121-84c0-4a28-893a-cceb9d2be169"
},
{
"id": "3608f8e0-6ba6-4d67-81e0-800ee85ea024"
}
]
}
HTTP Request
POST /api/4/documents/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[documents]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=customer,order |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
address |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
conditions |
hash eq |
confirmed |
boolean eq |
coupon_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
coupon_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
date |
date eq, not_eq, gt, gte, lt, lte |
date_or_created_at |
datetime eq, not_eq, gt, gte, lt, lte, between |
deposit_held_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_refunded_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_to_refund_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_type |
enum eq |
discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
discount_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
document_type |
enum eq, not_eq |
due_date |
date eq, not_eq, gt, gte, lt, lte |
finalized |
boolean eq |
fulfillment_type |
string eq |
grand_total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
grand_total_with_tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
number |
integer eq, not_eq, gt, gte, lt, lte |
order_id |
uuid eq, not_eq |
paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
prefix |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
prefix_with_number |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
revised |
boolean eq |
revision |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sent |
boolean eq |
start_location_id |
uuid eq, not_eq |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
stop_location_id |
uuid eq, not_eq |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
tax_region_id |
uuid eq, not_eq |
to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
coupon_discount_in_cents |
array sum, maximum, minimum, average |
currency |
array count |
deposit_held_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
deposit_paid_in_cents |
array sum, maximum, minimum, average |
deposit_refunded_in_cents |
array sum, maximum, minimum, average |
deposit_to_refund_in_cents |
array sum, maximum, minimum, average |
deposit_type |
array count |
discount_in_cents |
array sum, maximum, minimum, average |
discount_percentage |
array maximum, minimum, average |
fulfillment_type |
array count |
grand_total_in_cents |
array sum, maximum, minimum, average |
grand_total_with_tax_in_cents |
array sum, maximum, minimum, average |
paid_in_cents |
array sum, maximum, minimum, average |
price_in_cents |
array sum, maximum, minimum, average |
status |
array count |
tag_list |
array count |
tax_in_cents |
array sum, maximum, minimum, average |
tax_strategy |
array count |
to_be_paid_in_cents |
array sum, maximum, minimum, average |
total |
array count |
total_discount_in_cents |
array sum, maximum, minimum, average |
Includes
This request accepts the following includes:
customerorder
Fetch a document
How to fetch a documents:
curl --get 'https://example.booqable.com/api/4/documents/9c32036d-e60c-47b1-8ff2-7e28343dac1b'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "9c32036d-e60c-47b1-8ff2-7e28343dac1b",
"type": "documents",
"attributes": {
"created_at": "2021-05-18T10:30:00.000000+00:00",
"updated_at": "2021-05-18T10:30:00.000000+00:00",
"archived": false,
"archived_at": null,
"document_type": "invoice",
"number": null,
"prefix": null,
"prefix_with_number": null,
"revision": null,
"date": null,
"due_date": null,
"name": "John Doe",
"address": null,
"body": null,
"footer": "",
"reference": null,
"starts_at": null,
"stops_at": null,
"start_location_id": null,
"stop_location_id": null,
"revised": false,
"finalized": false,
"sent": false,
"confirmed": false,
"status": "payment_due",
"signature_url": null,
"deposit_type": "percentage",
"deposit_value": 10.0,
"tag_list": [],
"price_in_cents": 80250,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"total_discount_in_cents": 8025,
"deposit_in_cents": 10000,
"deposit_paid_in_cents": 0,
"deposit_refunded_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"to_be_paid_in_cents": 97392,
"paid_in_cents": 0,
"tax_in_cents": 15167,
"discount_type": "percentage",
"discount_percentage": 10.0,
"fulfillment_type": "pickup",
"delivery_label": null,
"delivery_price_in_cents": 0,
"delivery_carrier_name": null,
"delivery_address": null,
"order_id": "9c1a27c9-93ab-45fc-810c-ad69b9ab9617",
"customer_id": "35578b5e-ed35-40b4-8e46-6d218d036c42",
"tax_region_id": null,
"coupon_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/documents/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[documents]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=coupon,properties,customer |
Includes
This request accepts the following includes:
coupon-
customerproperties
-
lines-
itemphotoproperties
-
planning-
stock_item_planningsstock_item
-
tax_category
-
-
ordercouponpropertiesstart_locationstop_location
propertiestax_regiontax_values
Create a document
How to create a contract:
curl --request POST
--url 'https://example.booqable.com/api/4/documents'
--header 'content-type: application/json'
--data '{
"data": {
"type": "documents",
"attributes": {
"document_type": "contract",
"order_id": "c7d596a9-f29d-4dd8-8f81-dac3bef16c03"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "33d005c3-65d8-4a49-80fa-5bc116112f39",
"type": "documents",
"attributes": {
"created_at": "2022-10-18T11:28:01.000000+00:00",
"updated_at": "2022-10-18T11:28:01.000000+00:00",
"archived": false,
"archived_at": null,
"document_type": "contract",
"number": 1,
"prefix": null,
"prefix_with_number": "1",
"revision": null,
"date": "2022-10-18",
"due_date": null,
"name": "John Doe",
"address": null,
"body": "",
"footer": "",
"reference": null,
"starts_at": "1977-03-09T14:03:01.000000+00:00",
"stops_at": "1977-04-08T14:03:01.000000+00:00",
"start_location_id": "2f4f9473-239b-4b05-8bb3-e9f933d42d64",
"stop_location_id": "2f4f9473-239b-4b05-8bb3-e9f933d42d64",
"revised": false,
"finalized": true,
"sent": false,
"confirmed": false,
"status": "unconfirmed",
"signature_url": null,
"deposit_type": "percentage",
"deposit_value": 10.0,
"tag_list": [],
"price_in_cents": 80250,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"total_discount_in_cents": 8025,
"deposit_in_cents": 10000,
"deposit_paid_in_cents": 0,
"deposit_refunded_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"to_be_paid_in_cents": 0,
"paid_in_cents": 0,
"tax_in_cents": 15167,
"discount_type": "percentage",
"discount_percentage": 10.0,
"fulfillment_type": "pickup",
"delivery_label": null,
"delivery_price_in_cents": 0,
"delivery_carrier_name": null,
"delivery_address": null,
"order_id": "c7d596a9-f29d-4dd8-8f81-dac3bef16c03",
"customer_id": "a937f30c-8af4-4171-89b6-fd40de388cf1",
"tax_region_id": null,
"coupon_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/documents
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[documents]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=coupon,properties,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address] |
string Customer Address. If left blank, automatically populated with the customer address of the associated order. |
data[attributes][body] |
string Custom content displayed on a document, agreement details on a contract, for instance. Applicable to quote and contract. Populated with setting {document_type}.body, but can also be overridden for a specific document. |
data[attributes][confirmed] |
boolean Whether document is confirmed, applies to quote and contract. |
data[attributes][coupon_id] |
uuid The associated coupon. |
data[attributes][customer_id] |
uuid The associated customer. |
data[attributes][date] |
date Date the document was finalized. |
data[attributes][deposit_type] |
enum Kind of deposit added. One of: none, percentage_total, percentage, fixed. |
data[attributes][deposit_value] |
float The value to use for deposit_type. |
data[attributes][discount_percentage] |
float The discount percentage applied to this order. |
data[attributes][document_type] |
enum Type of document. One of: invoice, contract, quote. |
data[attributes][due_date] |
date The latest date by which the invoice must be fully paid. |
data[attributes][finalized] |
boolean Whether document is finalized ( quote and contract are always finalized). |
data[attributes][footer] |
string The footer of a document. Populated with setting {document_type}.footer, but can also be overridden for a specific document. |
data[attributes][fulfillment_type] |
enum Type of fulfillment. One of: pickup, delivery. |
data[attributes][name] |
string Customer name. If left blank, automatically populated with the customer name of the associated order. |
data[attributes][number] |
integer The document number, must be unique per type. Automatically generated if left blank. |
data[attributes][order_id] |
uuid The order this document is for. |
data[attributes][prefix] |
string Add a prefix to document numbers to make it easier to identify different documents. You can add dynamic values (like a year or order number) and custom prefixes e.g. {year}-{customer_number}. |
data[attributes][reference] |
string A project number or other reference. |
data[attributes][revised] |
boolean Whether document is revised (applies only to invoice). |
data[attributes][sent] |
boolean Whether document is sent (with Booqable). |
data[attributes][status] |
enum Status (possible values depend on document type). One of: confirmed, unconfirmed, revised, partially_paid, payment_due, paid, process_deposit, overpaid. |
data[attributes][tag_list][] |
array Case insensitive tag list. |
data[attributes][tax_region_id] |
uuid The associated tax region. |
Includes
This request accepts the following includes:
coupon-
customerproperties
-
lines-
itemphotoproperties
-
planning-
stock_item_planningsstock_item
-
tax_category
-
-
ordercouponpropertiesstart_locationstop_location
propertiestax_regiontax_values
Update a document
How to update a document:
curl --request PUT
--url 'https://example.booqable.com/api/4/documents/6b8e0c59-4b01-42e6-8477-bbfa4cea11f3'
--header 'content-type: application/json'
--data '{
"data": {
"id": "6b8e0c59-4b01-42e6-8477-bbfa4cea11f3",
"type": "documents",
"attributes": {
"name": "Jane Doe"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "6b8e0c59-4b01-42e6-8477-bbfa4cea11f3",
"type": "documents",
"attributes": {
"created_at": "2016-09-18T03:33:01.000000+00:00",
"updated_at": "2016-09-18T03:33:01.000000+00:00",
"archived": false,
"archived_at": null,
"document_type": "invoice",
"number": null,
"prefix": null,
"prefix_with_number": null,
"revision": null,
"date": null,
"due_date": null,
"name": "Jane Doe",
"address": null,
"body": null,
"footer": "",
"reference": null,
"starts_at": null,
"stops_at": null,
"start_location_id": null,
"stop_location_id": null,
"revised": false,
"finalized": false,
"sent": false,
"confirmed": false,
"status": "payment_due",
"signature_url": null,
"deposit_type": "percentage",
"deposit_value": 10.0,
"tag_list": [],
"price_in_cents": 80250,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"total_discount_in_cents": 8025,
"deposit_in_cents": 10000,
"deposit_paid_in_cents": 0,
"deposit_refunded_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"to_be_paid_in_cents": 97392,
"paid_in_cents": 0,
"tax_in_cents": 15167,
"discount_type": "percentage",
"discount_percentage": 10.0,
"fulfillment_type": "pickup",
"delivery_label": null,
"delivery_price_in_cents": 0,
"delivery_carrier_name": null,
"delivery_address": null,
"order_id": "6952ae61-0c41-4a20-8379-52f56e41884c",
"customer_id": "da876af0-82ef-4a18-8e51-86680fba81bc",
"tax_region_id": null,
"coupon_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/documents/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[documents]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=coupon,properties,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address] |
string Customer Address. If left blank, automatically populated with the customer address of the associated order. |
data[attributes][body] |
string Custom content displayed on a document, agreement details on a contract, for instance. Applicable to quote and contract. Populated with setting {document_type}.body, but can also be overridden for a specific document. |
data[attributes][confirmed] |
boolean Whether document is confirmed, applies to quote and contract. |
data[attributes][coupon_id] |
uuid The associated coupon. |
data[attributes][customer_id] |
uuid The associated customer. |
data[attributes][date] |
date Date the document was finalized. |
data[attributes][deposit_type] |
enum Kind of deposit added. One of: none, percentage_total, percentage, fixed. |
data[attributes][deposit_value] |
float The value to use for deposit_type. |
data[attributes][discount_percentage] |
float The discount percentage applied to this order. |
data[attributes][document_type] |
enum Type of document. One of: invoice, contract, quote. |
data[attributes][due_date] |
date The latest date by which the invoice must be fully paid. |
data[attributes][finalized] |
boolean Whether document is finalized ( quote and contract are always finalized). |
data[attributes][footer] |
string The footer of a document. Populated with setting {document_type}.footer, but can also be overridden for a specific document. |
data[attributes][fulfillment_type] |
enum Type of fulfillment. One of: pickup, delivery. |
data[attributes][name] |
string Customer name. If left blank, automatically populated with the customer name of the associated order. |
data[attributes][number] |
integer The document number, must be unique per type. Automatically generated if left blank. |
data[attributes][order_id] |
uuid The order this document is for. |
data[attributes][prefix] |
string Add a prefix to document numbers to make it easier to identify different documents. You can add dynamic values (like a year or order number) and custom prefixes e.g. {year}-{customer_number}. |
data[attributes][reference] |
string A project number or other reference. |
data[attributes][revised] |
boolean Whether document is revised (applies only to invoice). |
data[attributes][sent] |
boolean Whether document is sent (with Booqable). |
data[attributes][status] |
enum Status (possible values depend on document type). One of: confirmed, unconfirmed, revised, partially_paid, payment_due, paid, process_deposit, overpaid. |
data[attributes][tag_list][] |
array Case insensitive tag list. |
data[attributes][tax_region_id] |
uuid The associated tax region. |
Includes
This request accepts the following includes:
coupon-
customerproperties
-
lines-
itemphotoproperties
-
planning-
stock_item_planningsstock_item
-
tax_category
-
-
ordercouponpropertiesstart_locationstop_location
propertiestax_regiontax_values
Archive a document
When archiving an invoice make sure delete_invoices permission is enabled.
How to archive a document:
curl --request DELETE
--url 'https://example.booqable.com/api/4/documents/e00df330-8241-466f-8706-d2db3d03494d'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "e00df330-8241-466f-8706-d2db3d03494d",
"type": "documents",
"attributes": {
"created_at": "2018-05-06T00:22:02.000000+00:00",
"updated_at": "2018-05-06T00:22:02.000000+00:00",
"archived": true,
"archived_at": "2018-05-06T00:22:02.000000+00:00",
"document_type": "invoice",
"number": null,
"prefix": null,
"prefix_with_number": null,
"revision": null,
"date": null,
"due_date": null,
"name": "John Doe",
"address": null,
"body": null,
"footer": "",
"reference": null,
"starts_at": null,
"stops_at": null,
"start_location_id": null,
"stop_location_id": null,
"revised": false,
"finalized": false,
"sent": false,
"confirmed": false,
"status": "payment_due",
"signature_url": null,
"deposit_type": "percentage",
"deposit_value": 10.0,
"tag_list": [],
"price_in_cents": 80250,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"total_discount_in_cents": 8025,
"deposit_in_cents": 10000,
"deposit_paid_in_cents": 0,
"deposit_refunded_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"to_be_paid_in_cents": 97392,
"paid_in_cents": 0,
"tax_in_cents": 15167,
"discount_type": "percentage",
"discount_percentage": 10.0,
"fulfillment_type": "pickup",
"delivery_label": null,
"delivery_price_in_cents": 0,
"delivery_carrier_name": null,
"delivery_address": null,
"order_id": "9253db70-5ed8-44a6-8d0b-f1af78e021fe",
"customer_id": "3af62bd7-4635-4714-8680-79d8e23ec549",
"tax_region_id": null,
"coupon_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/documents/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[documents]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Emails
Emails allow you to easily communicate with your customers by using optional templates. Booqable keeps a complete history of all emails sent for orders or customers, making it easy to track customer communications and maintain a clear audit trail.
Creating Emails
Emails can be created manually through the API or automatically triggered by certain system events. When creating an email, you can either provide the content directly (subject and body) or reference an EmailTemplate that will be rendered using data from associated resources.
Sending Process
After an email is created and validated, it's automatically queued for delivery through
Booqable's email service. The sent attribute indicates whether the email was successfully
handed off to the mail server, while has_error shows if any problems occurred during
the sending process. Emails are processed asynchronously to ensure fast API responses.
Relationships
| Name | Description |
|---|---|
customer |
Customer requiredThe Customer this email is associated with. When specified and using an EmailTemplate, customer data is available during template rendering. This relationship is useful for customer-specific communications that aren't tied to a particular order, or for providing customer context when an order relationship is also present. The customer's email address is typically used as the default recipient. |
email_template |
Email template requiredThe EmailTemplate used to generate this email's content. When specified, the template is rendered with data from the associated resources to populate the email's subject and body. Templates allow for consistent, branded communication with dynamic content. |
employee |
Employee requiredThe Employee who created and sent this email. This is automatically set to the current user when the email is created and cannot be modified. The employee relationship tracks who initiated the communication and may be used for reply-to addresses or signature information in the email content. |
order |
Order requiredThe Order this email is associated with. When an email is linked to an order and uses an EmailTemplate, the template can access order data during rendering. Linking an email to an order also helps maintain a clear communication history for that rental transaction. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
body |
string The main content of the email. When providing the body directly (without using an EmailTemplate), this is the final text that will be sent. When using a template, this field is automatically populated by rendering the template with data from associated resources. |
created_at |
datetime readonlyWhen the email was created by the user or automatically by Booqable. At this time, the email has not been sent yet and may still be in the process of being prepared. Once the email is created and validated, it will be queued for delivery. |
customer_id |
uuid readonly-after-createThe Customer this email is associated with. When specified and using an EmailTemplate, customer data is available during template rendering. This relationship is useful for customer-specific communications that aren't tied to a particular order, or for providing customer context when an order relationship is also present. The customer's email address is typically used as the default recipient. |
document_ids |
array Array of Document IDs to attach to the email. These documents will be included as PDF attachments when the email is sent. Common use cases include attaching quotes, contracts, or invoices to customer communications. |
email_template_id |
uuid readonly-after-createThe EmailTemplate used to generate this email's content. When specified, the template is rendered with data from the associated resources to populate the email's subject and body. Templates allow for consistent, branded communication with dynamic content. |
employee_id |
uuid readonlyThe Employee who created and sent this email. This is automatically set to the current user when the email is created and cannot be modified. The employee relationship tracks who initiated the communication and may be used for reply-to addresses or signature information in the email content. |
has_error |
boolean readonlyWhether any errors occurred when attempting to send this email. Returns true if the email encountered problems during sending (such as invalid addresses, server issues, or other delivery failures). When true, additional error details may be available to help diagnose the issue. |
id |
uuid readonlyPrimary key. |
order_id |
uuid readonly-after-createThe Order this email is associated with. When an email is linked to an order and uses an EmailTemplate, the template can access order data during rendering. Linking an email to an order also helps maintain a clear communication history for that rental transaction. |
payment_id |
uuid writeonlyPayment to use when rendering an EmailTemplate. When provided, payment data is available during template rendering, which is useful for sending payment requests or payment confirmation emails with payment-specific information such as payment links. |
recipients |
string Comma-separated list of recipient email addresses. All addresses must be valid and properly formatted for the email to be sent. The system validates each address before sending. Multiple recipients can be specified, but there is a limit on the maximum number of recipients per email to prevent abuse. The limit is 10 recipients per email. |
sent |
boolean readonlyWhether the email was sent successfully. Returns true if the email has been delivered to the mail server, false if it hasn't been sent yet or if sending failed. Note that this indicates successful handoff to the mail server, not necessarily that the recipient received the email. |
subject |
string The subject line of the email. When providing the subject directly (without using an EmailTemplate), this is the exact text that will appear in the recipient's inbox. When using a template, this field is automatically populated by rendering the template's subject with the available data from associated resources. |
updated_at |
datetime readonlyThe last time the email was updated. This timestamp changes when the email status is modified, such as after a delivery attempt succeeds or fails. Updates may also occur when error information is recorded or when the email is retried after a failed delivery attempt. |
List emails
How to fetch a list of emails:
curl --get 'https://example.booqable.com/api/4/emails'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "b882543c-57cc-4fcf-8a1e-dc471e664ac4",
"type": "emails",
"attributes": {
"created_at": "2016-11-24T02:24:00.000000+00:00",
"updated_at": "2016-11-24T02:24:00.000000+00:00",
"subject": "Order confirmation",
"body": "We hereby confirm your order with number #123",
"recipients": "[email protected]",
"has_error": false,
"sent": false,
"document_ids": [],
"order_id": null,
"customer_id": "878c23b8-3fa0-44b1-856f-7fd95560fabc",
"email_template_id": null,
"employee_id": null
},
"relationships": {}
}
],
"meta": {}
}
How to fetch a list of emails for a specific order:
curl --get 'https://example.booqable.com/api/4/emails'
--header 'content-type: application/json'
--data-urlencode 'filter[order_id]=f97ca4a9-7d59-46d9-8df1-6cc7dae11393'
A 200 status response looks like this:
{
"data": [
{
"id": "a1b5a25c-bd16-4249-8052-72ebda9c133d",
"type": "emails",
"attributes": {
"created_at": "2024-08-21T09:09:01.000000+00:00",
"updated_at": "2024-08-21T09:09:01.000000+00:00",
"subject": "Order confirmation",
"body": "We hereby confirm your order with number #123",
"recipients": "[email protected]",
"has_error": false,
"sent": false,
"document_ids": [],
"order_id": "f97ca4a9-7d59-46d9-8df1-6cc7dae11393",
"customer_id": "659dbd01-2c4c-42b8-890e-afe1f60d29ec",
"email_template_id": null,
"employee_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/emails
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[emails]=created_at,updated_at,subject |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=customer,order |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
email_template_id |
uuid eq, not_eq |
employee_id |
uuid eq, not_eq |
has_error |
boolean eq |
id |
uuid eq, not_eq |
order_id |
uuid eq, not_eq |
sent |
boolean eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
has_error |
array count |
total |
array count |
Includes
This request accepts the following includes:
customerorder
Create and sending an email
How to create and send an email:
curl --request POST
--url 'https://example.booqable.com/api/4/emails'
--header 'content-type: application/json'
--data '{
"data": {
"type": "emails",
"attributes": {
"recipients": "[email protected],[email protected]",
"subject": "Order confirmation",
"body": "Hi {{customer.name}}",
"email_template_id": "4b2e6043-c307-4b1c-8f2d-872b85d20fc4",
"order_id": "c504d320-966c-4b0d-88fb-9490bc6483e5",
"customer_id": "c353e670-ad55-43ad-803b-3e12456726de",
"document_ids": [
"b308505b-b1cb-485c-8d0e-7d937d2f38a5"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "b0779013-b390-48c6-8286-123716b0a3e1",
"type": "emails",
"attributes": {
"created_at": "2025-09-16T16:16:01.000000+00:00",
"updated_at": "2025-09-16T16:16:01.000000+00:00",
"subject": "Order confirmation",
"body": "Hi {{customer.name}}",
"recipients": "[email protected],[email protected]",
"has_error": false,
"sent": false,
"document_ids": [
"b308505b-b1cb-485c-8d0e-7d937d2f38a5"
],
"order_id": "c504d320-966c-4b0d-88fb-9490bc6483e5",
"customer_id": "c353e670-ad55-43ad-803b-3e12456726de",
"email_template_id": "4b2e6043-c307-4b1c-8f2d-872b85d20fc4",
"employee_id": "1a34d41c-d99a-49de-8090-cb632e9ef172"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/emails
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[emails]=created_at,updated_at,subject |
include |
string List of comma seperated relationships to sideload. ?include=customer,order,email_template |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][body] |
string The main content of the email. When providing the body directly (without using an EmailTemplate), this is the final text that will be sent. When using a template, this field is automatically populated by rendering the template with data from associated resources. |
data[attributes][customer_id] |
uuid The Customer this email is associated with. When specified and using an EmailTemplate, customer data is available during template rendering. This relationship is useful for customer-specific communications that aren't tied to a particular order, or for providing customer context when an order relationship is also present. The customer's email address is typically used as the default recipient. |
data[attributes][document_ids][] |
array Array of Document IDs to attach to the email. These documents will be included as PDF attachments when the email is sent. Common use cases include attaching quotes, contracts, or invoices to customer communications. |
data[attributes][email_template_id] |
uuid The EmailTemplate used to generate this email's content. When specified, the template is rendered with data from the associated resources to populate the email's subject and body. Templates allow for consistent, branded communication with dynamic content. |
data[attributes][order_id] |
uuid The Order this email is associated with. When an email is linked to an order and uses an EmailTemplate, the template can access order data during rendering. Linking an email to an order also helps maintain a clear communication history for that rental transaction. |
data[attributes][payment_id] |
uuid Payment to use when rendering an EmailTemplate. When provided, payment data is available during template rendering, which is useful for sending payment requests or payment confirmation emails with payment-specific information such as payment links. |
data[attributes][recipients] |
string Comma-separated list of recipient email addresses. All addresses must be valid and properly formatted for the email to be sent. The system validates each address before sending. Multiple recipients can be specified, but there is a limit on the maximum number of recipients per email to prevent abuse. The limit is 10 recipients per email. |
data[attributes][subject] |
string The subject line of the email. When providing the subject directly (without using an EmailTemplate), this is the exact text that will appear in the recipient's inbox. When using a template, this field is automatically populated by rendering the template's subject with the available data from associated resources. |
Includes
This request accepts the following includes:
customeremail_templateorder
Email templates
Email templates allow for creating pre-filled emails with dynamic data. Booqable comes with a couple of default templates which can be updated but not deleted.
For more information about using variables for dynamic data in email templates see our help center
Fields
| Name | Description |
|---|---|
automated |
boolean readonlyWhen true, this template is used by built-in features and cannot be deleted. Updating is possible. |
body |
string Email body template. |
context |
enum Which resource or process the template applies to. One of: order, invoice, document, all, payment, user. |
created_at |
datetime readonlyWhen the resource was created. |
default |
boolean readonlyWhether this is a system default template. |
id |
uuid readonlyPrimary key. |
identifier |
string readonlyA unique identifier assigned to this template. |
name |
string Name of the template. |
subject |
string Email subject line template. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List email templates
How to fetch a list of email templates:
curl --get 'https://example.booqable.com/api/4/email_templates'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "e0a7c360-45c6-4a04-81c5-8886d3aeb275",
"type": "email_templates",
"attributes": {
"created_at": "2018-07-14T00:07:00.000000+00:00",
"updated_at": "2018-07-14T00:07:00.000000+00:00",
"name": "Webshop confirmation",
"identifier": "webshop_confirmation",
"subject": "We received your order",
"context": "all",
"body": "We'll get started on it right away",
"default": false,
"automated": false
}
}
],
"meta": {}
}
HTTP Request
GET /api/4/email_templates
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[email_templates]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
automated |
boolean eq |
context |
enum eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
default |
boolean eq |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch an email template
How to fetch an email template:
curl --get 'https://example.booqable.com/api/4/email_templates/95b3a72d-9c05-4c26-8679-d2ecd5ff2739'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "95b3a72d-9c05-4c26-8679-d2ecd5ff2739",
"type": "email_templates",
"attributes": {
"created_at": "2023-09-05T22:46:01.000000+00:00",
"updated_at": "2023-09-05T22:46:01.000000+00:00",
"name": "Webshop confirmation",
"identifier": "webshop_confirmation",
"subject": "We received your order",
"context": "all",
"body": "We'll get started on it right away",
"default": false,
"automated": false
}
},
"meta": {}
}
HTTP Request
GET /api/4/email_templates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[email_templates]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=emails |
Includes
This request accepts the following includes:
emails
Create an email template
How to create a email template:
curl --request POST
--url 'https://example.booqable.com/api/4/email_templates'
--header 'content-type: application/json'
--data '{
"data": {
"type": "email_templates",
"attributes": {
"name": "Webshop confirmation",
"subject": "We received your order (#{{order.number}})",
"body": "We'll get started on it right away. Your order number is #{{order.number}}.",
"context": "order"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "fdb97b9d-4542-44dc-856e-510228b6d83a",
"type": "email_templates",
"attributes": {
"created_at": "2019-09-07T19:36:01.000000+00:00",
"updated_at": "2019-09-07T19:36:01.000000+00:00",
"name": "Webshop confirmation",
"identifier": "webshop_confirmation",
"subject": "We received your order (#{{order.number}})",
"context": "order",
"body": "We'll get started on it right away. Your order number is #{{order.number}}.",
"default": false,
"automated": false
}
},
"meta": {}
}
HTTP Request
POST /api/4/email_templates
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[email_templates]=created_at,updated_at,name |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][body] |
string Email body template. |
data[attributes][context] |
enum Which resource or process the template applies to. One of: order, invoice, document, all, payment, user. |
data[attributes][name] |
string Name of the template. |
data[attributes][subject] |
string Email subject line template. |
Includes
This request does not accept any includes
Update an email template
How to update an email template:
curl --request PUT
--url 'https://example.booqable.com/api/4/email_templates/8cc919ef-bada-48fa-8d22-1ee523f0e88f'
--header 'content-type: application/json'
--data '{
"data": {
"id": "8cc919ef-bada-48fa-8d22-1ee523f0e88f",
"type": "email_templates",
"attributes": {
"name": "Order confirmation"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "8cc919ef-bada-48fa-8d22-1ee523f0e88f",
"type": "email_templates",
"attributes": {
"created_at": "2027-11-19T06:26:00.000000+00:00",
"updated_at": "2027-11-19T06:26:00.000000+00:00",
"name": "Order confirmation",
"identifier": "webshop_confirmation",
"subject": "We received your order",
"context": "all",
"body": "We'll get started on it right away",
"default": false,
"automated": false
}
},
"meta": {}
}
How to update a default email template:
curl --request PUT
--url 'https://example.booqable.com/api/4/email_templates/f4304c84-6349-470c-875b-7bc8ac0dd626'
--header 'content-type: application/json'
--data '{
"data": {
"id": "f4304c84-6349-470c-875b-7bc8ac0dd626",
"type": "email_templates",
"attributes": {
"name": "Order confirmation"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "f4304c84-6349-470c-875b-7bc8ac0dd626",
"type": "email_templates",
"attributes": {
"created_at": "2017-06-27T23:42:00.000000+00:00",
"updated_at": "2017-06-27T23:42:00.000000+00:00",
"name": "Order confirmation",
"identifier": "webshop_confirmation",
"subject": "We received your order",
"context": "all",
"body": "We'll get started on it right away",
"default": true,
"automated": false
}
},
"meta": {}
}
HTTP Request
PUT /api/4/email_templates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[email_templates]=created_at,updated_at,name |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][body] |
string Email body template. |
data[attributes][context] |
enum Which resource or process the template applies to. One of: order, invoice, document, all, payment, user. |
data[attributes][name] |
string Name of the template. |
data[attributes][subject] |
string Email subject line template. |
Includes
This request does not accept any includes
Delete an email template
How to delete a email template:
curl --request DELETE
--url 'https://example.booqable.com/api/4/email_templates/1353d9c3-b214-4b45-8153-505e3ab4d573'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "1353d9c3-b214-4b45-8153-505e3ab4d573",
"type": "email_templates",
"attributes": {
"created_at": "2019-10-07T17:21:00.000000+00:00",
"updated_at": "2019-10-07T17:21:00.000000+00:00",
"name": "Sales Tax",
"identifier": "sales_tax",
"subject": "This is a subject!",
"context": "all",
"body": "Hi there user!",
"default": false,
"automated": false
}
},
"meta": {}
}
HTTP Request
DELETE /api/4/email_templates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[email_templates]=created_at,updated_at,name |
Includes
This request does not accept any includes
Employees
Employees give access to a Booqable account. You can set different permissions for each employee and let other people use Booqable without giving them access to sensitive information.
Employees also allow you to streamline Booqable's interface for specific roles or use cases. For example, if you create an account for someone dedicated to looking after your financials and accounting, it wouldn't need to manage your products and stock levels.
Fields
| Name | Description |
|---|---|
active |
boolean Whether this employee is active (counts towards billing). |
avatar_base64 |
string writeonlyBase64 encoded avatar. |
avatar_url |
string readonlyUrl to avatar. |
confirmed |
boolean readonlyWhether this employee confirmed it's email address. |
created_at |
datetime readonlyWhen the resource was created. |
current_password |
string writeonlyCurrent password, needed to update password or email address. |
deactivated_at |
datetime writeonlyEmployee deactivation date. |
email |
string Employee's e-mail address. |
firstname |
string First name of the employee. |
has_two_factor_autentication |
boolean readonlyWhether two factor authentication is enabled. |
id |
uuid readonlyPrimary key. |
large_avatar_url |
string readonlyUrl to avatar (Large). |
lastname |
string Last name of the employee. |
locale |
string Locale of the employee, used as application locale. |
name |
string readonlyFull name of the employee. |
owner |
boolean readonlyWhether this employee is the account owner. |
password |
string writeonlySet a new password. |
password_confirmation |
string writeonlyConfirm new password. |
permissions |
array Zero or more from: reports, products, settings, security_settings, account, exports, cancel_orders, revert_orders, delete_invoices, make_invoice_revisions, override_rental_period. All permissions are always returned when the roles & permissions feature is not included in the current pricing plan or if the employee is the account owner. |
remove_avatar |
boolean writeonlyRemove current avatar. |
third_party_id |
string ID used for third party tools. |
time_to_confirm |
integer readonlyTime in days left to confirm. |
unconfirmed_email |
string readonlyUnconfirmed e-mail address if present. |
updated_at |
datetime readonlyWhen the resource was last updated. |
viewed_whats_new_at |
datetime Date when this employee viewed product updates for the last time. |
List employees
How to fetch a list of employees:
curl --get 'https://example.booqable.com/api/4/employees'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "9e27ff9f-0909-42c7-81b2-3bb9f34ad507",
"type": "employees",
"attributes": {
"created_at": "2021-09-07T07:00:00.000000+00:00",
"updated_at": "2024-04-27T03:52:00.000000+00:00",
"name": "John Doe",
"firstname": "John",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2023-06-07T12:19:00.000000+00:00",
"active": true,
"owner": true,
"confirmed": true,
"time_to_confirm": 0,
"permissions": [
"reports",
"products",
"settings",
"security_settings",
"account",
"exports",
"cancel_orders",
"revert_orders",
"delete_invoices",
"make_invoice_revisions",
"override_rental_period"
],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/f3eb64211cf620aa291957f1f66d5f39.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/f3eb64211cf620aa291957f1f66d5f39.png?d=mm&size=200",
"third_party_id": "9e27ff9f-0909-42c7-81b2-3bb9f34ad507-1679574840"
}
}
],
"meta": {}
}
HTTP Request
GET /api/4/employees
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[employees]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
active |
boolean eq |
confirmed |
boolean eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deactivated_at |
datetime eq, not_eq, gt, gte, lt, lte |
email |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
id |
uuid eq, not_eq |
locale |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
owner |
boolean eq |
third_party_id |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch an employee
How to fetch a employee:
curl --get 'https://example.booqable.com/api/4/employees/4c367dac-4839-49f3-89e4-ff584a1f30e0'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "4c367dac-4839-49f3-89e4-ff584a1f30e0",
"type": "employees",
"attributes": {
"created_at": "2015-05-14T01:40:00.000000+00:00",
"updated_at": "2017-01-20T23:07:00.000000+00:00",
"name": "John Doe",
"firstname": "John",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2017-02-10T06:59:00.000000+00:00",
"active": true,
"owner": true,
"confirmed": true,
"time_to_confirm": 0,
"permissions": [
"reports",
"products",
"settings",
"security_settings",
"account",
"exports",
"cancel_orders",
"revert_orders",
"delete_invoices",
"make_invoice_revisions",
"override_rental_period"
],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/b9e4d02e55a6d091223dfb568620be4b.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/b9e4d02e55a6d091223dfb568620be4b.png?d=mm&size=200",
"third_party_id": "4c367dac-4839-49f3-89e4-ff584a1f30e0-1679574840"
}
},
"meta": {}
}
HTTP Request
GET /api/4/employees/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[employees]=created_at,updated_at,name |
Includes
This request does not accept any includes
Update an employee
How to update an employee:
curl --request PUT
--url 'https://example.booqable.com/api/4/employees/cebcf411-1b2a-402f-8d77-43c67daf282f'
--header 'content-type: application/json'
--data '{
"data": {
"id": "cebcf411-1b2a-402f-8d77-43c67daf282f",
"type": "employees",
"attributes": {
"firstname": "Jane"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "cebcf411-1b2a-402f-8d77-43c67daf282f",
"type": "employees",
"attributes": {
"created_at": "2016-10-03T04:30:00.000000+00:00",
"updated_at": "2022-07-23T16:22:00.000000+00:00",
"name": "Jane Doe",
"firstname": "Jane",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2021-07-24T23:16:00.000000+00:00",
"active": true,
"owner": false,
"confirmed": true,
"time_to_confirm": 0,
"permissions": [
"reports",
"products",
"settings",
"security_settings",
"account",
"exports",
"cancel_orders",
"revert_orders",
"delete_invoices",
"make_invoice_revisions",
"override_rental_period"
],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/716558eb15f1e4801c770410e3eed8fe.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/716558eb15f1e4801c770410e3eed8fe.png?d=mm&size=200",
"third_party_id": "cebcf411-1b2a-402f-8d77-43c67daf282f-1579642440"
}
},
"meta": {}
}
How to de-activate an employee:
curl --request PUT
--url 'https://example.booqable.com/api/4/employees/b40a7c1c-5190-4d54-8cea-405d36944a87'
--header 'content-type: application/json'
--data '{
"data": {
"id": "b40a7c1c-5190-4d54-8cea-405d36944a87",
"type": "employees",
"attributes": {
"active": false
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "b40a7c1c-5190-4d54-8cea-405d36944a87",
"type": "employees",
"attributes": {
"created_at": "2014-10-16T17:49:01.000000+00:00",
"updated_at": "2020-08-05T05:41:01.000000+00:00",
"name": "John Doe",
"firstname": "John",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2019-08-07T12:35:01.000000+00:00",
"active": false,
"owner": false,
"confirmed": true,
"time_to_confirm": 0,
"permissions": [
"reports",
"products",
"settings",
"security_settings",
"account",
"exports",
"cancel_orders",
"revert_orders",
"delete_invoices",
"make_invoice_revisions",
"override_rental_period"
],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/8a0e879db54c50c14de0c4203a4e7a93.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/8a0e879db54c50c14de0c4203a4e7a93.png?d=mm&size=200",
"third_party_id": "b40a7c1c-5190-4d54-8cea-405d36944a87-1579642440"
}
},
"meta": {}
}
How to set permissions:
curl --request PUT
--url 'https://example.booqable.com/api/4/employees/94b3f0ff-ef32-49be-8f5f-7aa6916cc901'
--header 'content-type: application/json'
--data '{
"data": {
"id": "94b3f0ff-ef32-49be-8f5f-7aa6916cc901",
"type": "employees",
"attributes": {
"permissions": [
"reports",
"settings"
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "94b3f0ff-ef32-49be-8f5f-7aa6916cc901",
"type": "employees",
"attributes": {
"created_at": "2027-04-16T02:37:01.000000+00:00",
"updated_at": "2033-02-02T14:29:01.000000+00:00",
"name": "John Doe",
"firstname": "John",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2032-02-04T21:23:01.000000+00:00",
"active": true,
"owner": false,
"confirmed": true,
"time_to_confirm": 0,
"permissions": [
"reports",
"settings"
],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/ae75ea2be6c7d7aa987d98145aa7618c.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/ae75ea2be6c7d7aa987d98145aa7618c.png?d=mm&size=200",
"third_party_id": "94b3f0ff-ef32-49be-8f5f-7aa6916cc901-1579642440"
}
},
"meta": {}
}
HTTP Request
PUT /api/4/employees/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[employees]=created_at,updated_at,name |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][active] |
boolean Whether this employee is active (counts towards billing). |
data[attributes][avatar_base64] |
string Base64 encoded avatar. |
data[attributes][current_password] |
string Current password, needed to update password or email address. |
data[attributes][deactivated_at] |
datetime Employee deactivation date. |
data[attributes][email] |
string Employee's e-mail address. |
data[attributes][firstname] |
string First name of the employee. |
data[attributes][lastname] |
string Last name of the employee. |
data[attributes][locale] |
string Locale of the employee, used as application locale. |
data[attributes][password] |
string Set a new password. |
data[attributes][password_confirmation] |
string Confirm new password. |
data[attributes][permissions][] |
array Zero or more from: reports, products, settings, security_settings, account, exports, cancel_orders, revert_orders, delete_invoices, make_invoice_revisions, override_rental_period. All permissions are always returned when the roles & permissions feature is not included in the current pricing plan or if the employee is the account owner. |
data[attributes][remove_avatar] |
boolean Remove current avatar. |
data[attributes][third_party_id] |
string ID used for third party tools. |
data[attributes][viewed_whats_new_at] |
datetime Date when this employee viewed product updates for the last time. |
Includes
This request does not accept any includes
Employee invitations
Employees give access to a Booqable account. You can invite employees by sending an invitation. For more info about employees see Employees.
Relationships
| Name | Description |
|---|---|
employee |
Employee optionalThe employee that is invited. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
email |
string writeonlyEmployee's email address. |
employee_id |
uuid nullableThe employee that is invited. |
firstname |
string writeonlyFirst name of the employee. |
id |
uuid Specify employee ID to re-send invitation. |
lastname |
string writeonlyLast name of the employee. |
permissions |
array[string] writeonlyZero or more from: reports, products, settings, security_settings, account, exports, cancel_orders, revert_orders, delete_invoices, make_invoice_revisions, override_rental_period. |
Send invitations
How to create an invitation:
curl --request POST
--url 'https://example.booqable.com/api/4/employee_invitations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "employee_invitations",
"attributes": {
"firstname": "John",
"lastname": "Doe",
"email": "[email protected]"
}
},
"include": "employee"
}'
A 201 status response looks like this:
{
"data": {
"id": "bb80bf32-f049-4ea9-8090-006821195ab4",
"type": "employee_invitations",
"attributes": {
"employee_id": "1ccdaa36-f317-4feb-8a06-003668fc0c59"
},
"relationships": {
"employee": {
"data": {
"type": "employees",
"id": "1ccdaa36-f317-4feb-8a06-003668fc0c59"
}
}
}
},
"included": [
{
"id": "1ccdaa36-f317-4feb-8a06-003668fc0c59",
"type": "employees",
"attributes": {
"created_at": "2020-01-26T19:11:05.000000+00:00",
"updated_at": "2020-01-26T19:11:05.000000+00:00",
"name": "John Doe",
"firstname": "John",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2020-01-26T19:11:05.000000+00:00",
"active": true,
"owner": false,
"confirmed": false,
"time_to_confirm": 0,
"permissions": [],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/31ff5e6c9b0f2e3b5d27340dd84e003a.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/31ff5e6c9b0f2e3b5d27340dd84e003a.png?d=mm&size=200",
"third_party_id": "1ccdaa36-f317-4feb-8a06-003668fc0c59-1762766792"
}
}
],
"meta": {}
}
To re-send an invitation we supply the ID the employee for which the invitation was sent. Note that you can also update other fields.:
curl --request POST
--url 'https://example.booqable.com/api/4/employee_invitations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "employee_invitations",
"attributes": {
"id": "a5f55cdd-7e5a-46ea-84db-1c8352c8fa06",
"email": "[email protected]"
}
},
"include": "employee"
}'
A 201 status response looks like this:
{
"data": {
"id": "a5f55cdd-7e5a-46ea-84db-1c8352c8fa06",
"type": "employee_invitations",
"attributes": {
"employee_id": "a5f55cdd-7e5a-46ea-84db-1c8352c8fa06"
},
"relationships": {
"employee": {
"data": {
"type": "employees",
"id": "a5f55cdd-7e5a-46ea-84db-1c8352c8fa06"
}
}
}
},
"included": [
{
"id": "a5f55cdd-7e5a-46ea-84db-1c8352c8fa06",
"type": "employees",
"attributes": {
"created_at": "2020-05-11T21:58:00.000000+00:00",
"updated_at": "2020-05-11T21:58:00.000000+00:00",
"name": "John Doe",
"firstname": "John",
"lastname": "Doe",
"locale": null,
"email": "[email protected]",
"unconfirmed_email": null,
"viewed_whats_new_at": "2020-05-11T21:58:00.000000+00:00",
"active": true,
"owner": true,
"confirmed": true,
"time_to_confirm": 0,
"permissions": [
"reports",
"products",
"settings",
"security_settings",
"account",
"exports",
"cancel_orders",
"revert_orders",
"delete_invoices",
"make_invoice_revisions",
"override_rental_period"
],
"has_two_factor_autentication": false,
"avatar_url": "https://gravatar.com/avatar/98d4e49bbf9d94d0b9c6155e3e6ad46c.png?d=404",
"large_avatar_url": "https://gravatar.com/avatar/98d4e49bbf9d94d0b9c6155e3e6ad46c.png?d=mm&size=200",
"third_party_id": "a5f55cdd-7e5a-46ea-84db-1c8352c8fa06-1762766793"
}
}
],
"meta": {}
}
HTTP Request
POST /api/4/employee_invitations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[employee_invitations]=employee_id |
include |
string List of comma seperated relationships to sideload. ?include=employee |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][email] |
string Employee's email address. |
data[attributes][employee_id] |
uuid The employee that is invited. |
data[attributes][firstname] |
string First name of the employee. |
data[attributes][id] |
uuid Specify employee ID to re-send invitation. |
data[attributes][lastname] |
string Last name of the employee. |
data[attributes][permissions] |
array[string] Zero or more from: reports, products, settings, security_settings, account, exports, cancel_orders, revert_orders, delete_invoices, make_invoice_revisions, override_rental_period. |
Includes
This request accepts the following includes:
employee
Inventory breakdowns
Fetch quantitative information about product inventory compared to the current time, broken down by:
- Location
- Product
- Type
- Mutation date(s)
Useful for
- Examining what the current inventory looks, and will look, like for products
- Performing an inventory count (total in stock vs. out with a customer)
Relationships
| Name | Description |
|---|---|
location |
Location requiredThe Location to which this breakdown record applies. |
product |
Product requiredThe Product whose availability this breakdown record describes. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
downtime_count |
integer The amount of items that are in downtime for product and location. |
from |
datetime When the amount of items will be available (only for status expected). |
id |
uuid readonlyPrimary key. |
inventory_breakdown_type |
string One of regular or temporary. |
location_id |
uuid readonlyThe Location to which this breakdown record applies. |
product_id |
uuid readonlyThe Product whose availability this breakdown record describes. |
started |
integer The amount of items that are started for product and location. Only rendered when applicable. |
status |
string One of expected, in_stock, or expired. |
stock_count |
integer The total amount of stock for product and location. |
till |
datetime When the amount of items will become unavailable (only for type temporary and/or status expired). |
List inventory breakdowns
How to fetch a breakdown of all items in stock:
curl --get 'https://example.booqable.com/api/4/inventory_breakdowns'
--header 'content-type: application/json'
--data-urlencode 'filter[product_group_id]=fc4bfed6-545d-4ffe-8b66-81e8dbde9d4e'
--data-urlencode 'filter[status]=in_stock'
--data-urlencode 'stats[inventory_breakdown_type][]=sum'
--data-urlencode 'stats[started][]=sum'
--data-urlencode 'stats[status][]=sum'
--data-urlencode 'stats[stock_count][]=sum'
A 200 status response looks like this:
{
"data": [
{
"id": "4d112455-70ef-47ab-8e13-317982d7a785",
"type": "inventory_breakdowns",
"attributes": {
"stock_count": 100,
"started": 50,
"downtime_count": 0,
"status": "in_stock",
"inventory_breakdown_type": "regular",
"location_id": "93539676-0eec-4298-8221-d37c766028c4",
"product_id": "856d3a4c-8f1c-4392-8837-b1033d097162"
},
"relationships": {}
},
{
"id": "cfc74ef9-ca0f-4337-8020-dc4ecddbde48",
"type": "inventory_breakdowns",
"attributes": {
"till": "2020-08-15T02:26:01.000000+00:00",
"stock_count": 5,
"started": 0,
"downtime_count": 0,
"status": "in_stock",
"inventory_breakdown_type": "temporary",
"location_id": "93539676-0eec-4298-8221-d37c766028c4",
"product_id": "856d3a4c-8f1c-4392-8837-b1033d097162"
},
"relationships": {}
}
],
"meta": {
"stats": {
"inventory_breakdown_type": {
"sum": {
"regular": 100,
"temporary": 5
}
},
"started": {
"sum": 50
},
"status": {
"sum": {
"in_stock": 105,
"expected": 17,
"expired": 22
}
},
"stock_count": {
"sum": 105
}
}
}
}
How to fetch a breakdown of all expected items:
curl --get 'https://example.booqable.com/api/4/inventory_breakdowns'
--header 'content-type: application/json'
--data-urlencode 'filter[product_group_id]=3142a9c7-40c2-4dff-8a3d-61aef93400cf'
--data-urlencode 'filter[status]=expected'
--data-urlencode 'stats[inventory_breakdown_type][]=sum'
--data-urlencode 'stats[started][]=sum'
--data-urlencode 'stats[status][]=sum'
--data-urlencode 'stats[stock_count][]=sum'
A 200 status response looks like this:
{
"data": [
{
"id": "d6f88a18-89e5-409d-84ae-8e3e2af10659",
"type": "inventory_breakdowns",
"attributes": {
"from": "2017-11-18T03:35:00.000000+00:00",
"stock_count": 12,
"downtime_count": 0,
"status": "expected",
"inventory_breakdown_type": "regular",
"location_id": "53f12674-6a2f-4878-804c-eb4dd3aa204f",
"product_id": "11b3f75f-518c-4e76-8979-2efbc4019818"
},
"relationships": {}
},
{
"id": "7f3caf33-119d-43b7-8bd5-8c7bd5de639a",
"type": "inventory_breakdowns",
"attributes": {
"from": "2017-11-18T03:35:00.000000+00:00",
"till": "2017-12-19T03:35:00.000000+00:00",
"stock_count": 5,
"downtime_count": 0,
"status": "expected",
"inventory_breakdown_type": "temporary",
"location_id": "53f12674-6a2f-4878-804c-eb4dd3aa204f",
"product_id": "11b3f75f-518c-4e76-8979-2efbc4019818"
},
"relationships": {}
}
],
"meta": {
"stats": {
"inventory_breakdown_type": {
"sum": {
"regular": 12,
"temporary": 5
}
},
"started": {
"sum": 0
},
"status": {
"sum": {
"in_stock": 105,
"expected": 17,
"expired": 22
}
},
"stock_count": {
"sum": 17
}
}
}
}
How to fetch a breakdown of all expired items:
curl --get 'https://example.booqable.com/api/4/inventory_breakdowns'
--header 'content-type: application/json'
--data-urlencode 'filter[product_group_id]=8d1d8d66-b01e-4300-83da-7418f5acaaea'
--data-urlencode 'filter[status]=expired'
--data-urlencode 'stats[inventory_breakdown_type][]=sum'
--data-urlencode 'stats[started][]=sum'
--data-urlencode 'stats[status][]=sum'
--data-urlencode 'stats[stock_count][]=sum'
A 200 status response looks like this:
{
"data": [
{
"id": "b5e5064e-831e-4883-8a71-2e612ddbb495",
"type": "inventory_breakdowns",
"attributes": {
"till": "2022-08-20T18:59:00.000000+00:00",
"stock_count": 22,
"downtime_count": 0,
"status": "expired",
"inventory_breakdown_type": "temporary",
"location_id": "8a5cbdf6-c713-419f-868e-14208fd6df91",
"product_id": "243a8fd8-a17c-4b5e-878c-3e0646778c26"
},
"relationships": {}
}
],
"meta": {
"stats": {
"inventory_breakdown_type": {
"sum": {
"regular": 0,
"temporary": 22
}
},
"started": {
"sum": 0
},
"status": {
"sum": {
"in_stock": 105,
"expected": 17,
"expired": 22
}
},
"stock_count": {
"sum": 22
}
}
}
}
HTTP Request
GET /api/4/inventory_breakdowns
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[inventory_breakdowns]=from,till,stock_count |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=location,product |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
inventory_breakdown_type |
string eq |
location_id |
uuid eq |
product_group_id |
uuid eq |
product_id |
uuid eq |
status |
string requiredeq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
inventory_breakdown_type |
array sum |
started |
array sum |
status |
array sum |
stock_count |
array sum, count |
total |
array count |
Includes
This request accepts the following includes:
location-
productphoto
Inventory levels
Inventory levels provide information on item availability. It describes availability, stock counts, and planned quantities for given items.
Relationships
| Name | Description |
|---|---|
item |
Item requiredThe item to return data for, this can be a single ID or an array of multiple IDs. |
location |
Location requiredThe location to filter on. |
order |
Order requiredThe order to filter on. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
cluster_available |
integer readonlyThe available quantity for the cluster the given location is part of. |
cluster_needed |
integer readonlyThe needed quantity for the cluster the given location is part of. This quantity does not contain what has already been returned for an order ( planned - stopped). |
cluster_plannable |
integer readonlyThe planned quantity for the cluster the given location is part of. |
cluster_planned |
integer readonlyThe planned quantity for the cluster the given location is part of. |
cluster_stock_count |
integer readonlyThe stock count for the cluster the given location is part of. |
id |
uuid readonlyPrimary key. |
item_id |
uuid readonlyThe item to return data for, this can be a single ID or an array of multiple IDs. |
location_available |
integer readonlyThe available quantity for the given location. |
location_id |
uuid readonlyThe location to filter on. |
location_needed |
integer readonlyThe needed quantity for the given location. This quantity does not contain what has already been returned for an order ( planned - stopped). |
location_plannable |
integer readonlyThe number of products that can be planned for the given location. |
location_planned |
integer readonlyThe planned quantity for the given location. |
location_stock_count |
integer readonlyThe quantity of stock present for the given the location. |
order_id |
uuid readonlyThe order to filter on. |
Fetch inventory levels for a product
How to fetch inventory levels for a product:
curl --get 'https://example.booqable.com/api/4/inventory_levels'
--header 'content-type: application/json'
--data-urlencode 'filter[from]=2022-01-01 09:00:00'
--data-urlencode 'filter[item_id]=d4ef30b8-8959-4262-8dcd-d90c23a4ee8a'
--data-urlencode 'filter[till]=2022-01-02 09:00:00'
A 200 status response looks like this:
{
"data": [
{
"id": "72684141-dea4-42b5-8c69-080d056a0e8c",
"type": "inventory_levels",
"attributes": {
"location_available": 0,
"location_stock_count": 0,
"location_plannable": 0,
"location_planned": 0,
"location_needed": 0,
"cluster_available": 0,
"cluster_stock_count": 0,
"cluster_plannable": 0,
"cluster_planned": 0,
"cluster_needed": 0,
"item_id": "d4ef30b8-8959-4262-8dcd-d90c23a4ee8a",
"location_id": "95c73381-5770-48e8-8a43-af7513a32ed9",
"order_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/inventory_levels
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[inventory_levels]=location_available,location_stock_count,location_plannable |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=item,location |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
from |
datetime requiredeq |
item_id |
uuid eq |
location_id |
uuid eq |
order_id |
uuid eq |
till |
datetime requiredeq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
itemlocation
Fetch inventory levels for a product for a specific location
How to fetch inventory levels for a product for a specific location:
curl --get 'https://example.booqable.com/api/4/inventory_levels'
--header 'content-type: application/json'
--data-urlencode 'filter[from]=2022-01-01 09:00:00'
--data-urlencode 'filter[item_id]=f13f0c48-b1bd-48ef-81be-94aba9cee2fc'
--data-urlencode 'filter[location_id]=fcf25ba2-1c63-4cf3-842b-be17908108c4'
--data-urlencode 'filter[till]=2022-01-02 09:00:00'
A 200 status response looks like this:
{
"data": [
{
"id": "7f66e4b6-37f8-4f22-8c62-e35634c5ebb5",
"type": "inventory_levels",
"attributes": {
"location_available": 0,
"location_stock_count": 0,
"location_plannable": 0,
"location_planned": 0,
"location_needed": 0,
"cluster_available": 0,
"cluster_stock_count": 0,
"cluster_plannable": 0,
"cluster_planned": 0,
"cluster_needed": 0,
"item_id": "f13f0c48-b1bd-48ef-81be-94aba9cee2fc",
"location_id": "fcf25ba2-1c63-4cf3-842b-be17908108c4",
"order_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/inventory_levels
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[inventory_levels]=location_available,location_stock_count,location_plannable |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=item,location |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
from |
datetime requiredeq |
item_id |
uuid eq |
location_id |
uuid eq |
order_id |
uuid eq |
till |
datetime requiredeq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
itemlocation
Invoice finalizations
Pro forma invoices are automatically generated and updated when changes
are made to an order. The InvoiceFinalizationResource resource allows
to request the finalization of the current pro forma invoice.
Further changes to the order will trigger a new pro forma invoice to be
generated with prorated changes.
Relationships
| Name | Description |
|---|---|
document |
Document requiredThe invoice that needs to be finalized. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
document_id |
uuid The invoice that needs to be finalized. |
id |
uuid readonlyPrimary key. |
Finalize invoice
Finalize a pro forma invoice:
curl --request POST
--url 'https://example.booqable.com/api/4/invoice_finalizations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "invoice_finalization",
"attributes": {
"document_id": "ef4f4bbd-55b2-4355-8436-74a4dde8fe55"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "797e55bb-b625-41fd-876a-c97b5ed135b0",
"type": "invoice_finalizations",
"attributes": {
"document_id": "ef4f4bbd-55b2-4355-8436-74a4dde8fe55"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/invoice_finalizations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[invoice_finalizations]=document_id |
include |
string List of comma seperated relationships to sideload. ?include=document |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][document_id] |
uuid The invoice that needs to be finalized. |
Includes
This request accepts the following includes:
-
document-
orderdocuments
properties
-
Invoice revisions
Revises the last finalized invoice for an order by combining it with the current pro forma invoice and creating a new finalized invoice.
Creating a revision requires that there is a finalized invoice, and that there is a pro forma invoice (i.e. changes must have been made to the order since the last finalized invoice).
Relationships
| Name | Description |
|---|---|
order |
Order requiredThe order for which the last invoice needs to be revised. |
revised_invoice |
Document requiredThe finalized invoice that was revised. |
revision_invoice |
Document requiredThe replacement invoice that was generated. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
id |
uuid readonlyPrimary key. |
order_id |
uuid The order for which the last invoice needs to be revised. |
revised_invoice_id |
uuid readonlyThe finalized invoice that was revised. |
revision_invoice_id |
uuid readonlyThe replacement invoice that was generated. |
Revise invoice
Revise a finalized invoice:
curl --request POST
--url 'https://example.booqable.com/api/4/invoice_revisions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "invoice_revisions",
"attributes": {
"order_id": "7b026e88-c408-4d9b-8ff7-4dc889f66f8b"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "75c7effe-1ae6-409a-8cb4-4003f6e2f901",
"type": "invoice_revisions",
"attributes": {
"order_id": "7b026e88-c408-4d9b-8ff7-4dc889f66f8b",
"revised_invoice_id": "5c7bff8c-1cec-4027-8049-2d29ac25ee0e",
"revision_invoice_id": "fcb6ea7b-1d93-482b-828e-ae3ab98226c0"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/invoice_revisions
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[invoice_revisions]=order_id,revised_invoice_id,revision_invoice_id |
include |
string List of comma seperated relationships to sideload. ?include=order,revised_invoice,revision_invoice |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][order_id] |
uuid The order for which the last invoice needs to be revised. |
Includes
This request accepts the following includes:
orderrevised_invoicerevision_invoice
Item prices
Allows you to calculate pricing for an item based on parameters.
You can calculate a price in a couple ways:
- Providing a
fromandtill, charge label and length will be derived from the dates provided - Providing a
charge_length
Relationships
| Name | Description |
|---|---|
item |
Item requiredRequired, the item or items to calculate price for. |
price_ruleset |
Price ruleset requiredThe advanced pricing rules that apply. |
price_structure |
Price structure requiredOptional price structure to use, if the item has a price structure associated with it that will be used by default. |
price_tile |
Price tile requiredThe price tile that was selected from the price structure. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
charge_label |
string readonlyLabel for the charge period. |
charge_length |
integer Length of charge period in seconds. |
from |
datetime Start of charge period. |
id |
uuid readonlyPrimary key. |
item_id |
uuid Required, the item or items to calculate price for. |
original_charge_label |
string readonlyLabel of charge period before charge rules are applied. |
original_charge_length |
integer readonlyLength of charge period before charge rules are applied. |
original_price_each_in_cents |
integer readonlyPrice per item before charge rules are applied. |
price_each_in_cents |
integer readonlyFinal price per item. |
price_rule_values |
hash readonlyWhat price rules were applied. |
price_ruleset_id |
uuid The advanced pricing rules that apply. |
price_structure_id |
uuid Optional price structure to use, if the item has a price structure associated with it that will be used by default. |
price_tile_id |
uuid readonlyThe price tile that was selected from the price structure. |
till |
datetime End of charge period. |
Calculate the price of products and/or bundles
Calculating price for a period:
curl --get 'https://example.booqable.com/api/4/item_prices'
--header 'content-type: application/json'
--data-urlencode 'filter[from]=2030-01-01 12:00:00 UTC'
--data-urlencode 'filter[item_id][]=6a8292cc-4002-4f8e-8da2-1e182dbacc08'
--data-urlencode 'filter[item_id][]=6ac6ad52-9587-4088-8fd8-af88a9295a8e'
--data-urlencode 'filter[till]=2030-01-14 12:00:00 UTC'
--data-urlencode 'include=item'
A 200 status response looks like this:
{
"data": [
{
"id": "7d3ef505-b175-4f03-8151-9d77c4e8d823",
"type": "item_prices",
"attributes": {
"item_id": "6a8292cc-4002-4f8e-8da2-1e182dbacc08",
"from": "2028-03-25T10:11:00.000000+00:00",
"till": "2028-04-07T10:11:00.000000+00:00",
"original_charge_length": 1123200,
"charge_length": 1123200,
"original_charge_label": "13 days",
"charge_label": "13 days",
"original_price_each_in_cents": 31200,
"price_each_in_cents": 31200,
"price_rule_values": null,
"price_structure_id": null,
"price_ruleset_id": null,
"price_tile_id": null
},
"relationships": {
"item": {
"data": {
"type": "products",
"id": "6a8292cc-4002-4f8e-8da2-1e182dbacc08"
}
}
}
},
{
"id": "1200d3ab-3efd-419e-8837-dbefde64a5c8",
"type": "item_prices",
"attributes": {
"item_id": "6ac6ad52-9587-4088-8fd8-af88a9295a8e",
"from": "2028-03-25T10:11:00.000000+00:00",
"till": "2028-04-07T10:11:00.000000+00:00",
"original_charge_length": 1123200,
"charge_length": 1123200,
"original_charge_label": "13 days",
"charge_label": "13 days",
"original_price_each_in_cents": 74100,
"price_each_in_cents": 74100,
"price_rule_values": null,
"price_structure_id": null,
"price_ruleset_id": null,
"price_tile_id": null
},
"relationships": {
"item": {
"data": {
"type": "products",
"id": "6ac6ad52-9587-4088-8fd8-af88a9295a8e"
}
}
}
}
],
"included": [
{
"id": "6a8292cc-4002-4f8e-8da2-1e182dbacc08",
"type": "products",
"attributes": {
"created_at": "2024-02-02T07:38:00.000000+00:00",
"updated_at": "2024-02-02T07:38:00.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "Product 1000010",
"group_name": "Product 1000010",
"slug": "product-1000010",
"sku": "PRODUCT 1000012",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 100,
"price_type": "simple",
"price_period": "hour",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [],
"product_group_id": "248e9f40-8ade-4dd1-8bbc-2049129c3146"
},
"relationships": {}
},
{
"id": "6ac6ad52-9587-4088-8fd8-af88a9295a8e",
"type": "products",
"attributes": {
"created_at": "2024-02-02T07:38:00.000000+00:00",
"updated_at": "2024-02-02T07:38:00.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "Product 1000011",
"group_name": "Product 1000011",
"slug": "product-1000011",
"sku": "PRODUCT 1000013",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 5700,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [],
"product_group_id": "88d23396-b095-4122-82f6-992f846605af"
},
"relationships": {}
}
],
"meta": {}
}
Calculating price charge length:
curl --get 'https://example.booqable.com/api/4/item_prices'
--header 'content-type: application/json'
--data-urlencode 'filter[charge_length]=36000'
--data-urlencode 'filter[item_id]=f513ca7d-c6b0-432c-84fa-1b60f29a4cfa'
--data-urlencode 'include=item'
A 200 status response looks like this:
{
"data": [
{
"id": "f010a8cf-b5d9-4ff8-853c-307a79289325",
"type": "item_prices",
"attributes": {
"item_id": "f513ca7d-c6b0-432c-84fa-1b60f29a4cfa",
"from": null,
"till": null,
"original_charge_length": 36000,
"charge_length": 36000,
"original_charge_label": "10 hours",
"charge_label": "10 hours",
"original_price_each_in_cents": null,
"price_each_in_cents": 1000,
"price_rule_values": null,
"price_structure_id": null,
"price_ruleset_id": null,
"price_tile_id": null
},
"relationships": {
"item": {
"data": {
"type": "products",
"id": "f513ca7d-c6b0-432c-84fa-1b60f29a4cfa"
}
}
}
}
],
"included": [
{
"id": "f513ca7d-c6b0-432c-84fa-1b60f29a4cfa",
"type": "products",
"attributes": {
"created_at": "2023-06-13T08:19:05.000000+00:00",
"updated_at": "2023-06-13T08:19:05.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "Product 1000012",
"group_name": "Product 1000012",
"slug": "product-1000012",
"sku": "PRODUCT 1000014",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 100,
"price_type": "simple",
"price_period": "hour",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [],
"product_group_id": "c9235b08-a9f1-43e5-8ae8-cf204f682b53"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/item_prices
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[item_prices]=item_id,from,till |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=price_tile,price_structure,item |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
charge_length |
integer eq |
from |
datetime eq |
item_id |
uuid eq |
original_charge_length |
integer eq |
price_ruleset_id |
uuid eq |
price_structure_id |
uuid eq |
till |
datetime eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
itemprice_structureprice_tile
Items
The Item resource makes it possible to fetch (and search!) the following resources in a single request:
The description of the relationships and attributes of these resources can be found in their respective sections
List items
How to fetch a list of items:
curl --get 'https://example.booqable.com/api/4/items'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "d7759df8-1381-4df4-832c-9ddde2efce9a",
"type": "bundles",
"attributes": {
"created_at": "2027-05-05T08:14:00.000000+00:00",
"updated_at": "2027-05-05T08:14:00.000000+00:00",
"archived": false,
"archived_at": null,
"type": "bundles",
"name": "iPad Bundle",
"slug": "ipad-bundle",
"product_type": "bundle",
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [
"tablets",
"apple"
],
"photo_id": null,
"tax_category_id": null
},
"relationships": {}
},
{
"id": "c721f29a-0574-4af4-8fb2-ab4715f97998",
"type": "product_groups",
"attributes": {
"created_at": "2027-05-05T08:14:00.000000+00:00",
"updated_at": "2027-05-05T08:14:00.000000+00:00",
"type": "product_groups",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": null,
"slug": "ipad-pro",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "trackable",
"trackable": true,
"has_variations": false,
"variation": false,
"extra_information": "Charging cable and case included",
"photo_url": null,
"description": "The Apple iPad Pro (2021) 12.9 inches 128GB Space Gray is one of the most powerful and fastest tablets of this moment thanks to the new M1 chip. This chip ensures that demanding apps from Adobe or 3D games run smoothly",
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 1995,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 10000,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [
"tablets",
"apple"
],
"properties": {},
"photo_id": null,
"tax_category_id": "58186c7a-50b1-4584-881d-3054f4f5790d",
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": true,
"shortage_limit": 3,
"variation_fields": [],
"flat_fee_price_in_cents": 1995,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
},
{
"id": "89e8b2cd-7a7e-47b2-8571-1379ad6e21f1",
"type": "products",
"attributes": {
"created_at": "2027-05-05T08:14:00.000000+00:00",
"updated_at": "2027-05-05T08:14:00.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": "iPad Pro",
"slug": "ipad-pro",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "trackable",
"trackable": true,
"has_variations": false,
"variation": false,
"extra_information": "Charging cable and case included",
"photo_url": null,
"description": "The Apple iPad Pro (2021) 12.9 inches 128GB Space Gray is one of the most powerful and fastest tablets of this moment thanks to the new M1 chip. This chip ensures that demanding apps from Adobe or 3D games run smoothly",
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 1995,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 10000,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [
"tablets",
"apple"
],
"properties": {},
"photo_id": null,
"tax_category_id": "58186c7a-50b1-4584-881d-3054f4f5790d",
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": true,
"shortage_limit": 3,
"variation_values": [],
"product_group_id": "c721f29a-0574-4af4-8fb2-ab4715f97998"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[items]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=barcode,bundle_items,inventory_levels |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
base_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_after |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_before |
integer eq, not_eq, gt, gte, lt, lte |
collection_id |
uuid eq, not_eq |
conditions |
hash eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
group_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
has_variations |
boolean eq |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
price_period |
enum eq |
price_ruleset_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_type |
enum eq |
product_group_id |
uuid eq |
product_type |
enum eq |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
show_in_store |
boolean eq |
sku |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_category_id |
uuid eq |
taxable |
boolean eq |
trackable |
boolean eq |
tracking_type |
enum eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
variation |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
base_price_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
discountable |
array count |
price_period |
array count |
price_type |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
tracking_type |
array count |
Includes
This request accepts the following includes:
barcodebundle_itemsinventory_levelsphotoproperties
Search items
Use advanced search to make logical filter groups with and/or operators.
How to search for items:
curl --request POST
--url 'https://example.booqable.com/api/4/items/search'
--header 'content-type: application/json'
--data '{
"fields": {
"items": "id"
},
"filter": {
"conditions": {
"operator": "or",
"attributes": [
{
"operator": "and",
"attributes": [
{
"discountable": true
},
{
"taxable": true
}
]
},
{
"operator": "and",
"attributes": [
{
"show_in_store": true
},
{
"taxable": true
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "569def8b-7636-476f-8a1f-be15feb8defb"
},
{
"id": "90acfcac-e08a-40a8-8189-769b49dd2197"
},
{
"id": "000f9d47-49fe-4495-8d4c-39a2187d00f2"
},
{
"id": "b71ea42f-340e-4143-81c1-ca6a463d21ac"
},
{
"id": "f5b4b96e-515c-42f6-8214-95013aa9cdc4"
}
]
}
HTTP Request
POST /api/4/items/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[items]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=barcode,bundle_items,inventory_levels |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
base_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_after |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_before |
integer eq, not_eq, gt, gte, lt, lte |
collection_id |
uuid eq, not_eq |
conditions |
hash eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
group_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
has_variations |
boolean eq |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
price_period |
enum eq |
price_ruleset_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_type |
enum eq |
product_group_id |
uuid eq |
product_type |
enum eq |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
show_in_store |
boolean eq |
sku |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_category_id |
uuid eq |
taxable |
boolean eq |
trackable |
boolean eq |
tracking_type |
enum eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
variation |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
base_price_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
discountable |
array count |
price_period |
array count |
price_type |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
tracking_type |
array count |
Includes
This request accepts the following includes:
barcodebundle_itemsinventory_levelsphotoproperties
Fetch an item
How to fetch an item:
curl --get 'https://example.booqable.com/api/4/items/15cd96a9-f5ba-4fb6-8ca3-16b2581f1385'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "15cd96a9-f5ba-4fb6-8ca3-16b2581f1385",
"type": "product_groups",
"attributes": {
"created_at": "2015-07-22T22:42:00.000000+00:00",
"updated_at": "2015-07-22T22:42:00.000000+00:00",
"type": "product_groups",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": null,
"slug": "ipad-pro",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "trackable",
"trackable": true,
"has_variations": false,
"variation": false,
"extra_information": "Charging cable and case included",
"photo_url": null,
"description": "The Apple iPad Pro (2021) 12.9 inches 128GB Space Gray is one of the most powerful and fastest tablets of this moment thanks to the new M1 chip. This chip ensures that demanding apps from Adobe or 3D games run smoothly",
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 1995,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 10000,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [
"tablets",
"apple"
],
"properties": {},
"photo_id": null,
"tax_category_id": "2a2acff0-f752-4c88-85d7-23015f91caff",
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": true,
"shortage_limit": 3,
"variation_fields": [],
"flat_fee_price_in_cents": 1995,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[items]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=barcode,bundle_items,inventory_levels |
Includes
This request accepts the following includes:
barcodebundle_itemsinventory_levelsphotoproperties
Lines
Lines make up the individual elements of an order, document, or cart. They contain information about pricing, planning, or markup.
Lines can only be created for orders. On invoices, lines are automatically generated based on price changes of the order. For quotes and contracts, lines are generated through the Document resource.
Kinds of Lines
Planning lines Lines that have an associated Planning. These lines cannot be created through the Line resource but are created by submitting a
book_*action to OrderFulfillments. Updating or destroying a line linked to a planning will also destroy the planning.Custom lines Lines created through the resource that don't have a planning associated with them. Can be of one of type
chargeorsection.
Types of Lines
chargeRegular charge line which contains price information. These lines are automatically generated for each Planning, but they can also be added manually for one-off charges.sectionBehaves as a visual section on orders and documents. Sections allow users to organize orders as they like and do not affect order totals.deposit_chargeA deposit charge line generated by a deposit hold action. This line is always calculated from a price including taxes.prorationA line representing a proration. These lines only appear on invoices and can't be updated or destroyed by the resource; they are automatically synced.refundThis line was created due to a refund.delivery_rateThis line represents delivery charges based on carrier rates. These are created for delivery orders.legacy_migrationProration bundled as one line. These lines appear on invoices that were made before Booqable was able to sync invoices automatically.delivery_rateWhen orderfulfillment_typeisdelivery, this line is created to represent the delivery rate information (price, label, etc).
Line Price Calculation
Line prices are calculated based on several factors:
- For planning lines, the price is based on the item's price settings, the rental period, and any applicable price rules.
- The
charge_length(in seconds) can differ from the actual rental period due to price rule adjustments. - The
price_rule_valuesattribute contains a detailed breakdown of how price rules affected the final price. - Setting
charge_lengthtonullwill trigger recalculation based on order period and rules. - For custom charge lines, the price is manually set and not affected by period changes.
Ownership Model
Lines have an owner polymorphic relationship which can point to either:
- An Order (for order lines)
- A Document (for invoice, quote, and contract lines)
Lines also have a direct order_id which always points to the related order, even when
the line is owned by a document. This makes it easier to retrieve the order context.
Bundles
Nested lines contain information about individual items in a Bundle; for these lines, the quantity and price information cannot be updated directly but should be updated through the parent line instead.
Sorting Lines
# example of lines when using bundles
(position=1) Product A
(position=2) Product B
(position=3) Bundle
(position=1) Product C
(position=2) Product D
When using Bundles, the line.position attribute is not unique. Special care needs
to be taken to sort all lines correctly.
When booking a bundle:
- The parent line is assigned a
positionbased on the other lines already on the order. - The child lines are assigned a
positionbased on how the bundle is configured.
To correctly sort all lines so they appear as they do within Booqable:
- Child lines should be sorted relative to their siblings of the same parent.
To do this, child lines need to be grouped by the
parent_line_idattribute.
Relationships
| Name | Description |
|---|---|
item |
Item optionalThe Product or Bundle that was booked, when this Line has an associated Planning. |
nested_lines |
Lines hasmanyWhen item is a Bundle, then there is a nested line that corresponds for each BundleItem. |
order |
Order requiredThe Order this Line belongs to. |
owner |
Order, Document requiredThe resource this Line belongs to. Either the Order directly, or a Document. |
parent_line |
Line optionalWhen present, this Line is part of a Bundle and corresponds to a BundleItem. Inverse of the nested_lines relation. |
planning |
Planning optionalThe Planning for which this Line was created that contains the logistical information related to this Line. |
price_structure |
Price structure optionalThe PriceStructure used to calculate the price. |
price_tile |
Price tile optionalThe PriceTile that was selected to calculate the price. |
tax_category |
Tax category optionalTaxCategory applied to this Line. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether line is archived. |
archived_at |
datetime readonly nullableWhen the line was archived. |
charge_label |
string nullableCharge label. |
charge_length |
integer nullableThe charge length in seconds. It can be different than the time planned. Setting charge_length to null will trigger recalculation of the price based on order period and price rules. To recalculate prices for the entire order, use OrderPriceRecalculation. |
confirm_shortage |
boolean writeonlyWhether to confirm a shortage when updating quantity on a line. When a line has an associated planning and you increase the quantity, the planning's quantity will also be increased. If this results in a shortage (requested quantity exceeds available inventory), the update will fail with a shortage error. Setting this to true confirms that you want to proceed with the update despite the shortage. This is useful when you know you'll be able to fulfill the order through other means, such as acquiring additional inventory before the rental period.Overriding shortage warnings is only possible when the ProductGroup is configured to allow shortage. |
created_at |
datetime readonlyWhen the resource was created. |
discountable |
boolean Whether line is discountable. |
extra_information |
string nullableExtra information about the line. |
id |
uuid readonlyPrimary key. |
item_id |
uuid readonly nullableThe Product or Bundle that was booked, when this Line has an associated Planning. |
line_type |
enum readonly-after-createType of line. Can be one of: - charge: Regular charge line for rental items or custom charges - section: Visual section for organizing lines (no financial impact) - deposit_charge: Deposit charge line - proration: Partial charge for partial rental periods (invoices only) - refund: Refund line with negative amount - delivery_rate: Delivery charge based on carrier rates - legacy_migration: Legacy proration lineOnly charge and section line types can be created through the resource. Other types are created by the system.One of: section, deposit_charge, proration, charge, legacy_migration, delivery_rate. |
order_id |
uuid readonlyThe Order this Line belongs to. |
original_charge_label |
string nullableThe original charge label of the product (without price rule adjustments). |
original_charge_length |
integer readonlyThe original charge length of the product (without price rule adjustments). |
original_price_each_in_cents |
integer readonlyThe original price of the product (without price rule adjustments). |
owner_id |
uuid readonly-after-createThe resource this Line belongs to. Either the Order directly, or a Document. |
owner_type |
enum readonly-after-createThe resource type of the owner. One of: orders, documents. |
parent_line_id |
uuid readonly nullableWhen present, this Line is part of a Bundle and corresponds to a BundleItem. Inverse of the nested_lines relation. |
planning_id |
uuid readonly nullableThe Planning for which this Line was created that contains the logistical information related to this Line. |
position |
integer nullableThe ordering of lines on an order or document. See this section to understand how to sort when using bundles. |
price_each_in_cents |
integer Price of each line. |
price_in_cents |
integer readonlyPrice of each line x quantity, based on the tax setting of the company (inclusive vs. exclusive). |
price_rule_values |
hash readonly nullableBreakdown of applied price rules. This is a complex structure that contains detailed information about how price rules affected the final price calculation, including: - Which price rules were applied - What time periods they applied to - How they affected the pricing - The resulting price adjustments This data is particularly useful for understanding why a line has its current price and for providing transparent pricing explanations to customers. |
price_structure_id |
uuid readonly nullableThe PriceStructure used to calculate the price. |
price_tile_id |
uuid nullableThe PriceTile that was selected to calculate the price. |
quantity |
integer The quantity to calculate with. When updating quantity of a line with an associated planning, the planning also gets updated, which may lead to a shortage error. |
relevant |
boolean readonlyWhen false this line should not be shown to users. It is only needed for calculation of prorations. |
tax_category_id |
uuid nullableTaxCategory applied to this Line. |
taxable |
boolean Whether line is taxable. |
title |
string nullableTitle of the line. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List lines
How to fetch a list of lines:
curl --get 'https://example.booqable.com/api/4/lines'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "ae4a88a4-9a7a-4caf-811c-27f85ebe167f",
"type": "lines",
"attributes": {
"created_at": "2023-08-08T15:06:00.000000+00:00",
"updated_at": "2023-08-08T15:06:00.000000+00:00",
"archived": false,
"archived_at": null,
"title": "Macbook Pro",
"extra_information": "Comes with a mouse",
"quantity": 1,
"original_price_each_in_cents": 72500,
"original_charge_length": null,
"original_charge_label": null,
"price_each_in_cents": 80250,
"price_in_cents": 80250,
"position": 1,
"charge_label": "29 days",
"charge_length": 2505600,
"price_rule_values": {
"charge": {
"from": "1977-12-29T05:39:00.000000+00:00",
"till": "1978-01-27T05:39:00.000000+00:00",
"adjustments": [
{
"name": "Pickup day"
},
{
"name": "Return day"
}
]
},
"price": [
{
"name": "High-Season",
"charge_length": 1339200,
"multiplier": "0.2",
"price_in_cents": 7750,
"adjustments": [
{
"from": "1978-01-11T17:39:00.000000+00:00",
"till": "1978-01-27T05:39:00.000000+00:00",
"charge_length": 1339200,
"charge_label": "372 hours",
"price_in_cents": 7750
}
],
"stacked": false
}
]
},
"discountable": true,
"taxable": true,
"line_type": "charge",
"relevant": true,
"order_id": "db61e960-dc39-40c0-8967-af01657ec0d0",
"item_id": "dfb7e7c5-6c92-44de-8fd3-beb9fe5dee6e",
"tax_category_id": "4c97f8cd-9bbf-4048-819a-f50d8b7bff7b",
"price_structure_id": null,
"price_tile_id": null,
"planning_id": "9cf6e39a-f13f-46c3-89db-f1fd269f1bfd",
"parent_line_id": null,
"owner_id": "db61e960-dc39-40c0-8967-af01657ec0d0",
"owner_type": "orders"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/lines
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[lines]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=order,owner,tax_category |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
discountable |
boolean eq |
id |
uuid eq, not_eq |
item_id |
uuid eq, not_eq |
line_type |
enum eq |
order_id |
uuid eq |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
parent_line_id |
uuid eq, not_eq |
planning_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_tile_id |
uuid eq, not_eq |
quantity |
integer eq, not_eq, gt, gte, lt, lte |
relevant |
boolean eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
orderowner-
planning-
itemphoto
-
tax_category
Fetch a line
How to fetch a line:
curl --get 'https://example.booqable.com/api/4/lines/b4c827b6-c766-42d8-831c-87f9a610b8fa'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "b4c827b6-c766-42d8-831c-87f9a610b8fa",
"type": "lines",
"attributes": {
"created_at": "2022-10-10T21:41:02.000000+00:00",
"updated_at": "2022-10-10T21:41:02.000000+00:00",
"archived": false,
"archived_at": null,
"title": "Macbook Pro",
"extra_information": "Comes with a mouse",
"quantity": 1,
"original_price_each_in_cents": 72500,
"original_charge_length": null,
"original_charge_label": null,
"price_each_in_cents": 80250,
"price_in_cents": 80250,
"position": 1,
"charge_label": "29 days",
"charge_length": 2505600,
"price_rule_values": {
"charge": {
"from": "1977-03-02T12:14:02.000000+00:00",
"till": "1977-03-31T12:14:02.000000+00:00",
"adjustments": [
{
"name": "Pickup day"
},
{
"name": "Return day"
}
]
},
"price": [
{
"name": "High-Season",
"charge_length": 1339200,
"multiplier": "0.2",
"price_in_cents": 7750,
"adjustments": [
{
"from": "1977-03-16T00:14:02.000000+00:00",
"till": "1977-03-31T12:14:02.000000+00:00",
"charge_length": 1339200,
"charge_label": "372 hours",
"price_in_cents": 7750
}
],
"stacked": false
}
]
},
"discountable": true,
"taxable": true,
"line_type": "charge",
"relevant": true,
"order_id": "a206e703-8fe7-4045-826a-36b938ea47d4",
"item_id": "d4996c4d-efe0-4972-8124-37812a882d50",
"tax_category_id": "28930517-53d0-4346-865d-0988b23e5ea6",
"price_structure_id": null,
"price_tile_id": null,
"planning_id": "01296b4b-a633-4808-8993-91a287f01c9b",
"parent_line_id": null,
"owner_id": "a206e703-8fe7-4045-826a-36b938ea47d4",
"owner_type": "orders"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/lines/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[lines]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=order,owner,tax_category |
Includes
This request accepts the following includes:
-
nested_linesplanning
-
ordertax_values
-
ownertax_values
parent_line-
planning-
itemphoto
-
tax_category
Create a line
Lines created through this endpoint, so-called custom lines, can only have the type charge or section.
Custom charge lines enable you to add charges not (directly) connected to a product to an order.
Sections allow to add some organization to orders.
Order totals are automatically re-calculated after the creation of a new line and an invoice sync will be triggered if changes are relevant.
How to create a line:
curl --request POST
--url 'https://example.booqable.com/api/4/lines'
--header 'content-type: application/json'
--data '{
"data": {
"type": "lines",
"attributes": {
"owner_id": "e429675c-a2e8-46c3-88f4-316a4bdd2e5d",
"owner_type": "orders",
"price_each_in_cents": 1000
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "69903b58-4d14-4bcb-8490-66c5df3ee4df",
"type": "lines",
"attributes": {
"created_at": "2017-01-15T11:15:00.000000+00:00",
"updated_at": "2017-01-15T11:15:00.000000+00:00",
"archived": false,
"archived_at": null,
"title": null,
"extra_information": null,
"quantity": 1,
"original_price_each_in_cents": null,
"original_charge_length": null,
"original_charge_label": null,
"price_each_in_cents": 1000,
"price_in_cents": 1000,
"position": 1,
"charge_label": null,
"charge_length": null,
"price_rule_values": null,
"discountable": true,
"taxable": true,
"line_type": "charge",
"relevant": true,
"order_id": "e429675c-a2e8-46c3-88f4-316a4bdd2e5d",
"item_id": null,
"tax_category_id": null,
"price_structure_id": null,
"price_tile_id": null,
"planning_id": null,
"parent_line_id": null,
"owner_id": "e429675c-a2e8-46c3-88f4-316a4bdd2e5d",
"owner_type": "orders"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/lines
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[lines]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=order,owner,tax_category |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][charge_label] |
string Charge label. |
data[attributes][charge_length] |
integer The charge length in seconds. It can be different than the time planned. Setting charge_length to null will trigger recalculation of the price based on order period and price rules. To recalculate prices for the entire order, use OrderPriceRecalculation. |
data[attributes][confirm_shortage] |
boolean Whether to confirm a shortage when updating quantity on a line. When a line has an associated planning and you increase the quantity, the planning's quantity will also be increased. If this results in a shortage (requested quantity exceeds available inventory), the update will fail with a shortage error. Setting this to true confirms that you want to proceed with the update despite the shortage. This is useful when you know you'll be able to fulfill the order through other means, such as acquiring additional inventory before the rental period.Overriding shortage warnings is only possible when the ProductGroup is configured to allow shortage. |
data[attributes][discountable] |
boolean Whether line is discountable. |
data[attributes][extra_information] |
string Extra information about the line. |
data[attributes][line_type] |
enum Type of line. Can be one of: - charge: Regular charge line for rental items or custom charges - section: Visual section for organizing lines (no financial impact) - deposit_charge: Deposit charge line - proration: Partial charge for partial rental periods (invoices only) - refund: Refund line with negative amount - delivery_rate: Delivery charge based on carrier rates - legacy_migration: Legacy proration lineOnly charge and section line types can be created through the resource. Other types are created by the system.One of: section, deposit_charge, proration, charge, legacy_migration, delivery_rate. |
data[attributes][original_charge_label] |
string The original charge label of the product (without price rule adjustments). |
data[attributes][owner_id] |
uuid The resource this Line belongs to. Either the Order directly, or a Document. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: orders, documents. |
data[attributes][position] |
integer The ordering of lines on an order or document. See this section to understand how to sort when using bundles. |
data[attributes][price_each_in_cents] |
integer Price of each line. |
data[attributes][price_tile_id] |
uuid The PriceTile that was selected to calculate the price. |
data[attributes][quantity] |
integer The quantity to calculate with. When updating quantity of a line with an associated planning, the planning also gets updated, which may lead to a shortage error. |
data[attributes][tax_category_id] |
uuid TaxCategory applied to this Line. |
data[attributes][taxable] |
boolean Whether line is taxable. |
data[attributes][title] |
string Title of the line. |
Includes
This request accepts the following includes:
-
nested_linesplanning
-
ordertax_values
-
ownertax_values
parent_line-
planning-
itemphoto
-
tax_category
Update a line
Change information, pricing, or increase the quantity of a line. Note that when updating the quantity of a line associated with a planning, the quantity of the planning will also be updated, which may result in a shortage error.
Order totals are automatically re-calculated after updating a line and an invoice sync will be triggered if changes are relevant.
How to update a line:
curl --request PUT
--url 'https://example.booqable.com/api/4/lines/fc2e8815-5ad2-4d0b-8a28-777a6b57d933'
--header 'content-type: application/json'
--data '{
"data": {
"id": "fc2e8815-5ad2-4d0b-8a28-777a6b57d933",
"type": "lines",
"attributes": {
"price_each_in_cents": 1000
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "fc2e8815-5ad2-4d0b-8a28-777a6b57d933",
"type": "lines",
"attributes": {
"created_at": "2027-03-06T23:03:01.000000+00:00",
"updated_at": "2027-03-06T23:03:01.000000+00:00",
"archived": false,
"archived_at": null,
"title": "Macbook Pro",
"extra_information": "Comes with a mouse",
"quantity": 1,
"original_price_each_in_cents": 72500,
"original_charge_length": null,
"original_charge_label": null,
"price_each_in_cents": 1000,
"price_in_cents": 1000,
"position": 1,
"charge_label": "29 days",
"charge_length": 2505600,
"price_rule_values": null,
"discountable": true,
"taxable": true,
"line_type": "charge",
"relevant": true,
"order_id": "33b62e2b-8553-4919-8719-0de973ab048e",
"item_id": "6079761a-dac1-4eb8-88a9-d5c43040d760",
"tax_category_id": "87821aa9-fd93-4b69-8e67-01c17fd816d6",
"price_structure_id": null,
"price_tile_id": null,
"planning_id": "cdd8227f-b71f-41ae-83a9-4e47d0c1a2b6",
"parent_line_id": null,
"owner_id": "33b62e2b-8553-4919-8719-0de973ab048e",
"owner_type": "orders"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/lines/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[lines]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=order,owner,tax_category |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][charge_label] |
string Charge label. |
data[attributes][charge_length] |
integer The charge length in seconds. It can be different than the time planned. Setting charge_length to null will trigger recalculation of the price based on order period and price rules. To recalculate prices for the entire order, use OrderPriceRecalculation. |
data[attributes][confirm_shortage] |
boolean Whether to confirm a shortage when updating quantity on a line. When a line has an associated planning and you increase the quantity, the planning's quantity will also be increased. If this results in a shortage (requested quantity exceeds available inventory), the update will fail with a shortage error. Setting this to true confirms that you want to proceed with the update despite the shortage. This is useful when you know you'll be able to fulfill the order through other means, such as acquiring additional inventory before the rental period.Overriding shortage warnings is only possible when the ProductGroup is configured to allow shortage. |
data[attributes][discountable] |
boolean Whether line is discountable. |
data[attributes][extra_information] |
string Extra information about the line. |
data[attributes][line_type] |
enum Type of line. Can be one of: - charge: Regular charge line for rental items or custom charges - section: Visual section for organizing lines (no financial impact) - deposit_charge: Deposit charge line - proration: Partial charge for partial rental periods (invoices only) - refund: Refund line with negative amount - delivery_rate: Delivery charge based on carrier rates - legacy_migration: Legacy proration lineOnly charge and section line types can be created through the resource. Other types are created by the system.One of: section, deposit_charge, proration, charge, legacy_migration, delivery_rate. |
data[attributes][original_charge_label] |
string The original charge label of the product (without price rule adjustments). |
data[attributes][owner_id] |
uuid The resource this Line belongs to. Either the Order directly, or a Document. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: orders, documents. |
data[attributes][position] |
integer The ordering of lines on an order or document. See this section to understand how to sort when using bundles. |
data[attributes][price_each_in_cents] |
integer Price of each line. |
data[attributes][price_tile_id] |
uuid The PriceTile that was selected to calculate the price. |
data[attributes][quantity] |
integer The quantity to calculate with. When updating quantity of a line with an associated planning, the planning also gets updated, which may lead to a shortage error. |
data[attributes][tax_category_id] |
uuid TaxCategory applied to this Line. |
data[attributes][taxable] |
boolean Whether line is taxable. |
data[attributes][title] |
string Title of the line. |
Includes
This request accepts the following includes:
-
nested_linesplanning
-
ordertax_values
-
ownertax_values
parent_line-
planning-
itemphoto
-
tax_category
Archive a line
How to delete a line:
curl --request DELETE
--url 'https://example.booqable.com/api/4/lines/4ad8090f-0878-4fb1-8e5e-2dea58fd8ef6'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "4ad8090f-0878-4fb1-8e5e-2dea58fd8ef6",
"type": "lines",
"attributes": {
"created_at": "2018-12-01T08:17:02.000000+00:00",
"updated_at": "2018-12-01T08:17:02.000000+00:00",
"archived": true,
"archived_at": "2018-12-01T08:17:02.000000+00:00",
"title": "Macbook Pro",
"extra_information": "Comes with a mouse",
"quantity": 1,
"original_price_each_in_cents": 72500,
"original_charge_length": null,
"original_charge_label": null,
"price_each_in_cents": 80250,
"price_in_cents": 80250,
"position": 1,
"charge_label": "29 days",
"charge_length": 2505600,
"price_rule_values": {
"charge": {
"from": "1973-04-22T22:50:02.000000+00:00",
"till": "1973-05-21T22:50:02.000000+00:00",
"adjustments": [
{
"name": "Pickup day"
},
{
"name": "Return day"
}
]
},
"price": [
{
"name": "High-Season",
"charge_length": 1339200,
"multiplier": "0.2",
"price_in_cents": 7750,
"adjustments": [
{
"from": "1973-05-06T10:50:02.000000+00:00",
"till": "1973-05-21T22:50:02.000000+00:00",
"charge_length": 1339200,
"charge_label": "372 hours",
"price_in_cents": 7750
}
],
"stacked": false
}
]
},
"discountable": true,
"taxable": true,
"line_type": "charge",
"relevant": true,
"order_id": "78b392bd-6db0-4fb7-8eee-93b320eb554e",
"item_id": "914563ce-67a8-43f6-8d3a-bcd5476a2575",
"tax_category_id": "1f32b2e1-dd8e-4304-8d68-68f0077e18b7",
"price_structure_id": null,
"price_tile_id": null,
"planning_id": "372352f3-b88b-4b67-80e6-e89b803c2fb4",
"parent_line_id": null,
"owner_id": "78b392bd-6db0-4fb7-8eee-93b320eb554e",
"owner_type": "orders"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/lines/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[lines]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=order,owner,tax_category |
Includes
This request accepts the following includes:
-
ordertax_values
-
ownertax_values
parent_linetax_category
Line charge suggestions
Line charge suggestions are potential charge lengths for a Line.
For simple products, the suggested charge lengths and prices are based on the
configured price_type and price_period of the ProductGroup.
For products using price structures (tiered pricing), the charge lengths and prices are basically the same as the configured PriceTiles.
For Bundles, pricing depends on the chosen Product variations.
Therefore this API requires a line_id, so that the returned price
can be calculated based on the chosen Product variations.
Relationships
| Name | Description |
|---|---|
line |
Line requiredThe Line that this suggestion is for. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
charge_label |
string readonlyThe label corresponding to the charge_length. If the Item has tiered pricing, this is the label of a configured PriceTile. |
charge_length |
integer readonlyThe suggested charge length in seconds. |
created_at |
datetime readonlyThe date and time when this suggestion was calculated. |
id |
uuid readonlyPrimary key. |
line_id |
uuid The Line that this suggestion is for. |
price_each_in_cents |
integer readonlyThe price that would be charged if the suggested charge length is used. |
List suggestions
How to fetch a list of charge suggestions for a line:
curl --get 'https://example.booqable.com/api/4/line_charge_suggestions'
--header 'content-type: application/json'
--data-urlencode 'filter[line_id]=2ecfa77f-fcf3-4edb-8617-a39730f6055e'
A 200 status response looks like this:
{
"data": [
{
"id": "6d73c915-59f9-44e5-83d6-77e5946e26fe",
"type": "line_charge_suggestions",
"attributes": {
"created_at": "2018-04-25T04:08:00.000000+00:00",
"charge_length": 86400,
"charge_label": "very short",
"price_each_in_cents": 100,
"line_id": "2ecfa77f-fcf3-4edb-8617-a39730f6055e"
},
"relationships": {}
},
{
"id": "f6e84b69-8152-486c-8a10-b45e9e90a5fd",
"type": "line_charge_suggestions",
"attributes": {
"created_at": "2018-04-25T04:08:00.000000+00:00",
"charge_length": 172800,
"charge_label": "short",
"price_each_in_cents": 200,
"line_id": "2ecfa77f-fcf3-4edb-8617-a39730f6055e"
},
"relationships": {}
},
{
"id": "8bf65eb0-f809-4b4d-87a0-769800945375",
"type": "line_charge_suggestions",
"attributes": {
"created_at": "2018-04-25T04:08:00.000000+00:00",
"charge_length": 259200,
"charge_label": "longer",
"price_each_in_cents": 250,
"line_id": "2ecfa77f-fcf3-4edb-8617-a39730f6055e"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/line_charge_suggestions
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[line_charge_suggestions]=created_at,charge_length,charge_label |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=line |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
charge_label |
string eq |
charge_length |
integer eq |
created_at |
datetime eq |
line_id |
uuid requiredeq |
price_each_in_cents |
integer eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
line
Locations
A location is a place (like a store) where customers pick up and return orders or a warehouse that only stocks inventory.
Relationships
| Name | Description |
|---|---|
carriers |
App carriers hasmanyThe carriers that can do delivery from this location. |
clusters |
Clusters hasmanyThe clusters this location is part of. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
address_line_1 |
string First address line. |
address_line_2 |
string Second address line. |
archived |
boolean readonlyWhether location is archived. |
archived_at |
datetime readonly nullableWhen the location was archived. |
city |
string Address city. |
cluster_ids |
array Clusters this location belongs to. |
code |
string Code used to identify the location. |
confirm_has_orders |
boolean writeonlyA flag to confirm an address update when the location has orders. |
country |
string Address country. |
created_at |
datetime readonlyWhen the resource was created. |
delivery_enabled |
boolean readonlyWhether the location supports delivery. |
fulfillment_capabilities |
array[string] readonlyThe fulfillment process options available from this location. At least one from: delivery, pickup. |
id |
uuid readonlyPrimary key. |
location_type |
enum Determines if the location can be seen in the online store. One of: rental, internal. |
main_address |
hash A hash with the address fields. Use it when fetching a location. See address property type for more information. |
main_address_attributes |
hash writeonlyA hash with the address fields. Use it when creating or updating a location. See address property type for more information. |
name |
string Name of the location. |
pickup_enabled |
boolean Whether the location supports pickup. |
region |
string Address region. |
updated_at |
datetime readonlyWhen the resource was last updated. |
zipcode |
string Address ZIP code. |
List locations
How to fetch locations:
curl --get 'https://example.booqable.com/api/4/locations'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "f6399631-79bf-4a64-8deb-169a36a274ae",
"type": "locations",
"attributes": {
"created_at": "2020-04-09T06:23:00.000000+00:00",
"updated_at": "2020-04-09T06:23:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Warehouse",
"code": "LOC1000032",
"location_type": "rental",
"address_line_1": "Blokhuisplein 40",
"address_line_2": "Department II",
"zipcode": "8911LJ",
"city": "Leeuwarden",
"region": "Friesland",
"country": "Netherlands",
"cluster_ids": [],
"pickup_enabled": true,
"delivery_enabled": false,
"fulfillment_capabilities": [
"pickup"
],
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuisplein 40",
"address2": "Department II",
"city": "Leeuwarden",
"region": "Friesland",
"zipcode": "8911LJ",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "1",
"longitude": "1",
"value": "Blokhuisplein 40\nDepartment II\n8911LJ Leeuwarden Friesland\nNetherlands"
}
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/locations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[locations]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=clusters,carriers |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
cluster_id |
uuid eq, not_eq |
code |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
fulfillment_capabilities |
array[string] any_of |
id |
uuid eq, not_eq |
location_type |
enum eq |
main_address |
hash eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
carriersclusters
Fetch a location
How to fetch a single location:
curl --get 'https://example.booqable.com/api/4/locations/954bf312-7f80-4c5a-8547-8626943b877c'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "954bf312-7f80-4c5a-8547-8626943b877c",
"type": "locations",
"attributes": {
"created_at": "2023-01-14T17:38:02.000000+00:00",
"updated_at": "2023-01-14T17:38:02.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Warehouse",
"code": "LOC1000033",
"location_type": "rental",
"address_line_1": "Blokhuisplein 40",
"address_line_2": "Department II",
"zipcode": "8911LJ",
"city": "Leeuwarden",
"region": "Friesland",
"country": "Netherlands",
"cluster_ids": [],
"pickup_enabled": true,
"delivery_enabled": false,
"fulfillment_capabilities": [
"pickup"
],
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuisplein 40",
"address2": "Department II",
"city": "Leeuwarden",
"region": "Friesland",
"zipcode": "8911LJ",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "1",
"longitude": "1",
"value": "Blokhuisplein 40\nDepartment II\n8911LJ Leeuwarden Friesland\nNetherlands"
}
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/locations/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[locations]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=clusters,carriers |
Includes
This request accepts the following includes:
carriersclusters
Create a location
How to create a location and assign it to a cluster:
curl --request POST
--url 'https://example.booqable.com/api/4/locations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "locations",
"attributes": {
"name": "Store",
"code": "STR",
"location_type": "rental",
"address_line_1": "Blokhuisplein 40",
"address_line_2": "Department II",
"zipcode": "8911LJ",
"city": "Leeuwarden",
"region": "Friesland",
"country": "Netherlands",
"cluster_ids": [
"b6b7e9ad-3c95-41ca-897a-d2bd4270d323"
]
}
},
"include": "clusters"
}'
A 201 status response looks like this:
{
"data": {
"id": "d47e53d6-ce3a-42c6-8ca9-98dd789e4cde",
"type": "locations",
"attributes": {
"created_at": "2015-05-03T23:16:00.000000+00:00",
"updated_at": "2015-05-03T23:16:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Store",
"code": "STR",
"location_type": "rental",
"address_line_1": "Blokhuisplein 40",
"address_line_2": "Department II",
"zipcode": "8911LJ",
"city": "Leeuwarden",
"region": "Friesland",
"country": "Netherlands",
"cluster_ids": [
"b6b7e9ad-3c95-41ca-897a-d2bd4270d323"
],
"pickup_enabled": true,
"delivery_enabled": false,
"fulfillment_capabilities": [
"pickup"
],
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuisplein 40",
"address2": "Department II",
"city": "Leeuwarden",
"region": "Friesland",
"zipcode": "8911LJ",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "1",
"longitude": "1",
"value": "Blokhuisplein 40\nDepartment II\n8911LJ Leeuwarden Friesland\nNetherlands"
}
},
"relationships": {
"clusters": {
"data": [
{
"type": "clusters",
"id": "b6b7e9ad-3c95-41ca-897a-d2bd4270d323"
}
]
}
}
},
"included": [
{
"id": "b6b7e9ad-3c95-41ca-897a-d2bd4270d323",
"type": "clusters",
"attributes": {
"created_at": "2015-05-03T23:16:00.000000+00:00",
"updated_at": "2015-05-03T23:16:00.000000+00:00",
"name": "North",
"location_ids": [
"d47e53d6-ce3a-42c6-8ca9-98dd789e4cde"
]
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/locations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[locations]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=clusters,carriers |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address_line_1] |
string First address line. |
data[attributes][address_line_2] |
string Second address line. |
data[attributes][city] |
string Address city. |
data[attributes][cluster_ids][] |
array Clusters this location belongs to. |
data[attributes][code] |
string Code used to identify the location. |
data[attributes][confirm_has_orders] |
boolean A flag to confirm an address update when the location has orders. |
data[attributes][country] |
string Address country. |
data[attributes][location_type] |
enum Determines if the location can be seen in the online store. One of: rental, internal. |
data[attributes][main_address] |
hash A hash with the address fields. Use it when fetching a location. See address property type for more information. |
data[attributes][main_address_attributes] |
hash A hash with the address fields. Use it when creating or updating a location. See address property type for more information. |
data[attributes][name] |
string Name of the location. |
data[attributes][pickup_enabled] |
boolean Whether the location supports pickup. |
data[attributes][region] |
string Address region. |
data[attributes][zipcode] |
string Address ZIP code. |
Includes
This request accepts the following includes:
carriersclusters
Update a location
Note that disassociating clusters may result in a shortage error.
How to update a location and assign it to multiple clusters:
curl --request PUT
--url 'https://example.booqable.com/api/4/locations/620301be-6eb5-4f1f-8fdd-7d1539cbcfc2'
--header 'content-type: application/json'
--data '{
"data": {
"id": "620301be-6eb5-4f1f-8fdd-7d1539cbcfc2",
"type": "locations",
"attributes": {
"name": "Old warehouse",
"cluster_ids": [
"e9b03933-5297-4354-875b-0d0a14bc83fb",
"23d4e910-0ff5-4c29-8d01-1aa63a1b974d"
]
}
},
"include": "clusters"
}'
A 200 status response looks like this:
{
"data": {
"id": "620301be-6eb5-4f1f-8fdd-7d1539cbcfc2",
"type": "locations",
"attributes": {
"created_at": "2019-10-04T21:59:02.000000+00:00",
"updated_at": "2019-10-04T21:59:02.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Old warehouse",
"code": "LOC1000035",
"location_type": "rental",
"address_line_1": "Blokhuisplein 40",
"address_line_2": "Department II",
"zipcode": "8911LJ",
"city": "Leeuwarden",
"region": "Friesland",
"country": "Netherlands",
"cluster_ids": [
"e9b03933-5297-4354-875b-0d0a14bc83fb",
"23d4e910-0ff5-4c29-8d01-1aa63a1b974d"
],
"pickup_enabled": true,
"delivery_enabled": false,
"fulfillment_capabilities": [
"pickup"
],
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuisplein 40",
"address2": "Department II",
"city": "Leeuwarden",
"region": "Friesland",
"zipcode": "8911LJ",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "1",
"longitude": "1",
"value": "Blokhuisplein 40\nDepartment II\n8911LJ Leeuwarden Friesland\nNetherlands"
}
},
"relationships": {
"clusters": {
"data": [
{
"type": "clusters",
"id": "e9b03933-5297-4354-875b-0d0a14bc83fb"
},
{
"type": "clusters",
"id": "23d4e910-0ff5-4c29-8d01-1aa63a1b974d"
}
]
}
}
},
"included": [
{
"id": "e9b03933-5297-4354-875b-0d0a14bc83fb",
"type": "clusters",
"attributes": {
"created_at": "2019-10-04T21:59:02.000000+00:00",
"updated_at": "2019-10-04T21:59:02.000000+00:00",
"name": "North",
"location_ids": [
"620301be-6eb5-4f1f-8fdd-7d1539cbcfc2"
]
},
"relationships": {}
},
{
"id": "23d4e910-0ff5-4c29-8d01-1aa63a1b974d",
"type": "clusters",
"attributes": {
"created_at": "2019-10-04T21:59:02.000000+00:00",
"updated_at": "2019-10-04T21:59:02.000000+00:00",
"name": "Central",
"location_ids": [
"620301be-6eb5-4f1f-8fdd-7d1539cbcfc2"
]
},
"relationships": {}
}
],
"meta": {}
}
Disassociating cluster resulting in shortage error:
curl --request PUT
--url 'https://example.booqable.com/api/4/locations/f224137a-3275-466e-8502-c1e66ea8444c'
--header 'content-type: application/json'
--data '{
"data": {
"id": "f224137a-3275-466e-8502-c1e66ea8444c",
"type": "locations",
"attributes": {
"name": "Old warehouse",
"cluster_ids": []
}
},
"include": "clusters"
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "shortage",
"status": "422",
"title": "Shortage",
"detail": "This will create shortage for running or future orders",
"meta": {
"warning": [],
"blocking": [
{
"reason": "shortage",
"shortage": 2,
"item_id": "f198dfab-a4ce-4068-84c3-b706d007c30d",
"mutation": 0,
"order_ids": [
"42d674fe-c02a-4b91-834c-92069417c0ed"
],
"location_id": "f224137a-3275-466e-8502-c1e66ea8444c",
"available": -2,
"plannable": -2,
"stock_count": 0,
"planned": 2,
"needed": 2,
"cluster_available": -2,
"cluster_plannable": -2,
"cluster_stock_count": 0,
"cluster_planned": 2,
"cluster_needed": 2
}
]
}
}
]
}
HTTP Request
PUT /api/4/locations/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[locations]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=clusters,carriers |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address_line_1] |
string First address line. |
data[attributes][address_line_2] |
string Second address line. |
data[attributes][city] |
string Address city. |
data[attributes][cluster_ids][] |
array Clusters this location belongs to. |
data[attributes][code] |
string Code used to identify the location. |
data[attributes][confirm_has_orders] |
boolean A flag to confirm an address update when the location has orders. |
data[attributes][country] |
string Address country. |
data[attributes][location_type] |
enum Determines if the location can be seen in the online store. One of: rental, internal. |
data[attributes][main_address] |
hash A hash with the address fields. Use it when fetching a location. See address property type for more information. |
data[attributes][main_address_attributes] |
hash A hash with the address fields. Use it when creating or updating a location. See address property type for more information. |
data[attributes][name] |
string Name of the location. |
data[attributes][pickup_enabled] |
boolean Whether the location supports pickup. |
data[attributes][region] |
string Address region. |
data[attributes][zipcode] |
string Address ZIP code. |
Includes
This request accepts the following includes:
carriersclusters
Archive a location
To archive a location make sure that:
- There is no active stock at the location
- There are no running or future orders for this location
- This is not the last active location
How to archive a location:
curl --request DELETE
--url 'https://example.booqable.com/api/4/locations/3f258b5c-005d-4808-81c2-954da48df0cb'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "3f258b5c-005d-4808-81c2-954da48df0cb",
"type": "locations",
"attributes": {
"created_at": "2020-03-03T14:31:02.000000+00:00",
"updated_at": "2020-03-03T14:31:02.000000+00:00",
"archived": true,
"archived_at": "2020-03-03T14:31:02.000000+00:00",
"name": "Warehouse",
"code": "LOC1000038",
"location_type": "rental",
"address_line_1": "Blokhuisplein 40",
"address_line_2": "Department II",
"zipcode": "8911LJ",
"city": "Leeuwarden",
"region": "Friesland",
"country": "Netherlands",
"cluster_ids": [],
"pickup_enabled": true,
"delivery_enabled": false,
"fulfillment_capabilities": [
"pickup"
],
"main_address": {
"meets_validation_requirements": false,
"first_name": null,
"last_name": null,
"address1": "Blokhuisplein 40",
"address2": "Department II",
"city": "Leeuwarden",
"region": "Friesland",
"zipcode": "8911LJ",
"country": "Netherlands",
"country_id": null,
"province_id": null,
"latitude": "1",
"longitude": "1",
"value": "Blokhuisplein 40\nDepartment II\n8911LJ Leeuwarden Friesland\nNetherlands"
}
},
"relationships": {}
},
"meta": {}
}
Failure due to a future order:
curl --request DELETE
--url 'https://example.booqable.com/api/4/locations/0b51712b-bd56-43d4-8e58-08b818262a12'
--header 'content-type: application/json'
A 422 status response looks like this:
{
"errors": [
{
"code": "location_has_orders",
"status": "422",
"title": "Location has orders",
"detail": "This location has running or future orders",
"meta": {
"order_ids": [
"0d8a3816-e267-4375-8cd1-cf1340de963d"
]
}
}
]
}
Failure due to active stock at location:
curl --request DELETE
--url 'https://example.booqable.com/api/4/locations/d5edee8a-8801-48cd-8087-14b1d659a294'
--header 'content-type: application/json'
A 422 status response looks like this:
{
"errors": [
{
"code": "location_has_stock",
"status": "422",
"title": "Location has stock",
"detail": "This location has active stock",
"meta": {
"item_ids": [
"3e62df61-af47-4c9b-8279-1dfb80db2936"
]
}
}
]
}
HTTP Request
DELETE /api/4/locations/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[locations]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Notes
Allows you to leave notes attached to other resources.
Relationships
| Name | Description |
|---|---|
employee |
Employee requiredThe Employee who created this note. |
owner |
Customer, Product group, Product, Stock item, Bundle, Order, Document, User requiredThe resource this note is about. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
body |
string The content of the note. |
created_at |
datetime readonlyWhen the resource was created. |
employee_id |
uuid readonlyThe Employee who created this note. |
id |
uuid readonlyPrimary key. |
owner_id |
uuid readonly-after-createThe resource this note is about. |
owner_type |
enum readonly-after-createThe resource type of the owner. One of: customers, product_groups, products, stock_items, bundles, orders, documents, users. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List notes
How to fetch a list of notes:
curl --get 'https://example.booqable.com/api/4/notes'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "308f95f9-2661-4894-8d17-b4cf8fd661d2",
"type": "notes",
"attributes": {
"created_at": "2022-10-23T23:24:01.000000+00:00",
"updated_at": "2022-10-23T23:24:01.000000+00:00",
"body": "Agreed to give this customer a 20% discount on the next order",
"employee_id": "6e9725e6-9cd5-4743-8021-afe1b305c3f2",
"owner_id": "4ef2de9b-a05c-49a2-8d8d-3690843a43a8",
"owner_type": "customers"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/notes
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[notes]=created_at,updated_at,body |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=employee,owner |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
employee_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
employeeowner
Fetch a note
How to fetch a note:
curl --get 'https://example.booqable.com/api/4/notes/629a61d1-1b50-41fd-867f-b7882b29d2f6'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "629a61d1-1b50-41fd-867f-b7882b29d2f6",
"type": "notes",
"attributes": {
"created_at": "2028-07-04T15:39:01.000000+00:00",
"updated_at": "2028-07-04T15:39:01.000000+00:00",
"body": "Agreed to give this customer a 20% discount on the next order",
"employee_id": "8e17846d-a01b-4743-8d9b-a1ef2884c506",
"owner_id": "e1d2d7e1-879d-4864-8f80-b42ba923ab58",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/notes/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[notes]=created_at,updated_at,body |
include |
string List of comma seperated relationships to sideload. ?include=employee,owner |
Includes
This request accepts the following includes:
employeeowner
Create a note
How to create a note:
curl --request POST
--url 'https://example.booqable.com/api/4/notes'
--header 'content-type: application/json'
--data '{
"data": {
"type": "notes",
"attributes": {
"body": "Agreed to give this customer a 20% discount on the next order",
"owner_id": "1a7b6819-6c11-4eee-892a-9d87bee21d50",
"owner_type": "customers"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "40684345-0cb8-4a59-8dea-51468dffb879",
"type": "notes",
"attributes": {
"created_at": "2020-07-03T13:01:01.000000+00:00",
"updated_at": "2020-07-03T13:01:01.000000+00:00",
"body": "Agreed to give this customer a 20% discount on the next order",
"employee_id": "1eb997c6-a419-482c-8414-606eef3b8f04",
"owner_id": "1a7b6819-6c11-4eee-892a-9d87bee21d50",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/notes
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[notes]=created_at,updated_at,body |
include |
string List of comma seperated relationships to sideload. ?include=employee,owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][body] |
string The content of the note. |
data[attributes][owner_id] |
uuid The resource this note is about. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: customers, product_groups, products, stock_items, bundles, orders, documents, users. |
Includes
This request accepts the following includes:
employeeowner
Delete a note
How to delete a note:
curl --request DELETE
--url 'https://example.booqable.com/api/4/notes/32ad49c4-5673-460c-84fd-a5852a0e4d35'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "32ad49c4-5673-460c-84fd-a5852a0e4d35",
"type": "notes",
"attributes": {
"created_at": "2023-07-14T18:36:01.000000+00:00",
"updated_at": "2023-07-14T18:36:01.000000+00:00",
"body": "Agreed to give this customer a 20% discount on the next order",
"employee_id": "654e2ccf-f66b-4cd2-85d2-c446291c11a9",
"owner_id": "45351704-f8df-4523-8ff0-d5d2b77ecaa4",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/notes/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[notes]=created_at,updated_at,body |
include |
string List of comma seperated relationships to sideload. ?include=employee,owner |
Includes
This request accepts the following includes:
employeeowner
Orders
Orders are the heart of every rental operation. They hold configuration and information about:
- The customer
When assigning a customer to an order, the order will inherit the tax region and deposit from the customer. - Pricing and taxes
- Deposits
- Rental period and location
Changing these can lead to shortage, and the update will be blocked by a warning or error. A shortage warning can be confirmed by setting theconfirm_shortageattribute totrue. - Shortages
- Payment status
Statuses
newMeans the order is new, and invisible to anyone except the employee who created it.draftDoes not influence availability.reservedItems on the order will be reserved and not available for other orders.startedMeans that the rental has started. In most cases this means items are out with a customer.stoppedItems are available for other rentals again.canceledThe order is canceled. Items will be available for other rentals.archivedThe order won't show up in default search results.
To book products on an order, use the OrderFulfillment API to
submit book_product, book_stock_items, and book_bundle actions.
Products can be booked on an Order in any status except for canceled and archived.
A stopped order will transition back to started when additional products are booked.
Status Transitions and Workflow
Orders typically follow this workflow:
new→draftthrough OrderStatusTransitiondraft→reservedthrough OrderStatusTransitionreserved→started(pickup/delivery) through OrderFulfillmentstarted→stopped(return/completion) through OrderFulfillmentstopped→archivedthrough OrderStatusTransition
Booking products usually happens when an order is in the new or draft state,
but technically booking is possible in any state except for canceled and archived. When booking
additional products on a reserved, started or stopped order, the products are immediately reserved.
When booking products on a stopped order, the order reverts to the started state.
The draft and reserved states can be skipped.
An order can go from new to started directly when products or stock items are picked up.
Shortage Handling
There are two types of shortage indicators:
- shortage: Indicates there's a shortage anywhere in the system
- location_shortage: Indicates there's a shortage specifically at the pickup location
When updating an order causes a shortage, you'll receive an error response with details about the shortage. To confirm and proceed despite the shortage, include confirm_shortage: true in your update request.
Fulfillment Types
Orders can have different fulfillment types that define how items are provided to customers:
- pickup: Customer collects items from a location
- delivery: Items are delivered to the customer
The fulfillment type affects address requirements, delivery costs, and order processing.
Payment Statuses
The payment_status field indicates the current payment state:
- paid: All order amounts have been paid
- partially_paid: Some payments have been made but the full amount is not yet paid
- overpaid: More has been paid than required
- payment_due: Payment is still required
- process_deposit: A deposit needs to be processed
Deposit Handling
Deposits can be calculated and applied in different ways:
- none: No deposit is required
- percentage: Deposit is a percentage of the item prices
- percentage_total: Deposit is a percentage of the total order amount
- fixed: Deposit is a fixed amount
The deposit_value field determines the percentage or fixed amount, and various deposit-related fields track payment and refund status.
Setting Delivery and Billing Addresses
Delivery and billing addresses are stored as Properties of type address that belong to the order.
The delivery_address and billing_address attributes are read-only and display formatted address strings
for easy display in templates and interfaces.
To set addresses, you have two main approaches:
Method 1: Reference Existing Address Properties
If you already have address properties (e.g., saved to a customer), reference them directly:
{
"data": {
"type": "orders",
"attributes": {
"customer_id": "customer-uuid-here",
"fulfillment_type": "delivery",
"delivery_address_property_id": "address-property-uuid-here",
"billing_address_property_id": "billing-address-property-uuid-here",
"starts_at": "2025-01-01T10:00:00Z",
"stops_at": "2025-01-03T10:00:00Z"
}
}
}
This approach is recommended when reusing existing addresses and provides full control over address validation.
Method 2: Create Addresses Inline
Create address properties as part of the order using properties_attributes. This is convenient for one-off orders:
{
"data": {
"type": "orders",
"attributes": {
"customer_id": "customer-uuid-here",
"fulfillment_type": "delivery",
"starts_at": "2025-01-01T10:00:00Z",
"stops_at": "2025-01-03T10:00:00Z",
"properties_attributes": [
{
"identifier": "delivery_address",
"name": "Delivery Address",
"property_type": "address",
"address1": "123 Main Street",
"address2": "Apt 4B",
"city": "Springfield",
"region": "IL",
"zipcode": "62701",
"country": "United States"
},
{
"identifier": "billing_address",
"name": "Billing Address",
"property_type": "address",
"address1": "456 Business Ave",
"city": "Springfield",
"region": "IL",
"zipcode": "62702",
"country": "United States"
}
]
}
}
}
Automatic Linking: When you create address properties with identifier set to delivery_address or billing_address,
the order automatically links to them via delivery_address_property_id and billing_address_property_id.
Required fields for address properties:
- identifier: Must be delivery_address or billing_address for automatic linking
- name: Descriptive name for the address
- property_type: Must be set to address
- address1: Primary street address
- city: City name
- zipcode: Postal code
- country: Country name (or country_id for precision)
Optional but recommended:
- region: State/province (or province_id for precision)
- address2: Secondary address line (apartment, suite, etc.)
Address validation requirements vary by country. For international orders, consider using country_id and province_id
instead of string values for more reliable address handling. See the Properties documentation for complete field details.
Relationships
| Name | Description |
|---|---|
barcode |
Barcode optionalThe QR code automatically generated for this Order. |
coupon |
Coupon optionalThe Coupon added to this Order. |
customer |
Customer optionalThe Customer this Order is for. |
documents |
Documents hasmanyDocuments (quotes, contracts, invoices) related to this order. |
lines |
Lines hasmanyAll the Lines of this Order. There is an automatically generated line for every Planning. In addition there can be manually added lines for custom charges, deposit holds and sections. |
notes |
Notes hasmanyNotes about this Order. |
order_delivery_rate |
Order delivery rate optionalInformation about the cost of delivery for this Order. |
payments |
Payments hasmanyPayments (charges, authorizations, refunds) related to this order. |
plannings |
Plannings hasmanyThe Plannings for this Order, containing the booked quantities and current status for all Products on this Order. |
properties |
Properties hasmanyCustom but structured data added to this Order. Both Properties linked to DefaultProperties, and one-off Properties can be added to orders. Properties of Orders can be updated in bulk by writing to the properties_attributes attribute. |
start_location |
Location requiredThe Location where the customer will pick up the items. |
stock_item_plannings |
Stock item plannings hasmanyThe StockItemPlannings planned on this Order, and their current status. |
stop_location |
Location requiredThe Location where the customer will return the items. When the clusters feature is in use, the stop location needs to be in the same cluster as the start location. |
tax_region |
Tax region optionalTaxRegion applied to this Order. |
tax_values |
Tax values hasmanyThe taxes calculated for this order. There is one TaxValue for each applicable TaxRate. |
transfers |
Transfers hasmanyTransfers that have been generated to solve shortages on this order. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
amount_in_cents |
integer readonlyThe rental amount excluding taxes. |
amount_paid_in_cents |
integer readonlyThe portion of the rental amount that has been paid. |
amount_to_be_paid_in_cents |
integer readonlyThe portion of the rental amount that still needs to be paid. |
billing_address_property_id |
uuid The UUID of the address Property to use as the billing address. The property must be of type address and should belong either to the order or to the customer.See Setting Delivery and Billing Addresses for details on how to set addresses. |
confirm_shortage |
boolean writeonlyWhen set to true, this confirms a shortage warning during an update operation. Use this parameter when you receive a shortage warning but want to proceed with the update despite the shortage. Overriding shortage is only possible when the affected ProductGroup is configured to allow shortage. |
coupon_discount_in_cents |
integer readonlyCoupon discount (incl. or excl. taxes based on tax_strategy). |
coupon_id |
uuid nullableThe Coupon added to this Order. |
created_at |
datetime readonlyWhen the resource was created. |
customer_id |
uuid nullableThe Customer this Order is for. |
delivery_address |
string Read-only. A formatted string representation of the delivery address. This attribute cannot be written to directly. To set the delivery address, use either delivery_address_property_id to reference an existing address Property, or use properties_attributes to create the address inline. See Setting Delivery and Billing Addresses for detailed examples. |
delivery_address_property_id |
uuid The UUID of the address Property to use as the delivery address. Required when fulfillment_type is delivery. The property must be of type address and should belong either to the order or to the customer.See Setting Delivery and Billing Addresses for details on how to set addresses. |
deposit_held_in_cents |
integer readonlyAmount of deposit held. |
deposit_in_cents |
integer readonlyDeposit. |
deposit_paid_in_cents |
integer readonlyHow much of the deposit is paid. |
deposit_refunded_in_cents |
integer readonlyHow much of the deposit is refunded. |
deposit_to_be_paid_in_cents |
integer readonlyThe portion of the deposit that still needs to be paid. |
deposit_to_refund_in_cents |
integer readonlyAmount of deposit (still) to be refunded. |
deposit_type |
enum nullableHow deposit is calculated. One of: none, percentage_total, percentage, fixed. |
deposit_value |
float The value to use for deposit_type. |
discount_in_cents |
integer readonlyDiscount (incl. or excl. taxes based on tax_strategy). |
discount_percentage |
float readonlyThe discount percentage applied to this order. May update if order amount changes and type is fixed. |
discount_type |
enum Type of discount. One of: percentage, fixed. |
discount_value |
float writeonlyThe value to use for discount_type. |
entirely_started |
boolean readonlyWhether all items on the order are started. |
entirely_stopped |
boolean readonlyWhether all items on the order are stopped. |
fulfillment_type |
enum Indicates the process used to fulfill this order. Values can be pickup (customer collects items from a location) or delivery (items are delivered to the customer's address). This affects which address fields are required and whether delivery charges apply.One of: pickup, delivery. |
grand_total_in_cents |
integer readonlyTotal excl. taxes (excl. deposit). |
grand_total_with_tax_in_cents |
integer readonlyAmount incl. taxes (excl. deposit). |
has_signed_contract |
boolean readonlyWhether the order has a signed contract. |
id |
uuid readonlyPrimary key. |
item_count |
integer readonlyThe number of items on the order. |
location_shortage |
boolean readonlyWhether there is a shortage on the pickup location. This is true when the requested items are not available at the specific start_location selected for the order, even if they might be available at other locations in the same cluster. |
number |
integer readonlyThe unique order number. |
order_delivery_rate_attributes |
hash writeonlyAssign this attribute to create/update the order delivery rate as subresource of order in a single request. |
order_delivery_rate_id |
uuid nullableThe id of the order delivery rate. |
override_period_restrictions |
boolean Force free period selection when there are restrictions enabled for the order period picker. |
paid_in_cents |
integer readonlyHow much was paid. |
payment_status |
enum readonlyIndicates next step to take with respect to payment for this order. Values include paid (fully paid), partially_paid (some payments made), overpaid (more paid than required), payment_due (balance still due), or process_deposit (deposit needs processing).One of: paid, partially_paid, overpaid, payment_due, process_deposit. |
price_in_cents |
integer readonlySubtotal excl. taxes (excl. deposit). |
properties |
hash readonlyA hash containing all property identifiers and values (include the properties relation if you need more detailed information). Properties of orders can be updated in bulk by writing to the properties_attributes attribute. |
properties_attributes |
array writeonlyCreate or update Properties as part of the order in a single request. This is useful for setting custom fields and addresses inline without creating separate property resources first. To set a delivery or billing address, include a property with identifier set to delivery_address or billing_address and provide the address fields (address1, city, zipcode, country, etc.). The order will automatically link to this address via delivery_address_property_id or billing_address_property_id.See Setting Delivery and Billing Addresses for complete examples and Properties for all available address fields. |
shortage |
boolean readonlyWhether there is a shortage for this order. This indicates that the requested quantity of one or more items cannot be fulfilled during the specified rental period. |
start_location_id |
uuid The Location where the customer will pick up the items. |
starts_at |
datetime nullableWhen the items on the order become unavailable. This is the date/time when the rental period officially begins. Changing this date may result in shortages if the items are no longer available for the new time period. |
status |
enum readonly-after-createSimplified status of the order. An order can be in a mixed state (i.e. partially started or stopped). The statuses attribute contains the full list of current statuses, and status_counts specifies how many items are in each state.This attribute can only be written when creating an order. Accepted statuses are new, draft and reserved.One of: new, draft, reserved, started, stopped, archived, canceled. |
status_counts |
hash readonlyAn object containing the status counts of planned products, like { "draft": 0, "reserved": 2, "started": 5, "stopped": 10 }. |
statuses |
array readonlyStatus(es) of planned products. |
stop_location_id |
uuid The Location where the customer will return the items. When the clusters feature is in use, the stop location needs to be in the same cluster as the start location. |
stops_at |
datetime nullableWhen the items on the order become available again. This is the date/time when the rental period officially ends, and inventory becomes available for other orders after this point. Extending this date may result in shortages if the items are already booked for other orders. |
tag_list |
array[string] Case insensitive tag list. |
tax_in_cents |
integer readonlyTotal tax. |
tax_region_id |
uuid nullableTaxRegion applied to this Order. |
to_be_paid_in_cents |
integer readonlyAmount that (still) has to be paid. |
total_discount_in_cents |
integer readonlyTotal discount (incl. or excl. taxes based on tax_strategy). |
total_in_cents |
integer readonlyThe total order amount including rental amount, taxes, and deposit. |
total_paid_in_cents |
integer readonlyThe total amount that has been paid for this order. |
total_to_be_paid_in_cents |
integer readonlyThe total amount remaining to be paid for this order. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List orders
How to fetch a list of orders:
curl --get 'https://example.booqable.com/api/4/orders'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "3475c076-354c-4870-8326-459b23381f95",
"type": "orders",
"attributes": {
"created_at": "2015-02-09T00:29:01.000000+00:00",
"updated_at": "2015-02-09T00:29:01.000000+00:00",
"number": 1,
"status": "reserved",
"statuses": [
"reserved"
],
"status_counts": {
"draft": 0,
"new": 0,
"reserved": 1,
"started": 0,
"stopped": 0
},
"starts_at": "1969-07-01T03:00:01.000000+00:00",
"stops_at": "1969-07-31T03:00:01.000000+00:00",
"deposit_type": "percentage",
"deposit_value": 10.0,
"entirely_started": false,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "payment_due",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 1,
"tag_list": [
"webshop"
],
"properties": {
"delivery_address": null,
"billing_address": null
},
"amount_in_cents": 87392,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": 87392,
"deposit_in_cents": 10000,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": 10000,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 97392,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 97392,
"total_discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"discount_in_cents": 8025,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"paid_in_cents": 0,
"price_in_cents": 80250,
"tax_in_cents": 15167,
"to_be_paid_in_cents": 97392,
"discount_type": "percentage",
"discount_percentage": 10.0,
"billing_address_property_id": null,
"delivery_address_property_id": null,
"fulfillment_type": "pickup",
"delivery_address": null,
"customer_id": "5e7fb1d5-a69a-4dad-8f6c-0a321ec6da2c",
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "595f65d5-8218-4704-83ae-39aff6d1aeb4",
"stop_location_id": "595f65d5-8218-4704-83ae-39aff6d1aeb4",
"order_delivery_rate_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/orders
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[orders]=created_at,updated_at,number |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=customer,coupon,start_location |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
amount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
amount_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
amount_to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
any_shortage |
boolean eq |
billing_address_property_id |
uuid eq, not_eq |
conditions |
hash eq |
coupon_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
coupon_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
delivery_address_property_id |
uuid eq, not_eq |
deposit_held_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_refunded_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_to_refund_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_type |
enum eq |
discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
discount_type |
enum eq |
discount_value |
float eq, not_eq, gt, gte, lt, lte |
fulfillment_type |
string eq |
grand_total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
grand_total_with_tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
has_signed_contract |
boolean eq |
id |
uuid eq, not_eq, gt |
item_count |
integer eq, not_eq, gt, gte, lt, lte |
item_id |
uuid eq |
location_shortage |
boolean eq |
number |
integer eq, not_eq, gt, gte, lt, lte |
order_delivery_rate_id |
uuid eq, not_eq |
paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
payment_status |
enum eq |
price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
shortage |
boolean eq |
start_location_id |
uuid eq, not_eq |
start_or_stop_time |
datetime eq, not_eq, gt, gte, lt, lte, between |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
statuses |
array eq, not_eq |
stock_item_id |
uuid eq |
stop_location_id |
uuid eq, not_eq |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
tax_region_id |
uuid eq, not_eq |
to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
amount_in_cents |
array sum, maximum, minimum, average |
amount_paid_in_cents |
array sum, maximum, minimum, average |
amount_to_be_paid_in_cents |
array sum, maximum, minimum, average |
coupon_discount_in_cents |
array sum, maximum, minimum, average |
deposit_held_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
deposit_paid_in_cents |
array sum, maximum, minimum, average |
deposit_refunded_in_cents |
array sum, maximum, minimum, average |
deposit_to_be_paid_in_cents |
array sum, maximum, minimum, average |
deposit_to_refund_in_cents |
array sum, maximum, minimum, average |
deposit_type |
array count |
discount_in_cents |
array sum, maximum, minimum, average |
discount_percentage |
array maximum, minimum, average |
fulfillment_type |
array count |
grand_total_in_cents |
array sum, maximum, minimum, average |
grand_total_with_tax_in_cents |
array sum, maximum, minimum, average |
item_count |
array sum, maximum, minimum, average |
location_shortage |
array count |
paid_in_cents |
array sum, maximum, minimum, average |
payment_status |
array count |
price_in_cents |
array sum, maximum, minimum, average |
shortage |
array count |
status |
array count |
statuses |
array count |
tag_list |
array count |
tax_in_cents |
array sum, maximum, minimum, average |
to_be_paid_in_cents |
array sum, maximum, minimum, average |
total |
array count |
total_discount_in_cents |
array sum, maximum, minimum, average |
total_in_cents |
array sum, maximum, minimum, average |
total_paid_in_cents |
array sum, maximum, minimum, average |
total_to_be_paid_in_cents |
array sum, maximum, minimum, average |
Includes
This request accepts the following includes:
couponcustomerpropertiesstart_locationstop_location
Search orders
Use advanced search to make logical filter groups with and/or operators.
How to search for orders:
curl --request POST
--url 'https://example.booqable.com/api/4/orders/search'
--header 'content-type: application/json'
--data '{
"fields": {
"orders": "id"
},
"filter": {
"conditions": {
"operator": "and",
"attributes": [
{
"operator": "or",
"attributes": [
{
"starts_at": {
"gte": "2025-11-11T09:29:09Z",
"lte": "2025-11-14T09:29:09Z"
}
},
{
"stops_at": {
"gte": "2025-11-11T09:29:09Z",
"lte": "2025-11-14T09:29:09Z"
}
}
]
},
{
"operator": "and",
"attributes": [
{
"deposit_type": "none"
},
{
"payment_status": "paid"
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "b16cd617-07ab-4ca4-87d3-8868952b190e"
},
{
"id": "6021cb4f-601d-47a1-8f99-610793da2ba1"
}
]
}
HTTP Request
POST /api/4/orders/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[orders]=created_at,updated_at,number |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=customer,coupon,start_location |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
amount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
amount_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
amount_to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
any_shortage |
boolean eq |
billing_address_property_id |
uuid eq, not_eq |
conditions |
hash eq |
coupon_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
coupon_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
delivery_address_property_id |
uuid eq, not_eq |
deposit_held_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_refunded_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_to_refund_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
deposit_type |
enum eq |
discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
discount_percentage |
float eq, not_eq, gt, gte, lt, lte |
discount_type |
enum eq |
discount_value |
float eq, not_eq, gt, gte, lt, lte |
fulfillment_type |
string eq |
grand_total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
grand_total_with_tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
has_signed_contract |
boolean eq |
id |
uuid eq, not_eq, gt |
item_count |
integer eq, not_eq, gt, gte, lt, lte |
item_id |
uuid eq |
location_shortage |
boolean eq |
number |
integer eq, not_eq, gt, gte, lt, lte |
order_delivery_rate_id |
uuid eq, not_eq |
paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
payment_status |
enum eq |
price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
q |
string eq |
shortage |
boolean eq |
start_location_id |
uuid eq, not_eq |
start_or_stop_time |
datetime eq, not_eq, gt, gte, lt, lte, between |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
statuses |
array eq, not_eq |
stock_item_id |
uuid eq |
stop_location_id |
uuid eq, not_eq |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
tax_region_id |
uuid eq, not_eq |
to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_discount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
total_to_be_paid_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
amount_in_cents |
array sum, maximum, minimum, average |
amount_paid_in_cents |
array sum, maximum, minimum, average |
amount_to_be_paid_in_cents |
array sum, maximum, minimum, average |
coupon_discount_in_cents |
array sum, maximum, minimum, average |
deposit_held_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
deposit_paid_in_cents |
array sum, maximum, minimum, average |
deposit_refunded_in_cents |
array sum, maximum, minimum, average |
deposit_to_be_paid_in_cents |
array sum, maximum, minimum, average |
deposit_to_refund_in_cents |
array sum, maximum, minimum, average |
deposit_type |
array count |
discount_in_cents |
array sum, maximum, minimum, average |
discount_percentage |
array maximum, minimum, average |
fulfillment_type |
array count |
grand_total_in_cents |
array sum, maximum, minimum, average |
grand_total_with_tax_in_cents |
array sum, maximum, minimum, average |
item_count |
array sum, maximum, minimum, average |
location_shortage |
array count |
paid_in_cents |
array sum, maximum, minimum, average |
payment_status |
array count |
price_in_cents |
array sum, maximum, minimum, average |
shortage |
array count |
status |
array count |
statuses |
array count |
tag_list |
array count |
tax_in_cents |
array sum, maximum, minimum, average |
to_be_paid_in_cents |
array sum, maximum, minimum, average |
total |
array count |
total_discount_in_cents |
array sum, maximum, minimum, average |
total_in_cents |
array sum, maximum, minimum, average |
total_paid_in_cents |
array sum, maximum, minimum, average |
total_to_be_paid_in_cents |
array sum, maximum, minimum, average |
Includes
This request accepts the following includes:
couponcustomerpropertiesstart_locationstop_location
New order
Returns an existing or new order for the current employee.
How to fetch a new order:
curl --get 'https://example.booqable.com/api/4/orders/new'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "952676bb-b830-4efa-8bd4-6b03b23fbe32",
"type": "orders",
"attributes": {
"created_at": "2025-08-08T10:38:00.000000+00:00",
"updated_at": "2025-08-08T10:38:00.000000+00:00",
"number": null,
"status": "new",
"statuses": [
"new"
],
"status_counts": {
"new": 0,
"draft": 0,
"reserved": 0,
"started": 0,
"stopped": 0
},
"starts_at": null,
"stops_at": null,
"deposit_type": "percentage",
"deposit_value": 100.0,
"entirely_started": true,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "paid",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 0,
"tag_list": [],
"properties": {
"delivery_address": null,
"billing_address": null
},
"amount_in_cents": 0,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": null,
"deposit_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": null,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 0,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 0,
"total_discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"discount_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"paid_in_cents": 0,
"price_in_cents": 0,
"tax_in_cents": 0,
"to_be_paid_in_cents": 0,
"discount_type": "percentage",
"discount_percentage": 0.0,
"billing_address_property_id": null,
"delivery_address_property_id": null,
"fulfillment_type": "pickup",
"delivery_address": null,
"customer_id": null,
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "a1af9993-17e0-4410-8fd6-a096f9bcdd0d",
"stop_location_id": "a1af9993-17e0-4410-8fd6-a096f9bcdd0d",
"order_delivery_rate_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/orders/new
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[orders]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=barcode,coupon,customer |
Includes
This request accepts the following includes:
barcodecoupon-
customermerge_suggestion_customerpayment_methodsproperties
documents-
lines-
itembarcodebundle_itemsphotoproperties
-
planning-
stock_item_plannings-
stock_itembarcode
-
-
tax_category
-
notesorder_delivery_rate-
paymentspayment_method
propertiesstart_locationstop_locationtax_regiontax_valuestransfers
Fetch an order
How to fetch an order:
curl --get 'https://example.booqable.com/api/4/orders/620766b9-d5c5-4e8d-83cd-c106f1bb148e'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "620766b9-d5c5-4e8d-83cd-c106f1bb148e",
"type": "orders",
"attributes": {
"created_at": "2015-07-07T09:48:01.000000+00:00",
"updated_at": "2015-07-07T09:48:01.000000+00:00",
"number": 1,
"status": "reserved",
"statuses": [
"reserved"
],
"status_counts": {
"draft": 0,
"new": 0,
"reserved": 1,
"started": 0,
"stopped": 0
},
"starts_at": "1969-11-26T12:19:01.000000+00:00",
"stops_at": "1969-12-26T12:19:01.000000+00:00",
"deposit_type": "percentage",
"deposit_value": 10.0,
"entirely_started": false,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "payment_due",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 1,
"tag_list": [
"webshop"
],
"properties": {
"delivery_address": null,
"billing_address": null
},
"amount_in_cents": 87392,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": 87392,
"deposit_in_cents": 10000,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": 10000,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 97392,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 97392,
"total_discount_in_cents": 8025,
"coupon_discount_in_cents": 0,
"discount_in_cents": 8025,
"grand_total_in_cents": 72225,
"grand_total_with_tax_in_cents": 87392,
"paid_in_cents": 0,
"price_in_cents": 80250,
"tax_in_cents": 15167,
"to_be_paid_in_cents": 97392,
"discount_type": "percentage",
"discount_percentage": 10.0,
"billing_address_property_id": null,
"delivery_address_property_id": null,
"fulfillment_type": "pickup",
"delivery_address": null,
"customer_id": "af4ff106-fdde-49e2-83ec-57302f00cd68",
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "8a045d6d-cb6a-4ead-8c79-6e7bc659d7d4",
"stop_location_id": "8a045d6d-cb6a-4ead-8c79-6e7bc659d7d4",
"order_delivery_rate_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/orders/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[orders]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=barcode,coupon,customer |
Includes
This request accepts the following includes:
barcodecoupon-
customermerge_suggestion_customerpayment_methodsproperties
documents-
lines-
itembarcodebundle_itemsphotoproperties
-
planning-
stock_item_plannings-
stock_itembarcode
-
-
tax_category
-
notesorder_delivery_rate-
paymentspayment_method
propertiesstart_locationstop_locationtax_regiontax_valuestransfers
Create an order
When creating an order it is possible to choose the initial status. Accepted statuses
are new, draft and reserved.
The created Order is empty (contains no products or other lines). To book products, stock items or bundles on an order, use the OrderFulfillment API.
When the following attributes are not specified, a sensible default will be picked:
deposit_type- From customer settings, or global default deposit type.deposit_value- From customer settings, or global default deposit type.discount_type- From customer settings.tax_region_id- From customer settings.start_location_id- First created active location.stop_location_id- First created active location.
How to create an order:
curl --request POST
--url 'https://example.booqable.com/api/4/orders'
--header 'content-type: application/json'
--data '{
"data": {
"type": "orders",
"attributes": {
"starts_at": "2026-09-25T14:40:01.000000+00:00",
"stops_at": "2026-11-03T14:40:01.000000+00:00"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "2ad70f42-1f86-4a2a-80fd-d3da815fcc0a",
"type": "orders",
"attributes": {
"created_at": "2026-09-22T14:40:01.000000+00:00",
"updated_at": "2026-09-22T14:40:01.000000+00:00",
"number": null,
"status": "new",
"statuses": [
"new"
],
"status_counts": {
"new": 0,
"draft": 0,
"reserved": 0,
"started": 0,
"stopped": 0
},
"starts_at": "2026-09-25T14:26:01.000000+00:00",
"stops_at": "2026-11-03T14:26:01.000000+00:00",
"deposit_type": "percentage",
"deposit_value": 100.0,
"entirely_started": true,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "paid",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 0,
"tag_list": [],
"properties": {
"delivery_address": null,
"billing_address": null
},
"amount_in_cents": 0,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": null,
"deposit_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": null,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 0,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 0,
"total_discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"discount_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"paid_in_cents": 0,
"price_in_cents": 0,
"tax_in_cents": 0,
"to_be_paid_in_cents": 0,
"discount_type": "percentage",
"discount_percentage": 0.0,
"billing_address_property_id": null,
"delivery_address_property_id": null,
"fulfillment_type": "pickup",
"delivery_address": null,
"customer_id": null,
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "e425fa84-11b4-48c8-8c41-73bdfabc34d9",
"stop_location_id": "e425fa84-11b4-48c8-8c41-73bdfabc34d9",
"order_delivery_rate_id": null
},
"relationships": {}
},
"meta": {}
}
Create an order with delivery address:
curl --request POST
--url 'https://example.booqable.com/api/4/orders'
--header 'content-type: application/json'
--data '{
"data": {
"type": "orders",
"attributes": {
"customer_id": "3a27640b-1429-4e99-8731-797893bb4e7a",
"fulfillment_type": "delivery",
"starts_at": "2018-04-05T18:58:00.000000+00:00",
"stops_at": "2018-05-14T18:58:00.000000+00:00",
"start_location_id": "46d00ab8-c063-4a54-8b94-db5d2eff88fe",
"stop_location_id": "46d00ab8-c063-4a54-8b94-db5d2eff88fe",
"properties_attributes": [
{
"identifier": "delivery_address",
"name": "Delivery address",
"property_type": "address",
"address1": "81801 Overseas Hwy",
"address2": "Suite 100",
"city": "Islamorada",
"region": "Florida",
"zipcode": "33036",
"country": "United States"
}
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "a627b12b-8d33-4094-8653-d80ec942410b",
"type": "orders",
"attributes": {
"created_at": "2018-04-02T18:58:00.000000+00:00",
"updated_at": "2018-04-02T18:58:00.000000+00:00",
"number": null,
"status": "new",
"statuses": [
"new"
],
"status_counts": {
"new": 0,
"draft": 0,
"reserved": 0,
"started": 0,
"stopped": 0
},
"starts_at": "2018-04-05T18:44:00.000000+00:00",
"stops_at": "2018-05-14T18:44:00.000000+00:00",
"deposit_type": "percentage",
"deposit_value": 100.0,
"entirely_started": true,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "paid",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 0,
"tag_list": [],
"properties": {
"delivery_address": "81801 Overseas Hwy\nSuite 100\n33036 Islamorada Florida\nUnited States",
"billing_address": "81801 Overseas Hwy\nSuite 100\n33036 Islamorada Florida\nUnited States"
},
"amount_in_cents": 0,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": null,
"deposit_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": null,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 0,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 0,
"total_discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"discount_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"paid_in_cents": 0,
"price_in_cents": 0,
"tax_in_cents": 0,
"to_be_paid_in_cents": 0,
"discount_type": "percentage",
"discount_percentage": 0.0,
"billing_address_property_id": null,
"delivery_address_property_id": "c145ac19-ea96-40c6-8d7c-9dc81eec5035",
"fulfillment_type": "delivery",
"delivery_address": "81801 Overseas Hwy\nSuite 100\n33036 Islamorada Florida\nUnited States",
"customer_id": "3a27640b-1429-4e99-8731-797893bb4e7a",
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "46d00ab8-c063-4a54-8b94-db5d2eff88fe",
"stop_location_id": "46d00ab8-c063-4a54-8b94-db5d2eff88fe",
"order_delivery_rate_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/orders
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[orders]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=barcode,coupon,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][billing_address_property_id] |
uuid The UUID of the address Property to use as the billing address. The property must be of type address and should belong either to the order or to the customer.See Setting Delivery and Billing Addresses for details on how to set addresses. |
data[attributes][confirm_shortage] |
boolean When set to true, this confirms a shortage warning during an update operation. Use this parameter when you receive a shortage warning but want to proceed with the update despite the shortage. Overriding shortage is only possible when the affected ProductGroup is configured to allow shortage. |
data[attributes][coupon_id] |
uuid The Coupon added to this Order. |
data[attributes][customer_id] |
uuid The Customer this Order is for. |
data[attributes][delivery_address] |
string Read-only. A formatted string representation of the delivery address. This attribute cannot be written to directly. To set the delivery address, use either delivery_address_property_id to reference an existing address Property, or use properties_attributes to create the address inline. See Setting Delivery and Billing Addresses for detailed examples. |
data[attributes][delivery_address_property_id] |
uuid The UUID of the address Property to use as the delivery address. Required when fulfillment_type is delivery. The property must be of type address and should belong either to the order or to the customer.See Setting Delivery and Billing Addresses for details on how to set addresses. |
data[attributes][deposit_type] |
enum How deposit is calculated. One of: none, percentage_total, percentage, fixed. |
data[attributes][deposit_value] |
float The value to use for deposit_type. |
data[attributes][discount_type] |
enum Type of discount. One of: percentage, fixed. |
data[attributes][discount_value] |
float The value to use for discount_type. |
data[attributes][fulfillment_type] |
enum Indicates the process used to fulfill this order. Values can be pickup (customer collects items from a location) or delivery (items are delivered to the customer's address). This affects which address fields are required and whether delivery charges apply.One of: pickup, delivery. |
data[attributes][order_delivery_rate_attributes] |
hash Assign this attribute to create/update the order delivery rate as subresource of order in a single request. |
data[attributes][order_delivery_rate_id] |
uuid The id of the order delivery rate. |
data[attributes][override_period_restrictions] |
boolean Force free period selection when there are restrictions enabled for the order period picker. |
data[attributes][properties_attributes][] |
array Create or update Properties as part of the order in a single request. This is useful for setting custom fields and addresses inline without creating separate property resources first. To set a delivery or billing address, include a property with identifier set to delivery_address or billing_address and provide the address fields (address1, city, zipcode, country, etc.). The order will automatically link to this address via delivery_address_property_id or billing_address_property_id.See Setting Delivery and Billing Addresses for complete examples and Properties for all available address fields. |
data[attributes][start_location_id] |
uuid The Location where the customer will pick up the items. |
data[attributes][starts_at] |
datetime When the items on the order become unavailable. This is the date/time when the rental period officially begins. Changing this date may result in shortages if the items are no longer available for the new time period. |
data[attributes][status] |
enum Simplified status of the order. An order can be in a mixed state (i.e. partially started or stopped). The statuses attribute contains the full list of current statuses, and status_counts specifies how many items are in each state.This attribute can only be written when creating an order. Accepted statuses are new, draft and reserved.One of: new, draft, reserved, started, stopped, archived, canceled. |
data[attributes][stop_location_id] |
uuid The Location where the customer will return the items. When the clusters feature is in use, the stop location needs to be in the same cluster as the start location. |
data[attributes][stops_at] |
datetime When the items on the order become available again. This is the date/time when the rental period officially ends, and inventory becomes available for other orders after this point. Extending this date may result in shortages if the items are already booked for other orders. |
data[attributes][tag_list] |
array[string] Case insensitive tag list. |
data[attributes][tax_region_id] |
uuid TaxRegion applied to this Order. |
Includes
This request accepts the following includes:
barcodecoupon-
customermerge_suggestion_customerpayment_methodsproperties
documents-
lines-
itembarcodebundle_itemsphotoproperties
-
planning-
stock_item_plannings-
stock_itembarcode
-
-
tax_category
-
notesorder_delivery_rate-
paymentspayment_method
propertiesstart_locationstop_locationtax_regiontax_valuestransfers
Update an order
When updating a customer on an order the following settings will be applied and prices will be calculated accordingly:
discount_percentagedeposit_typedeposit_valuetax_region_id
How to assign a (new) customer to an order:
curl --request PUT
--url 'https://example.booqable.com/api/4/orders/b7fc4715-4681-4fbf-8786-f911532c94f1'
--header 'content-type: application/json'
--data '{
"fields": {
"orders": "customer_id,tax_region_id,price_in_cents,grand_total_with_tax_in_cents,to_be_paid_in_cents"
},
"data": {
"id": "b7fc4715-4681-4fbf-8786-f911532c94f1",
"type": "orders",
"attributes": {
"customer_id": "62778da7-58fa-4717-8474-a9bcd8c003b4"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "b7fc4715-4681-4fbf-8786-f911532c94f1",
"type": "orders",
"attributes": {
"grand_total_with_tax_in_cents": 97102,
"price_in_cents": 80250,
"to_be_paid_in_cents": 197102,
"customer_id": "62778da7-58fa-4717-8474-a9bcd8c003b4",
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
How to update the deposit_type:
curl --request PUT
--url 'https://example.booqable.com/api/4/orders/2508bac9-57f4-4320-8fe5-e3e30186754d'
--header 'content-type: application/json'
--data '{
"fields": {
"orders": "deposit_type,deposit_in_cents,to_be_paid_in_cents,deposit_paid_in_cents"
},
"data": {
"id": "2508bac9-57f4-4320-8fe5-e3e30186754d",
"type": "orders",
"attributes": {
"deposit_type": "percentage"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "2508bac9-57f4-4320-8fe5-e3e30186754d",
"type": "orders",
"attributes": {
"deposit_type": "percentage",
"deposit_in_cents": 10000,
"deposit_paid_in_cents": 0,
"to_be_paid_in_cents": 97392
},
"relationships": {}
},
"meta": {}
}
Updating stops_at resulting in a shortage:
curl --request PUT
--url 'https://example.booqable.com/api/4/orders/93a4240b-dabb-4402-8f6c-bc85a87f922c'
--header 'content-type: application/json'
--data '{
"data": {
"id": "93a4240b-dabb-4402-8f6c-bc85a87f922c",
"type": "orders",
"attributes": {
"stops_at": "2024-06-14T15:18:00.000000+00:00"
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "stock_item_specified",
"status": "422",
"title": "Stock item specified",
"detail": "One or more items are not available",
"meta": {
"warning": [],
"blocking": [
{
"reason": "stock_item_specified",
"item_id": "6b8dcfd1-8b08-4c90-8a27-22ad5a6a3ae9",
"unavailable": [
"e58fe3d1-2652-4c3c-8432-caf5b7148a09"
],
"available": [
"05f42f25-5487-40b6-8494-463dcf974a53"
]
}
]
}
}
]
}
HTTP Request
PUT /api/4/orders/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[orders]=created_at,updated_at,number |
include |
string List of comma seperated relationships to sideload. ?include=barcode,coupon,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][billing_address_property_id] |
uuid The UUID of the address Property to use as the billing address. The property must be of type address and should belong either to the order or to the customer.See Setting Delivery and Billing Addresses for details on how to set addresses. |
data[attributes][confirm_shortage] |
boolean When set to true, this confirms a shortage warning during an update operation. Use this parameter when you receive a shortage warning but want to proceed with the update despite the shortage. Overriding shortage is only possible when the affected ProductGroup is configured to allow shortage. |
data[attributes][coupon_id] |
uuid The Coupon added to this Order. |
data[attributes][customer_id] |
uuid The Customer this Order is for. |
data[attributes][delivery_address] |
string Read-only. A formatted string representation of the delivery address. This attribute cannot be written to directly. To set the delivery address, use either delivery_address_property_id to reference an existing address Property, or use properties_attributes to create the address inline. See Setting Delivery and Billing Addresses for detailed examples. |
data[attributes][delivery_address_property_id] |
uuid The UUID of the address Property to use as the delivery address. Required when fulfillment_type is delivery. The property must be of type address and should belong either to the order or to the customer.See Setting Delivery and Billing Addresses for details on how to set addresses. |
data[attributes][deposit_type] |
enum How deposit is calculated. One of: none, percentage_total, percentage, fixed. |
data[attributes][deposit_value] |
float The value to use for deposit_type. |
data[attributes][discount_type] |
enum Type of discount. One of: percentage, fixed. |
data[attributes][discount_value] |
float The value to use for discount_type. |
data[attributes][fulfillment_type] |
enum Indicates the process used to fulfill this order. Values can be pickup (customer collects items from a location) or delivery (items are delivered to the customer's address). This affects which address fields are required and whether delivery charges apply.One of: pickup, delivery. |
data[attributes][order_delivery_rate_attributes] |
hash Assign this attribute to create/update the order delivery rate as subresource of order in a single request. |
data[attributes][order_delivery_rate_id] |
uuid The id of the order delivery rate. |
data[attributes][override_period_restrictions] |
boolean Force free period selection when there are restrictions enabled for the order period picker. |
data[attributes][properties_attributes][] |
array Create or update Properties as part of the order in a single request. This is useful for setting custom fields and addresses inline without creating separate property resources first. To set a delivery or billing address, include a property with identifier set to delivery_address or billing_address and provide the address fields (address1, city, zipcode, country, etc.). The order will automatically link to this address via delivery_address_property_id or billing_address_property_id.See Setting Delivery and Billing Addresses for complete examples and Properties for all available address fields. |
data[attributes][start_location_id] |
uuid The Location where the customer will pick up the items. |
data[attributes][starts_at] |
datetime When items become unavailable, changing this value may result in shortages |
data[attributes][status] |
enum Simplified status of the order. An order can be in a mixed state (i.e. partially started or stopped). The statuses attribute contains the full list of current statuses, and status_counts specifies how many items are in each state.This attribute can only be written when creating an order. Accepted statuses are new, draft and reserved.One of: new, draft, reserved, started, stopped, archived, canceled. |
data[attributes][stop_location_id] |
uuid The Location where the customer will return the items. When the clusters feature is in use, the stop location needs to be in the same cluster as the start location. |
data[attributes][stops_at] |
datetime When items become available, changing this value may result in shortages |
data[attributes][tag_list] |
array[string] Case insensitive tag list. |
data[attributes][tax_region_id] |
uuid TaxRegion applied to this Order. |
Includes
This request accepts the following includes:
barcodecoupon-
customermerge_suggestion_customerpayment_methodsproperties
documents-
lines-
itembarcodebundle_itemsphotoproperties
-
planning-
stock_item_plannings-
stock_itembarcode
-
-
tax_category
-
notesorder_delivery_rate-
paymentspayment_method
propertiesstart_locationstop_locationtax_regiontax_valuestransfers
Order delivery rate recalculations
Recalculates the delivery rate of a delivery order.
Relationships
| Name | Description |
|---|---|
order |
Order requiredOrder that needs recalculation of its rates. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
id |
uuid readonlyPrimary key. |
order_id |
uuid Order that needs recalculation of its rates. |
Recalculate delivery rates
How to recalculate delivery rates:
curl --request POST
--url 'https://example.booqable.com/api/4/order_delivery_rate_recalculations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_delivery_rate_recalculations",
"attributes": {
"order_id": "48b7ecd6-6758-4045-81ee-d430100bd349"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "0c68209e-69ed-4c80-8b11-3801b7280e42",
"type": "order_delivery_rate_recalculations",
"attributes": {
"order_id": "48b7ecd6-6758-4045-81ee-d430100bd349"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_delivery_rate_recalculations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_delivery_rate_recalculations]=order_id |
include |
string List of comma seperated relationships to sideload. ?include=order |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][order_id] |
uuid Order that needs recalculation of its rates. |
Includes
This request accepts the following includes:
-
orderorder_delivery_ratetax_values
Order delivery rates
Order delivery rates hold information about the delivery rate associated with a delivery order.
This data is relevant only for orders that have a delivery fulfillment type.
Relationships
| Name | Description |
|---|---|
carrier |
App carrier optionalThe selected carrier for this order. |
order |
Order optionalThe delivery Order this rate is for. |
tax_category |
Tax category optionalThe tax category for custom delivery rates. When a carrier is selected, the carrier's tax category is used instead. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
carrier_id |
uuid readonly-after-create nullableThe selected carrier for this order. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
identifier |
string The identifier of the delivery rate. |
minimum_order_amount_in_cents |
integer The minimum order amount in cents for this delivery rate. |
order_id |
uuid writeonlyThe delivery Order this rate is for. |
price_in_cents |
integer The price of the delivery rate in cents. |
rate_id |
string The rate ID returned by a delivery app. |
signed_attributes |
string The signed attributes returned by a delivery app. |
tax_category_id |
uuid nullableThe tax category for custom delivery rates. When a carrier is selected, the carrier's tax category is used instead. |
updated_at |
datetime readonlyWhen the resource was last updated. |
Fetch rates from all installed delivery apps for an order
How to fetch a list of rates:
curl --get 'https://example.booqable.com/api/4/order_delivery_rates'
--header 'content-type: application/json'
--data-urlencode 'filter[order_id]=511097b6-24a3-4291-8141-095dcff3eb32'
A 200 status response looks like this:
{
"data": [
{
"id": "2370b233-cede-4a13-807c-be861a8e3cbd",
"type": "delivery_rates",
"attributes": {
"type": "flat",
"carrier_id": "04fc2f33-2196-4bbf-80be-31bdddf2a302",
"price_in_cents": 1000,
"label": "standard_delivery",
"range": "10 km",
"minimum_order_amount_in_cents": 0,
"description": "Standard delivery",
"errors": []
}
},
{
"id": "2bad4bc7-ab29-43ba-8c99-61c895023e9f",
"type": "delivery_rates",
"attributes": {
"type": "calculated",
"carrier_id": "04fc2f33-2196-4bbf-80be-31bdddf2a302",
"price_in_cents": 2500,
"label": "fast_delivery",
"range": "8.75 km",
"minimum_order_amount_in_cents": 1000,
"description": "Fast delivery",
"errors": [
"under_minimum_order_amount"
]
}
}
]
}
HTTP Request
GET /api/4/order_delivery_rates
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_delivery_rates]=created_at,updated_at,identifier |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=carrier,tax_category,order |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
carrier_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
minimum_order_amount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
rate_id |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
signed_attributes |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
tax_category_id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
carrierordertax_category
Fetch an order delivery rate
How to fetch a rate:
curl --get 'https://example.booqable.com/api/4/order_delivery_rates/92882618-2029-4da8-84ce-00546ba482bf'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "92882618-2029-4da8-84ce-00546ba482bf",
"type": "order_delivery_rates",
"attributes": {
"created_at": "2025-11-19T18:45:00.000000+00:00",
"updated_at": "2025-11-19T18:45:00.000000+00:00",
"identifier": "Custom",
"price_in_cents": 10000,
"rate_id": null,
"minimum_order_amount_in_cents": 0,
"tax_category_id": null,
"signed_attributes": null,
"carrier_id": "5d74673e-ac2b-4853-8a69-66982a001b26"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/order_delivery_rates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_delivery_rates]=created_at,updated_at,identifier |
include |
string List of comma seperated relationships to sideload. ?include=carrier,tax_category,order |
Includes
This request accepts the following includes:
carrierordertax_category
Create an order delivery rate
How to create an order delivery rate:
curl --request POST
--url 'https://example.booqable.com/api/4/order_delivery_rates'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_delivery_rates",
"attributes": {
"order_id": "614e2067-a249-44aa-899c-e0e493f52f34",
"identifier": "Custom rate",
"price_in_cents": 5000,
"minimum_order_amount_in_cents": 1000,
"tax_category_id": "3b1f144e-04a1-4bc3-829d-e1eb2c56f060"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "d5e985e9-1327-4fc2-8068-736295a1ec1f",
"type": "order_delivery_rates",
"attributes": {
"created_at": "2026-03-19T10:24:00.000000+00:00",
"updated_at": "2026-03-19T10:24:00.000000+00:00",
"identifier": "Custom rate",
"price_in_cents": 5000,
"rate_id": null,
"minimum_order_amount_in_cents": 1000,
"tax_category_id": "3b1f144e-04a1-4bc3-829d-e1eb2c56f060",
"signed_attributes": null,
"carrier_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_delivery_rates
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_delivery_rates]=created_at,updated_at,identifier |
include |
string List of comma seperated relationships to sideload. ?include=carrier,tax_category,order |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][carrier_id] |
uuid The selected carrier for this order. |
data[attributes][identifier] |
string The identifier of the delivery rate. |
data[attributes][minimum_order_amount_in_cents] |
integer The minimum order amount in cents for this delivery rate. |
data[attributes][order_id] |
uuid The delivery Order this rate is for. |
data[attributes][price_in_cents] |
integer The price of the delivery rate in cents. |
data[attributes][rate_id] |
string The rate ID returned by a delivery app. |
data[attributes][signed_attributes] |
string The signed attributes returned by a delivery app. |
data[attributes][tax_category_id] |
uuid The tax category for custom delivery rates. When a carrier is selected, the carrier's tax category is used instead. |
Includes
This request accepts the following includes:
carrierordertax_category
Update an order delivery rate
How to update an order delivery rate:
curl --request PUT
--url 'https://example.booqable.com/api/4/order_delivery_rates/00380853-f61f-4ade-8d98-f1cbcbfe2d7f'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_delivery_rates",
"id": "00380853-f61f-4ade-8d98-f1cbcbfe2d7f",
"attributes": {
"identifier": "Standard",
"price_in_cents": 5000
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "00380853-f61f-4ade-8d98-f1cbcbfe2d7f",
"type": "order_delivery_rates",
"attributes": {
"created_at": "2016-08-26T07:41:01.000000+00:00",
"updated_at": "2016-08-26T07:41:01.000000+00:00",
"identifier": "Standard",
"price_in_cents": 5000,
"rate_id": null,
"minimum_order_amount_in_cents": 0,
"tax_category_id": null,
"signed_attributes": null,
"carrier_id": "02309205-57de-4518-85c4-551531c6aba6"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/order_delivery_rates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_delivery_rates]=created_at,updated_at,identifier |
include |
string List of comma seperated relationships to sideload. ?include=carrier,tax_category,order |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][carrier_id] |
uuid The selected carrier for this order. |
data[attributes][identifier] |
string The identifier of the delivery rate. |
data[attributes][minimum_order_amount_in_cents] |
integer The minimum order amount in cents for this delivery rate. |
data[attributes][order_id] |
uuid The delivery Order this rate is for. |
data[attributes][price_in_cents] |
integer The price of the delivery rate in cents. |
data[attributes][rate_id] |
string The rate ID returned by a delivery app. |
data[attributes][signed_attributes] |
string The signed attributes returned by a delivery app. |
data[attributes][tax_category_id] |
uuid The tax category for custom delivery rates. When a carrier is selected, the carrier's tax category is used instead. |
Includes
This request accepts the following includes:
carrierordertax_category
Delete an order delivery rate
How to delete an order delivery rate:
curl --request DELETE
--url 'https://example.booqable.com/api/4/order_delivery_rates/e1bbed39-2b7f-4c41-806e-4d3259929112'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"meta": {}
}
HTTP Request
DELETE /api/4/order_delivery_rates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_delivery_rates]=created_at,updated_at,identifier |
include |
string List of comma seperated relationships to sideload. ?include=carrier,tax_category,order |
Includes
This request accepts the following includes:
carrierordertax_category
Order fulfillments
Takes an Order through the fulfillment process.
Actions
Book a Bundle
For each unspecified BundleItem a product variation needs to be selected. Specified BundleItems are automatically booked. These must not be included in the request. When a Bundle only contains specified BundleItems, an empty list of product variations must be provided.
The quantity attribute sets the quantity of the Bundle itself,
and multiplies the quantities of all products in the Bundle.
The confirm_shortage attribute (on the resource, not on the action),
overrides shortage warnings when booking on a reserved or started order.
{
"action": "book_bundle",
"bundle_id": "<id>",
"quantity": N,
"product_variations": [
{
"bundle_item_id": "<id>",
"product_id": "<id>"
},
{
"bundle_item_id": "<id>",
"product_id": "<id>"
}
]
}
Book a Product
Books a quantity of a Product on an Order. This can be any type of Product, including trackable Products.
This action supports 3 modes:
create_new, a new Planning and Line are created.update_existing, the quantity is added to an existing Planning/Lineinfer_planning, behaves asupdate_existingwhen a Planning for the same Product exists. Behaves ascreate_newwhen there is no existing Planning for the Product.
The confirm_shortage attribute (on the resource, not on the action),
overrides shortage warnings when booking on a reserved or started order.
{
"action": "book_product",
"mode": "create_new",
"planning_id": "<id>", // required for `mode==update_existing`
"product_id": "<id>",
"quantity": N,
}
Book StockItems
Books one or more StockItems of a trackable Product on an Order.
This action supports 3 modes:
create_new, a new Planning and Line are created.update_existing, the StockItems are booked on an existing Planning/Line. If needed, the quantity of the Planning is increased to accommodate all newly booked StockItems.infer_planning, behaves asupdate_existingwhen a Planning for the same Product exists. Behaves ascreate_newwhen there is no existing Planning for the Product.
The confirm_shortage attribute (on the resource, not on the action),
overrides shortage warnings when booking on a reserved or started order.
{
"action": "book_stock_items",
"stock_item_ids": ["<id>"],
"planning_id": "<id>", // required for `mode==update_existing`
"product_id": "<id>",
"mode": "infer_planning",
}
Specify StockItems
Adds or removes one or more StockItems from an existing Planning.
It is not possible to specify more StockItems than there is remaining quantity left on the Planning. StockItems that have already been started cannot be removed.
{
"action": "specify_stock_items",
"product_id": "<id>",
"planning_id": "<id>",
"stock_item_ids_to_add": ["<id>", "<id>"],
"stock_item_ids_to_remove": ["<id>", "<id>"]
}
When removing StockItems, the archived StockItemPlannings are returned
as part of the changed_stock_item_plannings relation.
Start a Product
A quantity of a product is started. The quantity can be the same as the booked quantity, or less when a subset of items is started.
The confirm_shortage attribute (on the resource, not on the action),
overrides shortage warnings when booking on a reserved or started order.
{
"action": "start_product",
"product_id": "<id>",
"planning_id": "<id>",
"quantity": N
}
Start StockItems
One or more stock items of a trackable product are started.
The confirm_shortage attribute (on the resource, not on the action),
overrides shortage warnings when booking on a reserved or started order.
{
"action": "start_stock_items",
"product_id": "<id>",
"planning_id": "<id>",
"stock_item_ids": ["<id>", "<id>"]
}
Stop a Product
A quantity of a product is returned. The product needs to have started. The quantity can be the same as the started quantity, or less when a subset of items is returned.
Sales items and Services cannot be stopped.
{
"action": "stop_product",
"product_id": "<id>",
"planning_id": "<id>",
"quantity": N
}
Stop StockItems
One or more stock items of a trackable product are returned. Only stock items that have been started can be stopped.
{
"action": "stop_stock_items",
"product_id": "<id>",
"planning_id": "<id>",
"stock_item_ids": ["<id>", "<id>"]
}
Errors
Booking and starting items can be blocked by shortage errors and other kinds of inventory errors.
Relationships
| Name | Description |
|---|---|
changed_lines |
Lines hasmanyThe Lines that have (indirectly) been created or changed by the fulfillment actions. |
changed_plannings |
Plannings hasmanyThe Plannings that have (indirectly) been created or changed by the fulfillment actions. |
changed_stock_item_plannings |
Stock item plannings hasmanyThe StockItemPlannings that have (indirectly) been created or changed by the fulfillment actions. |
order |
Order requiredThe Order to be fulfilled. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
actions |
array writeonlyArray of actions to be performed. The actions are executed atomically, and succeed as a whole, or fail as a whole. |
confirm_shortage |
boolean writeonlyA value of true overrides shortage warnings when booking products on a reserved or started Order. |
id |
uuid readonlyPrimary key. |
order_id |
uuid readonly-after-createThe Order to be fulfilled. |
Book
Book a Product (on a new Planning):
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "ff0e6b03-a401-4136-878d-03515e0a3506",
"confirm_shortage": null,
"actions": [
{
"action": "book_product",
"mode": "create_new",
"product_id": "58f2c5fd-6ac5-4557-82b8-4c33a2d89335",
"quantity": 3
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "b19330e5-df47-4444-86b2-67785dd806ab",
"type": "order_fulfillments",
"attributes": {
"order_id": "ff0e6b03-a401-4136-878d-03515e0a3506"
},
"relationships": {}
},
"meta": {}
}
Book a Product (on an existing Planning if there is any):
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "89ac038f-2546-4b89-8e0b-1ff27baca905",
"confirm_shortage": null,
"actions": [
{
"action": "book_product",
"mode": "infer_planning",
"product_id": "b495248c-6a73-4745-8921-839868860e99",
"planning_id": null,
"quantity": 3
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "6c4f57c9-8c1c-4e4d-8ccd-d681eb651f43",
"type": "order_fulfillments",
"attributes": {
"order_id": "89ac038f-2546-4b89-8e0b-1ff27baca905"
},
"relationships": {}
},
"meta": {}
}
Book a Product (on a specified Planning):
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "157cec54-7cba-4324-85f7-eff41c768bab",
"confirm_shortage": null,
"actions": [
{
"action": "book_product",
"mode": "update_existing",
"product_id": "965c1191-d5fa-4a9b-848c-fe79ad1d5594",
"planning_id": "08e98893-bab0-41b3-8913-ef8719114ef5",
"quantity": 3
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "3dc24c42-ceeb-4922-8fe9-cea120a58529",
"type": "order_fulfillments",
"attributes": {
"order_id": "157cec54-7cba-4324-85f7-eff41c768bab"
},
"relationships": {}
},
"meta": {}
}
Book StockItems:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "3d6a2dd6-55e4-4d4c-8072-e885f8315a7d",
"confirm_shortage": null,
"actions": [
{
"action": "book_stock_items",
"mode": "infer_planning",
"product_id": "8c9026b0-3f2d-4769-8658-1bbb8a272b80",
"stock_item_ids": [
"57720425-1bd2-4475-85ac-3341b8efb4dc",
"cd8f2e40-ff1b-47f7-8214-ba69e52251ed"
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "3ae75561-67df-49a3-80e2-3bb12a12ed2b",
"type": "order_fulfillments",
"attributes": {
"order_id": "3d6a2dd6-55e4-4d4c-8072-e885f8315a7d"
},
"relationships": {}
},
"meta": {}
}
Book a Bundle:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "b1d40ff0-0ab6-4316-83f7-6603b72c3c0b",
"confirm_shortage": null,
"actions": [
{
"action": "book_bundle",
"bundle_id": "1e5e1bd0-f59a-42a5-85ef-20d318221df3",
"quantity": 1,
"product_variations": [
{
"bundle_item_id": "09afe94a-0976-40b4-8993-b5caddafedd4",
"product_id": "97f7f012-d0e9-4c03-82a6-af889c86f673"
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "bf2f5b82-4ee5-47d2-866a-c48bacca6d24",
"type": "order_fulfillments",
"attributes": {
"order_id": "b1d40ff0-0ab6-4316-83f7-6603b72c3c0b"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_fulfillments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_fulfillments]=order_id |
include |
string List of comma seperated relationships to sideload. ?include=order,changed_lines,changed_plannings |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][actions][] |
array Array of actions to be performed. The actions are executed atomically, and succeed as a whole, or fail as a whole. |
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings when booking products on a reserved or started Order. |
data[attributes][order_id] |
uuid The Order to be fulfilled. |
Includes
This request accepts the following includes:
-
changed_lines-
itemphoto
-
changed_plannings-
changed_stock_item_planningsstock_item
-
ordertax_valuestransfers
Specify
Add a StockItem:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "3c6bb0a1-73c7-4087-8437-35dc26e866de",
"actions": [
{
"action": "specify_stock_items",
"product_id": "c34c820b-79b4-4c39-8a00-471d67934308",
"planning_id": "4b6038b6-5a01-4af0-83ec-0468429660c6",
"stock_item_ids_to_add": [
"5bb20b10-c7e9-4b2f-8a04-48aa9f12f117"
],
"stock_item_ids_to_remove": []
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "989891a6-cab1-4a93-8d5f-ea2bc4703ad0",
"type": "order_fulfillments",
"attributes": {
"order_id": "3c6bb0a1-73c7-4087-8437-35dc26e866de"
},
"relationships": {}
},
"meta": {}
}
Remove a StockItem:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "fd750947-416c-4da3-8158-cf456b81dc87",
"actions": [
{
"action": "specify_stock_items",
"product_id": "45cd8238-74d4-4f33-836f-31a80860316a",
"planning_id": "efda8344-0d43-4bf2-8360-2eaf863301df",
"stock_item_ids_to_add": [],
"stock_item_ids_to_remove": [
"1cf99ea9-3582-4711-8d60-f289187d90b5"
]
}
]
}
},
"include": "changed_stock_item_plannings"
}'
A 200 status response looks like this:
{
"data": {
"id": "16ff306e-ebff-4248-8533-bb32ff205846",
"type": "order_fulfillments",
"attributes": {
"order_id": "fd750947-416c-4da3-8158-cf456b81dc87"
},
"relationships": {
"changed_stock_item_plannings": {
"data": [
{
"type": "stock_item_plannings",
"id": "43523e16-c1e3-4352-8ab5-c90542c2f035"
}
]
}
}
},
"included": [
{
"id": "43523e16-c1e3-4352-8ab5-c90542c2f035",
"type": "stock_item_plannings",
"attributes": {
"created_at": "2016-07-05T01:17:01.000000+00:00",
"updated_at": "2016-07-05T01:17:01.000000+00:00",
"archived": true,
"archived_at": "2016-07-05T01:17:01.000000+00:00",
"starts_at": null,
"stops_at": null,
"reserved": false,
"started": false,
"stopped": false,
"status": "draft",
"stock_item_planning_type": "order",
"stock_item_id": "1cf99ea9-3582-4711-8d60-f289187d90b5",
"planning_id": "efda8344-0d43-4bf2-8360-2eaf863301df",
"order_id": "fd750947-416c-4da3-8158-cf456b81dc87",
"downtime_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/order_fulfillments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_fulfillments]=order_id |
include |
string List of comma seperated relationships to sideload. ?include=order,changed_lines,changed_plannings |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][actions][] |
array Array of actions to be performed. The actions are executed atomically, and succeed as a whole, or fail as a whole. |
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings when booking products on a reserved or started Order. |
data[attributes][order_id] |
uuid The Order to be fulfilled. |
Includes
This request accepts the following includes:
-
changed_lines-
itemphoto
-
changed_plannings-
changed_stock_item_planningsstock_item
-
ordertax_valuestransfers
Start
Start a Product:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "a9d2797d-f82f-4ca0-8f3a-8fc4e84e499a",
"confirm_shortage": null,
"actions": [
{
"action": "start_product",
"product_id": "3aa6808c-eb63-4f82-8c19-a65e206b5b18",
"planning_id": "ce05c511-c28f-4a58-8d1c-23cc25bfec2a",
"quantity": 1
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "5c62cc0f-134c-43a1-8d05-0a531f4bedcd",
"type": "order_fulfillments",
"attributes": {
"order_id": "a9d2797d-f82f-4ca0-8f3a-8fc4e84e499a"
},
"relationships": {}
},
"meta": {}
}
Start StockItems:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "69b468c6-e985-416f-897c-33103eb875b3",
"confirm_shortage": null,
"actions": [
{
"action": "start_stock_items",
"product_id": "df12b4c9-8a40-4d3c-86ca-cb26ad8c478a",
"planning_id": "964a14e3-4d5a-4466-8ba7-205f25d4797d",
"stock_item_ids": [
"fc165af7-9778-4d13-8fdb-fc647e19a9e3"
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "406efcb5-8979-43e7-8eea-b73ffd347952",
"type": "order_fulfillments",
"attributes": {
"order_id": "69b468c6-e985-416f-897c-33103eb875b3"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_fulfillments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_fulfillments]=order_id |
include |
string List of comma seperated relationships to sideload. ?include=order,changed_lines,changed_plannings |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][actions][] |
array Array of actions to be performed. The actions are executed atomically, and succeed as a whole, or fail as a whole. |
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings when booking products on a reserved or started Order. |
data[attributes][order_id] |
uuid The Order to be fulfilled. |
Includes
This request accepts the following includes:
-
changed_lines-
itemphoto
-
changed_plannings-
changed_stock_item_planningsstock_item
-
ordertax_valuestransfers
Stop
Stop a Product:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "a8576b48-8993-43b2-84ce-ab2403706fb9",
"actions": [
{
"action": "stop_product",
"product_id": "4ac65a34-99d1-423b-8389-ee49e2d7f3c6",
"planning_id": "8af7930b-bdab-4c3c-853b-48ba3d38d9fe",
"quantity": 1
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "1175185d-b612-4647-8bfd-24aa016dba47",
"type": "order_fulfillments",
"attributes": {
"order_id": "a8576b48-8993-43b2-84ce-ab2403706fb9"
},
"relationships": {}
},
"meta": {}
}
Stop StockItems:
curl --request POST
--url 'https://example.booqable.com/api/4/order_fulfillments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_fulfillments",
"attributes": {
"order_id": "7a2fbde4-94f3-4043-81b0-d6c4efe6dc39",
"actions": [
{
"action": "stop_stock_items",
"product_id": "9625c967-e233-4ef4-8546-78c7727754ba",
"planning_id": "b3c5171d-0080-443f-89f6-08984a27e706",
"stock_item_ids": [
"cda3cf3c-d51c-4f60-8868-6100ab309d69"
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "942d8391-0f00-4a32-840c-750509db3102",
"type": "order_fulfillments",
"attributes": {
"order_id": "7a2fbde4-94f3-4043-81b0-d6c4efe6dc39"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_fulfillments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_fulfillments]=order_id |
include |
string List of comma seperated relationships to sideload. ?include=order,changed_lines,changed_plannings |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][actions][] |
array Array of actions to be performed. The actions are executed atomically, and succeed as a whole, or fail as a whole. |
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings when booking products on a reserved or started Order. |
data[attributes][order_id] |
uuid The Order to be fulfilled. |
Includes
This request accepts the following includes:
-
changed_lines-
itemphoto
-
changed_plannings-
changed_stock_item_planningsstock_item
-
ordertax_valuestransfers
Order price recalculations
When the rental period of an order is changed, the prices of individual lines and the total price of the order are not automatically recalculated to preserve any manual changes that may have been made.
The OrderPriceRecalculation resource allows to request a recalculation for the
entire order and all its lines.
To recalculate the price of an individual line, set the charge_length of the
line to null as described here.
Relationships
| Name | Description |
|---|---|
order |
Order requiredOrder that needs to be recalculated. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
id |
uuid readonlyPrimary key. |
order_id |
uuid readonly-after-createOrder that needs to be recalculated. |
Recalculate prices
Recalculate prices when rental period has changed:
curl --request POST
--url 'https://example.booqable.com/api/4/order_price_recalculations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_price_recalculations",
"attributes": {
"order_id": "f9d1343a-593e-4557-86c1-de4af6faf4d2"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "9ee14a59-1417-4289-8959-a877624c6cb1",
"type": "order_price_recalculations",
"attributes": {
"order_id": "f9d1343a-593e-4557-86c1-de4af6faf4d2"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_price_recalculations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_price_recalculations]=order_id |
include |
string List of comma seperated relationships to sideload. ?include=order |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][order_id] |
uuid Order that needs to be recalculated. |
Includes
This request accepts the following includes:
-
orderlinestax_values
Order status transitions
Transitions an Order from one status to another status.
See Order for a description of the different statuses.
Note that you cannot transition to started or to stopped.
The Order will transition to those statuses automatically when
starting or stopping items through the OrderFulfillment resource.
It is however possible to revert to the started or the stopped status.
It is not possible to resurrect a canceled Order. Duplicating a canceled Order is possible.
Errors
When the Order cannot be transitioned, and error.code is items_not_available,
then the error.meta.blocking.*.reason or error.meta.warning.*.reason
attribute contains one of the following reasons:
stock_item_specifiedOne or more of the StockItems on this Order have also been planned for other current or future Orders. The Product is specified in theerror.meta.blocking.*.item_idattribute anderror.meta.blocking.*.unavailablecontains the problematic StockItems.shortageA shortage would be created for one or more of the Products on this Order. When the shortages would be within the shortage limits of the products, a warning is returned. Otherwise a blocking error is returned. When reserving an Order, a warning can be overridden by settingconfirm_shortagetotrue. The Product is specified in theerror.meta.warning.*.item_idorerror.meta.blocking.*.item_idattribute.
Note that is is possible to get multiple warnings and errors of different types at the same time.
Permissions
- Canceling an Order requires the
cancel_orderspermission. - Reverting an Order requires the
revert_orderspermission.
Relationships
| Name | Description |
|---|---|
order |
Order requiredThe Order whose status is changed. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
confirm_shortage |
boolean A value of true overrides shortage warnings. This is only possible when reserving an Order. |
id |
uuid readonlyPrimary key. |
order_id |
uuid The Order whose status is changed. |
revert |
boolean Indicates if this transition reverts the Order back to an earlier status. "Earlier status" does not require this specific Order to ever have been in that status (e.g. draft can have been skipped). "Earlier" means earlier in the conceptual progressing of statuses of Orders in general. |
transition_from |
enum The current status of the Order. One of: new, draft, reserved, started, stopped, archived. |
transition_to |
enum The new status of the Order. It is only possible to transition to started or stopped in combination with revert: true.One of: draft, reserved, started, stopped, archived, canceled. |
Transition
Save a new Order as draft:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "c0856c50-99cb-4cf4-87c4-39a873d65531",
"transition_from": "new",
"transition_to": "draft",
"confirm_shortage": null,
"revert": null
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "1d7c16ec-67b9-4c6b-894d-8f412f350115",
"type": "order_status_transitions",
"attributes": {
"order_id": "c0856c50-99cb-4cf4-87c4-39a873d65531",
"transition_from": "new",
"transition_to": "draft",
"revert": null,
"confirm_shortage": null
},
"relationships": {}
},
"meta": {}
}
Reserve a draft Order:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "e0f4a042-6327-407a-87b1-809014212e7b",
"transition_from": "draft",
"transition_to": "reserved",
"confirm_shortage": null,
"revert": null
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "caee0b5f-30b4-4c86-8986-e56a2e47011a",
"type": "order_status_transitions",
"attributes": {
"order_id": "e0f4a042-6327-407a-87b1-809014212e7b",
"transition_from": "draft",
"transition_to": "reserved",
"revert": null,
"confirm_shortage": null
},
"relationships": {}
},
"meta": {}
}
Reserve a draft Order, causing a blocking shortage error:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "1911dd15-db4b-4cad-8a18-6ff0723bd1d0",
"transition_from": "draft",
"transition_to": "reserved",
"confirm_shortage": null,
"revert": null
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "items_not_available",
"status": "422",
"title": "Items not available",
"detail": "One or more items are not available",
"meta": {
"warning": [],
"blocking": [
{
"reason": "shortage",
"item_id": "2759b345-6595-442a-8a84-03f156100879",
"stock_count": 1,
"reserved": 0,
"needed": 2,
"shortage": 1
}
]
}
}
]
}
Reserve a draft Order, causing a shortage warning:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "3b1ac92c-8d34-4b57-8578-40a3bf8834c7",
"transition_from": "draft",
"transition_to": "reserved",
"confirm_shortage": null,
"revert": null
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "items_not_available",
"status": "422",
"title": "Items not available",
"detail": "One or more items are not available",
"meta": {
"warning": [
{
"reason": "shortage",
"item_id": "4da5b0fd-58ca-4e60-8277-261000848262",
"stock_count": 1,
"reserved": 0,
"needed": 2,
"shortage": 1
}
],
"blocking": []
}
}
]
}
Reserve a draft Order, and override the shortage warning:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "1f2ef20f-c7d8-410c-89c2-9b5e8a2e037b",
"transition_from": "draft",
"transition_to": "reserved",
"confirm_shortage": true,
"revert": null
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "1b9ed0f6-277b-4cfd-85bd-2ea4f039dd5e",
"type": "order_status_transitions",
"attributes": {
"order_id": "1f2ef20f-c7d8-410c-89c2-9b5e8a2e037b",
"transition_from": "draft",
"transition_to": "reserved",
"revert": null,
"confirm_shortage": true
},
"relationships": {}
},
"meta": {}
}
Reserve a draft Order, causing a stock item specified error:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "5e038686-7768-4d36-8832-725442f49cc6",
"transition_from": "draft",
"transition_to": "reserved",
"confirm_shortage": null,
"revert": null
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "stock_item_specified",
"status": "422",
"title": "Stock item specified",
"detail": "One or more items are not available",
"meta": {
"warning": [],
"blocking": [
{
"reason": "stock_item_specified",
"item_id": "75bcb083-8a52-4212-814f-90b18421d198",
"unavailable": [
"c5c86b0e-7898-4c3d-8c33-425011f8ed0b"
],
"available": [
"c18a3863-071f-467f-8a25-d6b087473135"
]
}
]
}
}
]
}
Archive a reserved Order:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "428183f9-884f-4ead-885c-96af503180de",
"transition_from": "reserved",
"transition_to": "archived",
"confirm_shortage": null,
"revert": null
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "wrong_status",
"status": "422",
"title": "Wrong status",
"detail": "Can't transition order from 'reserved' to 'archived'",
"meta": null
}
]
}
Archive a stopped Order:
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "6fde1091-2638-4df5-8664-cf228c0441db",
"transition_from": "stopped",
"transition_to": "archived",
"confirm_shortage": null,
"revert": null
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "ec20fd1d-c123-48d0-81e5-eae2c73f75e3",
"type": "order_status_transitions",
"attributes": {
"order_id": "6fde1091-2638-4df5-8664-cf228c0441db",
"transition_from": "stopped",
"transition_to": "archived",
"revert": null,
"confirm_shortage": null
},
"relationships": {}
},
"meta": {}
}
Revert a reserved Order to 'draft':
curl --request POST
--url 'https://example.booqable.com/api/4/order_status_transitions'
--header 'content-type: application/json'
--data '{
"data": {
"type": "order_status_transitions",
"attributes": {
"order_id": "0c9cf30c-2afc-4972-8f6b-b1bc417fccb6",
"transition_from": "reserved",
"transition_to": "draft",
"confirm_shortage": null,
"revert": true
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "9fa0c885-f33d-40d2-85f7-711a671cfe6a",
"type": "order_status_transitions",
"attributes": {
"order_id": "0c9cf30c-2afc-4972-8f6b-b1bc417fccb6",
"transition_from": "reserved",
"transition_to": "draft",
"revert": true,
"confirm_shortage": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/order_status_transitions
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[order_status_transitions]=order_id,transition_from,transition_to |
include |
string List of comma seperated relationships to sideload. ?include=order |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings. This is only possible when reserving an Order. |
data[attributes][order_id] |
uuid The Order whose status is changed. |
data[attributes][revert] |
boolean Indicates if this transition reverts the Order back to an earlier status. "Earlier status" does not require this specific Order to ever have been in that status (e.g. draft can have been skipped). "Earlier" means earlier in the conceptual progressing of statuses of Orders in general. |
data[attributes][transition_from] |
enum The current status of the Order. One of: new, draft, reserved, started, stopped, archived. |
data[attributes][transition_to] |
enum The new status of the Order. It is only possible to transition to started or stopped in combination with revert: true.One of: draft, reserved, started, stopped, archived, canceled. |
Includes
This request accepts the following includes:
-
orderplanningsstock_item_plannings
Payments
Payments represent financial transactions in Booqable, including charges, authorizations, and refunds. This is a polymorphic resource that encompasses three distinct payment types, each with its own workflow and purpose.
The three payment types are:
- PaymentCharges: Direct charges for orders or carts
- PaymentAuthorizations: Pre-authorizations that can be captured later
- PaymentRefunds: Refunds for previously charged amounts
Payments can be processed through various providers:
stripe: Stripe payment processing (credit cards, etc.)app: Third-party payment apps integrated via Booqable Appsnone: Manual payments (cash, bank transfer, etc.)
Each payment tracks comprehensive financial information including the main amount, deposit amount, and total. All amounts are stored in cents to avoid floating-point precision issues.
Payment Statuses
While each payment type has its own specific statuses, common concepts include:
- Initial states like
createdindicate setup phase - Processing states like
started,action_required, orprocessing - Terminal states like
succeeded,failed,canceled, orexpired
Financial Tracking
All payment records maintain:
amount_in_cents: The main payment amount (e.g., rental charges)deposit_in_cents: The deposit portiontotal_in_cents: Always equals amount + deposit
These amounts are immutable once set to maintain financial integrity.
List payments
How to fetch a list of payments:
curl --get 'https://example.booqable.com/api/4/payments'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "d7796fe0-99e9-4f00-858b-eb3f1e28fd8f",
"type": "payment_refunds",
"attributes": {
"created_at": "2028-11-19T02:39:01.000000+00:00",
"updated_at": "2028-11-19T02:39:01.000000+00:00",
"type": "payment_refunds",
"provider": "none",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "created",
"description": null,
"failure_reason": null,
"reason": null,
"payment_charge_id": null,
"payment_method_id": null
},
"relationships": {}
},
{
"id": "d7d97872-e34d-4c76-8452-be23af13a699",
"type": "payment_authorizations",
"attributes": {
"created_at": "2028-11-19T02:39:01.000000+00:00",
"updated_at": "2028-11-19T02:39:01.000000+00:00",
"type": "payment_authorizations",
"provider": "stripe",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "created",
"mode": "request",
"description": null,
"redirect_url": null,
"capturable": false,
"amount_capturable_in_cents": 0,
"deposit_capturable_in_cents": 0,
"total_capturable_in_cents": 0,
"amount_captured_in_cents": 0,
"deposit_captured_in_cents": 0,
"total_captured_in_cents": 0,
"amount_released_in_cents": 0,
"deposit_released_in_cents": 0,
"total_released_in_cents": 0,
"captured_at": null,
"capture_before": null,
"payment_method_id": null
},
"relationships": {}
},
{
"id": "829cbadd-91ff-44e3-850b-28fb5b5dd16f",
"type": "payment_charges",
"attributes": {
"created_at": "2028-11-19T02:39:01.000000+00:00",
"updated_at": "2028-11-19T02:39:01.000000+00:00",
"type": "payment_charges",
"provider": "stripe",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "created",
"mode": "request",
"description": null,
"redirect_url": null,
"refundable": true,
"amount_refundable_in_cents": 5000,
"amount_refunded_in_cents": 0,
"deposit_refundable_in_cents": 0,
"deposit_refunded_in_cents": 0,
"total_refundable_in_cents": 5000,
"total_refunded_in_cents": 0,
"payment_method_id": null,
"payment_authorization_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/payments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payments]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=order,cart,payment_method |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
amount_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
canceled_at |
datetime eq, not_eq, gt, gte, lt, lte |
cart_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
currency |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
customer_id |
uuid eq, not_eq |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
employee_id |
uuid eq, not_eq |
expired_at |
datetime eq, not_eq, gt, gte, lt, lte |
failed_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
order_id |
uuid eq, not_eq |
provider |
enum eq |
provider_id |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
provider_link |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
provider_method |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
provider_secret |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
succeeded_at |
datetime eq, not_eq, gt, gte, lt, lte |
total_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
amount_in_cents |
array sum |
deposit_in_cents |
array sum |
total |
array count |
total_in_cents |
array sum |
Includes
This request accepts the following includes:
cartemployee-
orderpayments
payment_method
Fetch a payment
How to fetch a payment:
curl --get 'https://example.booqable.com/api/4/payments/bf92b7a9-88e9-43e2-85c0-49ff1418a448'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "bf92b7a9-88e9-43e2-85c0-49ff1418a448",
"type": "payment_charges",
"attributes": {
"created_at": "2016-06-23T23:18:00.000000+00:00",
"updated_at": "2016-06-23T23:18:00.000000+00:00",
"type": "payment_charges",
"provider": "stripe",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "created",
"mode": "request",
"description": null,
"redirect_url": null,
"refundable": true,
"amount_refundable_in_cents": 5000,
"amount_refunded_in_cents": 0,
"deposit_refundable_in_cents": 0,
"deposit_refunded_in_cents": 0,
"total_refundable_in_cents": 5000,
"total_refunded_in_cents": 0,
"payment_method_id": null,
"payment_authorization_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/payments/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payments]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,cart,payment_method |
Includes
This request accepts the following includes:
cartemployee-
orderpayments
payment_method
Payment authorizations
PaymentAuthorizations represent pre-authorized payment reservations in Booqable. They reserve funds on a customer's payment method without immediately collecting them, allowing for flexible payment collection at a later time through PaymentCharges.
PaymentAuthorizations are one of three payment types in Booqable's payment system, alongside PaymentCharges (direct charges) and PaymentRefunds (refunds). While charges immediately collect payment, authorizations only reserve funds that can be captured later, providing flexibility for rental businesses where final amounts may change.
Authorization Workflow
The typical authorization workflow follows these steps:
- Authorization Creation: Reserve funds on customer's payment method
- Funds Held: Customer sees pending charge, funds unavailable but not collected
- Capture or Release: Either capture some/all funds via PaymentCharge or let authorization expire
- Completion: Authorization marked as captured, expired, or canceled
Key Concepts
Capturable Amounts
Authorizations track what can still be captured:
amount_capturable_in_cents: Rental amount available for capturedeposit_capturable_in_cents: Deposit amount available for capturetotal_capturable_in_cents: Total available (amount + deposit)
Captured Amounts
Authorizations track what has been captured via charges:
amount_captured_in_cents: Rental amount already captureddeposit_captured_in_cents: Deposit amount already capturedtotal_captured_in_cents: Total captured (amount + deposit)
Capture Window
capture_before: Deadline for capturing funds before automatic expiration- After this time, the authorization expires and funds are released
- Typically 7 days for most payment providers
Status Lifecycle
PaymentAuthorizations follow a specific status lifecycle:
created → Initial state when authorization is created
- Can transition to:
started,action_required,canceled,expired,succeeded,failed - Set during creation based on mode
- Can transition to:
started → Authorization process has been initiated
- Can transition to:
created,action_required,succeeded,failed,expired,canceled - Indicates provider processing has begun
- Can transition to:
action_required → Customer intervention needed
- Can transition to:
created,started,succeeded,failed,expired,canceled - Common for 3D Secure authentication
- Customer must complete action to proceed
- Can transition to:
succeeded → Authorization successfully placed
- Can transition to:
captured,canceled,expired,failed - Funds are reserved and available for capture
- Sets
succeeded_attimestamp
- Can transition to:
failed → Authorization attempt failed
- Can transition to:
created,started,succeeded - Allows retry by transitioning back to earlier states
- Sets
failed_attimestamp
- Can transition to:
canceled → Authorization was canceled
- Can transition to:
succeeded,failed(for late completions) - Releases reserved funds back to customer
- Sets
canceled_attimestamp
- Can transition to:
expired → Authorization expired without capture
- Can transition to:
succeeded,failed(for late processing) - Automatically set when
capture_beforepasses - Releases reserved funds back to customer
- Sets
expired_attimestamp
- Can transition to:
captured → Authorization fully or partially captured
- Can transition to:
failed(for corrections only) - Set when PaymentCharge captures from this authorization
- Indicates at least partial funds were collected
- Can transition to:
Payment Modes
Different modes control how the authorization is created:
off_session: Merchant-initiated without customer presentcheckout: Part of checkout flow, customer presentrequest: On-demand request, often for additional chargesterminal: Physical payment terminal transaction
Capture Capabilities
Successful authorizations can be partially or fully captured via PaymentCharges. The authorization tracks:
- How much has been captured (
amount_captured_in_cents,deposit_captured_in_cents) - How much is still capturable (
amount_capturable_in_cents,deposit_capturable_in_cents) - Whether any amount remains capturable (
capturable)
Captures are created as separate PaymentCharge records linked to the original authorization.
Relationships
| Name | Description |
|---|---|
cart |
Cart requiredThe Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
customer |
Customer requiredThe Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
employee |
Employee requiredThe Employee who created or processed this payment. Automatically set by the system and cannot be modified through the API. |
order |
Order requiredThe Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
payment_charges |
Payment charges hasmanyThe PaymentCharges that capture funds from this authorization. A charge reduces the capturable amounts and the authorization becomes non-capturable. |
payment_method |
Payment method requiredThe PaymentMethod used for this authorization. Links to the saved customer payment details (like a specific card) being authorized. Required for off_session mode where saved payment methods are charged without customer presence. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
amount_capturable_in_cents |
integer readonlyRental amount still available for capture in cents. Starts equal to amount_in_cents and decreases as PaymentCharges capture funds. When fully captured, this becomes zero. |
amount_captured_in_cents |
integer readonlyRental amount already captured via PaymentCharges in cents. Starts at zero and increases as charges capture funds. Cannot exceed the original amount_in_cents. |
amount_in_cents |
integer The rental amount to authorize in cents. This represents the main charge amount excluding any deposit. Set during creation and cannot be changed. Combined with deposit_in_cents to determine total authorization. |
amount_released_in_cents |
integer readonlyRental amount that was not captured in cents. Calculated as the difference between the original amount_in_cents and amount_captured_in_cents. This represents funds that were authorized but ultimately not collected from the customer. |
canceled_at |
datetime readonlyTimestamp when the authorization was canceled, releasing any reserved funds back to the customer. Authorizations cannot be canceled after being captured. |
capturable |
boolean readonlyWhether this authorization can currently be captured. True when status is succeeded and the authorization hasn't expired. When false, attempts to create PaymentCharges from this authorization will fail. |
capture_before |
datetime readonlyDeadline for capturing this authorization before it automatically expires. After this time, reserved funds are released back to the customer. Typically 7 days after creation but varies by payment provider. |
captured_at |
datetime readonlyTimestamp when the authorization was first captured via a PaymentCharge. Once captured, the authorization cannot be canceled and capturable amounts are adjusted based on what was captured. |
cart_id |
uuid readonly-after-createThe Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
created_at |
datetime readonlyWhen the resource was created. |
currency |
string Three-letter ISO 4217 currency code (e.g., USD, EUR). Must match the currency of any associated order or cart. Set during creation and cannot be changed. |
customer_id |
uuid readonly-after-createThe Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
deposit_capturable_in_cents |
integer readonlyDeposit amount still available for capture in cents. Starts equal to deposit_in_cents and decreases as PaymentCharges capture funds. When fully captured, this becomes zero. |
deposit_captured_in_cents |
integer readonlyDeposit amount already captured via PaymentCharges in cents. Starts at zero and increases as charges capture funds. Cannot exceed the original deposit_in_cents. |
deposit_in_cents |
integer The deposit amount to authorize in cents. This represents the security deposit for the rental. Set during creation and cannot be changed. Combined with amount_in_cents to determine total authorization. |
deposit_released_in_cents |
integer readonlyDeposit amount that was not captured in cents. Calculated as the difference between the original deposit_in_cents and deposit_captured_in_cents. This represents deposit funds that were authorized but ultimately not collected from the customer. |
description |
string Human-readable description of what this authorization is for. Useful for displaying to customers on statements or in payment interfaces. Often includes order or rental details. |
employee_id |
uuid readonlyThe Employee who created or processed this payment. Automatically set by the system and cannot be modified through the API. |
expired_at |
datetime readonlyTimestamp when the authorization expired without being captured. Expiration releases reserved funds back to the customer. Usually occurs when capture_before is reached. |
failed_at |
datetime readonlyTimestamp when the authorization attempt failed. Failed authorizations can be retried by transitioning back to created or started status. |
id |
uuid readonlyPrimary key. |
mode |
enum How the authorization is created and processed. Each mode has different validation requirements and processing flows. One of: off_session, checkout, request, terminal.off_session - Merchant-initiated without customer presentcheckout - Part of checkout flow, customer presentrequest - On-demand request, often for additional chargesterminal - Physical payment terminal transaction |
order_id |
uuid readonly-after-createThe Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
payment_method_id |
uuid readonly-after-createThe PaymentMethod used for this authorization. Links to the saved customer payment details (like a specific card) being authorized. Required for off_session mode where saved payment methods are charged without customer presence. |
provider |
enum The payment service provider that processes this authorization. Determines which provider-specific implementation is used for authorization and capture operations. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - No payment provider (typically for manual mode) |
provider_id |
string External identifier from the payment provider for this authorization. For Stripe authorizations, this contains the PaymentIntent ID. Used for syncing status updates and debugging provider-specific issues. |
provider_link |
string Direct URL to view this authorization in the payment provider's dashboard. Useful for support teams to investigate issues or view detailed transaction information not available in Booqable. |
provider_method |
string The payment method type used at the provider level, such as card, ideal, or bancontact. This indicates how the customer's payment method is processed by the provider. |
provider_secret |
string Secret value used for secure client-side payment flows. For Stripe, this is the client secret allowing customer's browser to directly communicate with Stripe for authentication. This value is write-only for security. |
redirect_url |
string URL to redirect the customer after completing any required authentication or action. Used in checkout flows to return customers to the appropriate success or failure page after interacting with the payment provider. |
status |
enum Current status of the authorization in its lifecycle. Determines available actions and whether funds can be captured. One of: created, started, action_required, succeeded, failed, canceled, expired, captured. |
succeeded_at |
datetime Timestamp when the authorization was successfully placed and funds were reserved. Once set, the authorization can be captured until it expires or is canceled. |
total_capturable_in_cents |
integer readonlyTotal amount still available for capture in cents (amount + deposit). This is the maximum that can be collected via new PaymentCharges against this authorization. |
total_captured_in_cents |
integer readonlyTotal amount already captured via PaymentCharges in cents (amount + deposit). When this equals total_in_cents, the authorization is fully captured. |
total_in_cents |
integer Total amount authorized in cents (amount + deposit). This is the full amount reserved on the customer's payment method. Set during creation and cannot be changed. |
total_released_in_cents |
integer readonlyTotal amount that was not captured in cents (amount + deposit). This represents the portion of the original authorization that was released back to the customer. Updated when captures are applied to reflect the uncaptured portion. |
type |
string readonlyAlways returns payment_authorizations to identify this PaymentAuthorization resource. |
updated_at |
datetime readonlyWhen the resource was last updated. |
Create a payment authorization
How to create a payment authorization:
curl --request POST
--url 'https://example.booqable.com/api/4/payment_authorizations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "payment_authorizations",
"attributes": {
"mode": "request",
"amount_in_cents": 10000,
"deposit_in_cents": 5000
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "8aaa4100-cf5f-4fa4-80ba-fe3f05745629",
"type": "payment_authorizations",
"attributes": {
"created_at": "2018-07-05T22:55:03.000000+00:00",
"updated_at": "2018-07-05T22:55:03.000000+00:00",
"type": "payment_authorizations",
"provider": null,
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 10000,
"deposit_in_cents": 5000,
"total_in_cents": 15000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": "c6505e37-c8ba-4ebf-8345-3c74edbd6182",
"customer_id": null,
"status": "created",
"mode": "request",
"description": null,
"redirect_url": null,
"capturable": false,
"amount_capturable_in_cents": 0,
"deposit_capturable_in_cents": 0,
"total_capturable_in_cents": 0,
"amount_captured_in_cents": 0,
"deposit_captured_in_cents": 0,
"total_captured_in_cents": 0,
"amount_released_in_cents": 0,
"deposit_released_in_cents": 0,
"total_released_in_cents": 0,
"captured_at": null,
"capture_before": null,
"payment_method_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/payment_authorizations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_authorizations]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,customer,employee |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer The rental amount to authorize in cents. This represents the main charge amount excluding any deposit. Set during creation and cannot be changed. Combined with deposit_in_cents to determine total authorization. |
data[attributes][cart_id] |
uuid The Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
data[attributes][currency] |
string Three-letter ISO 4217 currency code (e.g., USD, EUR). Must match the currency of any associated order or cart. Set during creation and cannot be changed. |
data[attributes][customer_id] |
uuid The Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
data[attributes][deposit_in_cents] |
integer The deposit amount to authorize in cents. This represents the security deposit for the rental. Set during creation and cannot be changed. Combined with amount_in_cents to determine total authorization. |
data[attributes][mode] |
enum How the authorization is created and processed. Each mode has different validation requirements and processing flows. One of: off_session, checkout, request, terminal.off_session - Merchant-initiated without customer presentcheckout - Part of checkout flow, customer presentrequest - On-demand request, often for additional chargesterminal - Physical payment terminal transaction |
data[attributes][order_id] |
uuid The Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
data[attributes][payment_method_id] |
uuid The PaymentMethod used for this authorization. Links to the saved customer payment details (like a specific card) being authorized. Required for off_session mode where saved payment methods are charged without customer presence. |
data[attributes][provider] |
enum The payment service provider that processes this authorization. Determines which provider-specific implementation is used for authorization and capture operations. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - No payment provider (typically for manual mode) |
data[attributes][provider_id] |
string External identifier from the payment provider for this authorization. For Stripe authorizations, this contains the PaymentIntent ID. Used for syncing status updates and debugging provider-specific issues. |
data[attributes][provider_link] |
string Direct URL to view this authorization in the payment provider's dashboard. Useful for support teams to investigate issues or view detailed transaction information not available in Booqable. |
data[attributes][provider_method] |
string The payment method type used at the provider level, such as card, ideal, or bancontact. This indicates how the customer's payment method is processed by the provider. |
data[attributes][provider_secret] |
string Secret value used for secure client-side payment flows. For Stripe, this is the client secret allowing customer's browser to directly communicate with Stripe for authentication. This value is write-only for security. |
data[attributes][redirect_url] |
string URL to redirect the customer after completing any required authentication or action. Used in checkout flows to return customers to the appropriate success or failure page after interacting with the payment provider. |
data[attributes][status] |
enum Current status of the authorization in its lifecycle. Determines available actions and whether funds can be captured. One of: created, started, action_required, succeeded, failed, canceled, expired, captured. |
data[attributes][succeeded_at] |
datetime Timestamp when the authorization was successfully placed and funds were reserved. Once set, the authorization can be captured until it expires or is canceled. |
data[attributes][total_in_cents] |
integer Total amount authorized in cents (amount + deposit). This is the full amount reserved on the customer's payment method. Set during creation and cannot be changed. |
Includes
This request accepts the following includes:
customeremployee-
orderpayments
payment_chargespayment_method
Update a payment authorization
How to update a payment authorization:
curl --request PUT
--url 'https://example.booqable.com/api/4/payment_authorizations/1ed150c8-95c1-4995-84f1-2d34064f48ed'
--header 'content-type: application/json'
--data '{
"data": {
"id": "1ed150c8-95c1-4995-84f1-2d34064f48ed",
"type": "payment_authorizations",
"attributes": {
"status": "started",
"provider": "stripe",
"provider_method": "card"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "1ed150c8-95c1-4995-84f1-2d34064f48ed",
"type": "payment_authorizations",
"attributes": {
"created_at": "2018-11-07T01:48:04.000000+00:00",
"updated_at": "2018-11-07T01:48:04.000000+00:00",
"type": "payment_authorizations",
"provider": "stripe",
"provider_id": null,
"provider_method": "card",
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "started",
"mode": "request",
"description": null,
"redirect_url": null,
"capturable": false,
"amount_capturable_in_cents": 0,
"deposit_capturable_in_cents": 0,
"total_capturable_in_cents": 0,
"amount_captured_in_cents": 0,
"deposit_captured_in_cents": 0,
"total_captured_in_cents": 0,
"amount_released_in_cents": 0,
"deposit_released_in_cents": 0,
"total_released_in_cents": 0,
"captured_at": null,
"capture_before": null,
"payment_method_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/payment_authorizations/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_authorizations]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,customer,employee |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer The rental amount to authorize in cents. This represents the main charge amount excluding any deposit. Set during creation and cannot be changed. Combined with deposit_in_cents to determine total authorization. |
data[attributes][cart_id] |
uuid The Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
data[attributes][currency] |
string Three-letter ISO 4217 currency code (e.g., USD, EUR). Must match the currency of any associated order or cart. Set during creation and cannot be changed. |
data[attributes][customer_id] |
uuid The Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
data[attributes][deposit_in_cents] |
integer The deposit amount to authorize in cents. This represents the security deposit for the rental. Set during creation and cannot be changed. Combined with amount_in_cents to determine total authorization. |
data[attributes][mode] |
enum How the authorization is created and processed. Each mode has different validation requirements and processing flows. One of: off_session, checkout, request, terminal.off_session - Merchant-initiated without customer presentcheckout - Part of checkout flow, customer presentrequest - On-demand request, often for additional chargesterminal - Physical payment terminal transaction |
data[attributes][order_id] |
uuid The Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
data[attributes][payment_method_id] |
uuid The PaymentMethod used for this authorization. Links to the saved customer payment details (like a specific card) being authorized. Required for off_session mode where saved payment methods are charged without customer presence. |
data[attributes][provider] |
enum The payment service provider that processes this authorization. Determines which provider-specific implementation is used for authorization and capture operations. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - No payment provider (typically for manual mode) |
data[attributes][provider_id] |
string External identifier from the payment provider for this authorization. For Stripe authorizations, this contains the PaymentIntent ID. Used for syncing status updates and debugging provider-specific issues. |
data[attributes][provider_link] |
string Direct URL to view this authorization in the payment provider's dashboard. Useful for support teams to investigate issues or view detailed transaction information not available in Booqable. |
data[attributes][provider_method] |
string The payment method type used at the provider level, such as card, ideal, or bancontact. This indicates how the customer's payment method is processed by the provider. |
data[attributes][provider_secret] |
string Secret value used for secure client-side payment flows. For Stripe, this is the client secret allowing customer's browser to directly communicate with Stripe for authentication. This value is write-only for security. |
data[attributes][redirect_url] |
string URL to redirect the customer after completing any required authentication or action. Used in checkout flows to return customers to the appropriate success or failure page after interacting with the payment provider. |
data[attributes][status] |
enum Current status of the authorization in its lifecycle. Determines available actions and whether funds can be captured. One of: created, started, action_required, succeeded, failed, canceled, expired, captured. |
data[attributes][succeeded_at] |
datetime Timestamp when the authorization was successfully placed and funds were reserved. Once set, the authorization can be captured until it expires or is canceled. |
data[attributes][total_in_cents] |
integer Total amount authorized in cents (amount + deposit). This is the full amount reserved on the customer's payment method. Set during creation and cannot be changed. |
Includes
This request accepts the following includes:
customeremployee-
orderpayments
payment_chargespayment_method
Payment charges
PaymentCharges represent direct financial charges in Booqable. They are used to collect payments from customers for orders or carts, either immediately or through various payment flows.
PaymentCharges are one of three payment types in Booqable's payment system, alongside PaymentAuthorizations (pre-authorizations) and PaymentRefunds (refunds). While authorizations reserve funds for later capture, charges immediately collect payment from the customer.
Status Lifecycle
PaymentCharges follow a status lifecycle with specific transition rules and triggers:
Status Lifecycle
PaymentCharges follow a specific status lifecycle:
created → Initial state when a charge is created
- Can transition to:
started,action_required,canceled,expired,succeeded,failed - Set during creation via mode-specific interactors
- For Stripe charges, a payment intent is pre-created at this stage
- Can transition to:
started → Payment process has been initiated
- Can transition to:
created,action_required,processing,succeeded,failed,expired,canceled - Triggered when provider and payment method are set
- Can transition to:
action_required → Customer intervention needed
- Can transition to:
created,started,processing,succeeded,failed,expired,canceled - Common for 3D Secure authentication or additional verification
- Customer must complete action before payment can proceed
- Can transition to:
processing → Payment is being processed by provider
- Can transition to:
succeeded,failed,action_required - Indicates payment is in provider's processing queue
- Typically a brief transitional state
- Can transition to:
succeeded → Payment successfully collected
- Can transition to:
failed(for corrections only) - Sets
succeeded_attimestamp and enables refunds - Captures authorization if charge was created from one
- Triggers order creation for checkout mode charges
- Can transition to:
failed → Payment attempt failed
- Can transition to:
created,started,succeeded(recovery paths) - Sets
failed_attimestamp - Allows retry by transitioning back to earlier states
- Can transition to:
canceled → Charge was canceled
- Can transition to:
succeeded,failed(for late completions) - Sets
canceled_attimestamp - Cancels payment intent/app charge if exists
- Cannot cancel after charge has succeeded
- Can transition to:
expired → Charge expired due to timeout
- Can transition to:
succeeded,failed(for late processing) - Sets
expired_attimestamp - Triggered automatically by background job after timeout period
- Can transition to:
Status Transition Rules
- Transitions are validated at the model level - invalid transitions raise validation errors
- Some transitions are restricted based on provider type (e.g., manual payments have limited transitions)
- Late transitions (succeeded/failed after canceled/expired) are allowed for provider corrections
Payment Modes
Different modes control how the charge is processed:
manual: Direct charge with no automated processingoff_session: Charge saved payment method without customer presentrequest: Send payment request to customerterminal: Process through physical payment terminalcapture: Capture funds from existing authorization
Refund Capabilities
Successful charges can be partially or fully refunded through PaymentRefunds. The charge tracks:
- How much has been refunded (
amount_refunded_in_cents,deposit_refunded_in_cents) - How much is still refundable (
amount_refundable_in_cents,deposit_refundable_in_cents) - Whether any amount remains refundable (
refundable)
Refunds are created as separate PaymentRefund records linked to the original charge.
Relationships
| Name | Description |
|---|---|
cart |
Cart requiredThe Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
customer |
Customer requiredThe Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
employee |
Employee requiredThe Employee who created or processed this payment. Automatically set by the system and cannot be modified through the API. |
order |
Order requiredThe Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
payment_authorization |
Payment authorization requiredThe PaymentAuthorization this charge captures from. Only present for charges with mode capture. Links to the authorization that reserved the funds being captured. The authorization must have sufficient authorized amount to cover this charge.Only settable during creation and required when mode is capture. |
payment_method |
Payment method requiredThe PaymentMethod used for this charge. Can be an existing saved payment method (for off_session mode) or a new method created during payment. The payment method stores the actual payment credentials or reference.For charges using saved methods, this must be a valid method belonging to the customer. Only settable during creation. |
payment_refunds |
Payment refunds hasmanyThe PaymentRefunds issued against this charge. Collection of all refunds that have been processed for this charge. Each refund reduces the refundable amounts and increases the refunded amounts. Refunds can only be created for charges with status succeeded.Use this to track refund history and calculate total amounts refunded. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
amount_in_cents |
integer Main charge amount in cents (excluding deposit). This typically represents the rental charges, services, or products. Must be non-negative and cannot be changed after creation. |
amount_refundable_in_cents |
integer readonlyRemaining main amount that can still be refunded in cents. Starts equal to amount_in_cents for succeeded charges and decreases as refunds are processed. |
amount_refunded_in_cents |
integer readonlyTotal main amount already refunded in cents. Sum of all refund amounts applied to the main charge amount. Increases as refunds are processed. |
canceled_at |
datetime readonlyTimestamp when the charge was canceled. Will be null for charges that haven't been canceled. Charges can be canceled before completion, but not after they've succeeded. |
cart_id |
uuid readonly-after-createThe Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
created_at |
datetime readonlyWhen the resource was created. |
currency |
string Three-letter ISO 4217 currency code (e.g., USD, EUR).All amounts for this charge are in this currency. Must match the currency of the associated order or cart. |
customer_id |
uuid readonly-after-createThe Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
deposit_in_cents |
integer Deposit amount in cents. Deposits are held separately from the main amount and may have different refund rules. Cannot be changed after creation. |
deposit_refundable_in_cents |
integer readonlyRemaining deposit amount that can still be refunded in cents. Starts equal to deposit_in_cents for succeeded charges and decreases as deposit refunds are processed. |
deposit_refunded_in_cents |
integer readonlyTotal deposit amount already refunded in cents. Sum of all refund amounts applied to the deposit. Increases as deposit refunds are processed. |
description |
string Optional description for this charge that can be displayed to customers. Use this to provide context about what the charge is for, especially for partial payments or custom amounts. |
employee_id |
uuid readonlyThe Employee who created or processed this payment. Automatically set by the system and cannot be modified through the API. |
expired_at |
datetime readonlyTimestamp when the charge expired. Will be null for charges that haven't expired. Charges may expire if not completed within the provider's time limit. |
failed_at |
datetime readonlyTimestamp when the charge failed. Will be null for charges that haven't failed. Charges can fail due to insufficient funds, declined cards, or other payment processing issues. |
id |
uuid readonlyPrimary key. |
mode |
enum How the payment is collected. The mode determines the payment flow and cannot be changed after creation. One of: manual, off_session, request, terminal, capture.manual - Direct charge with manual payment marking (e.g., cash, bank transfer)off_session - Charge a saved payment method without customer interactionrequest - Send a payment request to the customerterminal - Process through a physical payment terminalcapture - Capture funds from an existing PaymentAuthorization |
order_id |
uuid readonly-after-createThe Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
payment_authorization_id |
uuid readonly-after-createThe PaymentAuthorization this charge captures from. Only present for charges with mode capture. Links to the authorization that reserved the funds being captured. The authorization must have sufficient authorized amount to cover this charge.Only settable during creation and required when mode is capture. |
payment_method_id |
uuid readonly-after-createThe PaymentMethod used for this charge. Can be an existing saved payment method (for off_session mode) or a new method created during payment. The payment method stores the actual payment credentials or reference.For charges using saved methods, this must be a valid method belonging to the customer. Only settable during creation. |
provider |
enum The payment service provider used to process this charge. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - No payment provider (typically for manual mode)For app providers, additional details are available in provider_app. |
provider_id |
string Unique identifier from the payment provider (e.g., Stripe charge ID). Use this to reconcile with external payment systems or for support inquiries with the payment provider. |
provider_link |
string Direct link to view this payment in the provider's dashboard. Useful for support staff to quickly access payment details in the external system. |
provider_method |
string The payment method type used for this charge (e.g., card, ideal, bancontact).Available methods depend on the provider and its configuration. |
provider_secret |
string Secret token used for client-side payment processing. For Stripe, this includes the client secret needed for Payment Element or confirmCardPayment. |
redirect_url |
string URL to redirect the customer to after payment completion. The customer will be redirected here after successful payment, failure, or cancellation. Include any necessary parameters to identify the order or context. |
refundable |
boolean readonlyWhether this charge can still be refunded. Returns true if total_refundable_in_cents is greater than zero. Only succeeded charges can be refunded. |
status |
enum Current status of the charge in its lifecycle. One of: created, started, action_required, processing, succeeded, failed, canceled, expired.Status transitions follow specific rules - for example, a charge can move from created to started, but not directly to succeeded without going through processing. |
succeeded_at |
datetime Timestamp when the charge successfully completed. Will be null for charges that haven't succeeded yet. Once set, the charge is considered successful and funds have been collected. |
total_in_cents |
integer Total charge amount in cents. Always equals amount_in_cents + deposit_in_cents. This is the total amount the customer will be charged. |
total_refundable_in_cents |
integer readonlyTotal amount still available for refund in cents. Always equals amount_refundable_in_cents + deposit_refundable_in_cents. Use this to check maximum refund amount. |
total_refunded_in_cents |
integer readonlyTotal amount already refunded in cents. Always equals amount_refunded_in_cents + deposit_refunded_in_cents. Tracks the complete refund history. |
type |
string readonlyAlways returns payment_charges.To retrieve charges along with other payment types, use the Payments endpoint which returns all payment types. |
updated_at |
datetime readonlyWhen the resource was last updated. |
Create a payment charge
How to create a payment charge:
curl --request POST
--url 'https://example.booqable.com/api/4/payment_charges'
--header 'content-type: application/json'
--data '{
"data": {
"type": "payment_charges",
"attributes": {
"mode": "manual",
"provider": "none",
"amount_in_cents": 10000,
"deposit_in_cents": 5000
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "173c372c-a487-4900-843d-17ca3a33c915",
"type": "payment_charges",
"attributes": {
"created_at": "2023-02-26T05:02:01.000000+00:00",
"updated_at": "2023-02-26T05:02:01.000000+00:00",
"type": "payment_charges",
"provider": "none",
"provider_id": null,
"provider_method": "bank",
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 10000,
"deposit_in_cents": 5000,
"total_in_cents": 15000,
"currency": "usd",
"succeeded_at": "2023-02-26T05:02:01.000000+00:00",
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": "7dd1d262-ea22-442d-8f2b-551256cde93a",
"customer_id": null,
"status": "succeeded",
"mode": "manual",
"description": null,
"redirect_url": null,
"refundable": true,
"amount_refundable_in_cents": 10000,
"amount_refunded_in_cents": 0,
"deposit_refundable_in_cents": 5000,
"deposit_refunded_in_cents": 0,
"total_refundable_in_cents": 15000,
"total_refunded_in_cents": 0,
"payment_method_id": null,
"payment_authorization_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/payment_charges
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_charges]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,cart,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer Main charge amount in cents (excluding deposit). This typically represents the rental charges, services, or products. Must be non-negative and cannot be changed after creation. |
data[attributes][cart_id] |
uuid The Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
data[attributes][currency] |
string Three-letter ISO 4217 currency code (e.g., USD, EUR).All amounts for this charge are in this currency. Must match the currency of the associated order or cart. |
data[attributes][customer_id] |
uuid The Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
data[attributes][deposit_in_cents] |
integer Deposit amount in cents. Deposits are held separately from the main amount and may have different refund rules. Cannot be changed after creation. |
data[attributes][mode] |
enum How the payment is collected. The mode determines the payment flow and cannot be changed after creation. One of: manual, off_session, request, terminal, capture.manual - Direct charge with manual payment marking (e.g., cash, bank transfer)off_session - Charge a saved payment method without customer interactionrequest - Send a payment request to the customerterminal - Process through a physical payment terminalcapture - Capture funds from an existing PaymentAuthorization |
data[attributes][order_id] |
uuid The Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
data[attributes][payment_authorization_id] |
uuid The PaymentAuthorization this charge captures from. Only present for charges with mode capture. Links to the authorization that reserved the funds being captured. The authorization must have sufficient authorized amount to cover this charge.Only settable during creation and required when mode is capture. |
data[attributes][payment_method_id] |
uuid The PaymentMethod used for this charge. Can be an existing saved payment method (for off_session mode) or a new method created during payment. The payment method stores the actual payment credentials or reference.For charges using saved methods, this must be a valid method belonging to the customer. Only settable during creation. |
data[attributes][provider] |
enum The payment service provider used to process this charge. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - No payment provider (typically for manual mode)For app providers, additional details are available in provider_app. |
data[attributes][provider_id] |
string Unique identifier from the payment provider (e.g., Stripe charge ID). Use this to reconcile with external payment systems or for support inquiries with the payment provider. |
data[attributes][provider_link] |
string Direct link to view this payment in the provider's dashboard. Useful for support staff to quickly access payment details in the external system. |
data[attributes][provider_method] |
string The payment method type used for this charge (e.g., card, ideal, bancontact).Available methods depend on the provider and its configuration. |
data[attributes][provider_secret] |
string Secret token used for client-side payment processing. For Stripe, this includes the client secret needed for Payment Element or confirmCardPayment. |
data[attributes][redirect_url] |
string URL to redirect the customer to after payment completion. The customer will be redirected here after successful payment, failure, or cancellation. Include any necessary parameters to identify the order or context. |
data[attributes][status] |
enum Current status of the charge in its lifecycle. One of: created, started, action_required, processing, succeeded, failed, canceled, expired.Status transitions follow specific rules - for example, a charge can move from created to started, but not directly to succeeded without going through processing. |
data[attributes][succeeded_at] |
datetime Timestamp when the charge successfully completed. Will be null for charges that haven't succeeded yet. Once set, the charge is considered successful and funds have been collected. |
data[attributes][total_in_cents] |
integer Total charge amount in cents. Always equals amount_in_cents + deposit_in_cents. This is the total amount the customer will be charged. |
Includes
This request accepts the following includes:
cartcustomeremployee-
orderdocumentspayments
payment_authorizationpayment_methodpayment_refunds
Update a payment charge
How to update a payment charge:
curl --request PUT
--url 'https://example.booqable.com/api/4/payment_charges/04972b14-5348-4e61-8896-e61e346e3001'
--header 'content-type: application/json'
--data '{
"data": {
"id": "04972b14-5348-4e61-8896-e61e346e3001",
"type": "payment_charges",
"attributes": {
"status": "started",
"provider": "stripe",
"provider_method": "card"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "04972b14-5348-4e61-8896-e61e346e3001",
"type": "payment_charges",
"attributes": {
"created_at": "2015-05-19T14:36:00.000000+00:00",
"updated_at": "2015-05-19T14:36:00.000000+00:00",
"type": "payment_charges",
"provider": "stripe",
"provider_id": null,
"provider_method": "card",
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "started",
"mode": "request",
"description": null,
"redirect_url": null,
"refundable": true,
"amount_refundable_in_cents": 5000,
"amount_refunded_in_cents": 0,
"deposit_refundable_in_cents": 0,
"deposit_refunded_in_cents": 0,
"total_refundable_in_cents": 5000,
"total_refunded_in_cents": 0,
"payment_method_id": null,
"payment_authorization_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/payment_charges/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_charges]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,cart,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer Main charge amount in cents (excluding deposit). This typically represents the rental charges, services, or products. Must be non-negative and cannot be changed after creation. |
data[attributes][cart_id] |
uuid The Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
data[attributes][currency] |
string Three-letter ISO 4217 currency code (e.g., USD, EUR).All amounts for this charge are in this currency. Must match the currency of the associated order or cart. |
data[attributes][customer_id] |
uuid The Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
data[attributes][deposit_in_cents] |
integer Deposit amount in cents. Deposits are held separately from the main amount and may have different refund rules. Cannot be changed after creation. |
data[attributes][mode] |
enum How the payment is collected. The mode determines the payment flow and cannot be changed after creation. One of: manual, off_session, request, terminal, capture.manual - Direct charge with manual payment marking (e.g., cash, bank transfer)off_session - Charge a saved payment method without customer interactionrequest - Send a payment request to the customerterminal - Process through a physical payment terminalcapture - Capture funds from an existing PaymentAuthorization |
data[attributes][order_id] |
uuid The Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
data[attributes][payment_authorization_id] |
uuid The PaymentAuthorization this charge captures from. Only present for charges with mode capture. Links to the authorization that reserved the funds being captured. The authorization must have sufficient authorized amount to cover this charge.Only settable during creation and required when mode is capture. |
data[attributes][payment_method_id] |
uuid The PaymentMethod used for this charge. Can be an existing saved payment method (for off_session mode) or a new method created during payment. The payment method stores the actual payment credentials or reference.For charges using saved methods, this must be a valid method belonging to the customer. Only settable during creation. |
data[attributes][provider] |
enum The payment service provider used to process this charge. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - No payment provider (typically for manual mode)For app providers, additional details are available in provider_app. |
data[attributes][provider_id] |
string Unique identifier from the payment provider (e.g., Stripe charge ID). Use this to reconcile with external payment systems or for support inquiries with the payment provider. |
data[attributes][provider_link] |
string Direct link to view this payment in the provider's dashboard. Useful for support staff to quickly access payment details in the external system. |
data[attributes][provider_method] |
string The payment method type used for this charge (e.g., card, ideal, bancontact).Available methods depend on the provider and its configuration. |
data[attributes][provider_secret] |
string Secret token used for client-side payment processing. For Stripe, this includes the client secret needed for Payment Element or confirmCardPayment. |
data[attributes][redirect_url] |
string URL to redirect the customer to after payment completion. The customer will be redirected here after successful payment, failure, or cancellation. Include any necessary parameters to identify the order or context. |
data[attributes][status] |
enum Current status of the charge in its lifecycle. One of: created, started, action_required, processing, succeeded, failed, canceled, expired.Status transitions follow specific rules - for example, a charge can move from created to started, but not directly to succeeded without going through processing. |
data[attributes][succeeded_at] |
datetime Timestamp when the charge successfully completed. Will be null for charges that haven't succeeded yet. Once set, the charge is considered successful and funds have been collected. |
data[attributes][total_in_cents] |
integer Total charge amount in cents. Always equals amount_in_cents + deposit_in_cents. This is the total amount the customer will be charged. |
Includes
This request accepts the following includes:
cartcustomeremployee-
orderdocumentspayments
payment_authorizationpayment_methodpayment_refunds
Delete a payment charge
How to delete a payment charge:
curl --request DELETE
--url 'https://example.booqable.com/api/4/payment_charges/06860f88-3205-482e-82da-5ef680030bd4'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "06860f88-3205-482e-82da-5ef680030bd4",
"type": "payment_charges",
"attributes": {
"created_at": "2025-12-21T22:55:00.000000+00:00",
"updated_at": "2025-12-21T22:55:00.000000+00:00",
"type": "payment_charges",
"provider": "stripe",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "created",
"mode": "manual",
"description": null,
"redirect_url": null,
"refundable": true,
"amount_refundable_in_cents": 5000,
"amount_refunded_in_cents": 0,
"deposit_refundable_in_cents": 0,
"deposit_refunded_in_cents": 0,
"total_refundable_in_cents": 5000,
"total_refunded_in_cents": 0,
"payment_method_id": null,
"payment_authorization_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/payment_charges/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_charges]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,cart,customer |
Includes
This request accepts the following includes:
cartcustomeremployee-
orderdocumentspayments
payment_authorizationpayment_methodpayment_refunds
Payment methods
PaymentMethods represent stored payment details that can be used for charging customers. They store tokenized payment information from providers like Stripe, enabling secure off-session payments without requiring customers to re-enter payment details.
PaymentMethods are typically created when customers save their payment information during checkout or through payment provider flows. They maintain a secure reference to the actual payment details stored with the payment provider, never storing sensitive card numbers or bank details directly.
Provider Integration
PaymentMethods work with different payment providers:
- Stripe: Tokenized cards and other Stripe payment methods
- App: Internal payment methods managed by the application (not currently supported)
Each PaymentMethod stores provider-specific details and identifiers that allow Booqable to charge the payment method through the provider's API.
Status Management
PaymentMethods have a status indicating their readiness:
created: Initial state when first createdready: Verified and ready for use in payments
The status typically transitions to ready after provider verification or when explicitly marked
as ready by the payment flow.
Customer Association
PaymentMethods belong to Customers and represent payment options available for that specific customer. A customer can have multiple PaymentMethods, allowing them to choose between different cards or payment options when paying.
Labels and Display
PaymentMethods include customizable labels:
label_primary: Main display label (e.g., "Visa ending in 4242")label_secondary: Additional information (e.g., "Expires 12/2025")
These labels help customers identify their saved payment methods in the interface. If not provided, they may be automatically generated based on the payment method details.
Relationships
| Name | Description |
|---|---|
customer |
Customer optionalThe Customer who owns this payment method. PaymentMethods must belong to a customer to be created (required for Stripe payment methods). When a PaymentMethod is detached (via DELETE endpoint), this relationship is removed, effectively disabling the payment method for future use while preserving the historical record. The customer relationship can only be set during creation and can only be removed through the detach operation. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen the resource was created. |
customer_id |
uuid readonly-after-create nullableThe Customer who owns this payment method. PaymentMethods must belong to a customer to be created (required for Stripe payment methods). When a PaymentMethod is detached (via DELETE endpoint), this relationship is removed, effectively disabling the payment method for future use while preserving the historical record. The customer relationship can only be set during creation and can only be removed through the detach operation. |
details |
hash readonly-after-createProvider-specific details about the payment method stored as a JSON object. The structure and contents vary by provider and method type. For cards, this might include card brand, last four digits, expiration date, and card network metadata. This data is typically populated automatically from provider webhooks or API responses and provides additional context about the payment method without containing sensitive data. |
id |
uuid readonlyPrimary key. |
identifier |
string readonly-after-createUnique identifier for the payment method from the provider's system. For Stripe, this would be the Stripe payment method ID (e.g., "pm_1234567890"). For app payment methods, this could be an internal reference. This identifier is used to reference the actual payment details stored securely with the provider and cannot be changed after creation. |
label_primary |
string Primary label for displaying the payment method to customers. This is typically the card brand and last four digits (e.g., "Visa •••• 4242") or a custom name given by the customer. If not provided during creation, this may be automatically generated based on the payment method details from the provider. Can be updated after creation to provide custom labeling. |
label_secondary |
string Secondary label providing additional information about the payment method. Often contains the expiration date for cards (e.g., "Expires 12/2025") or other relevant details. Like the primary label, this can be automatically generated or customized. Useful for helping customers distinguish between multiple similar payment methods. |
method_type |
string readonly-after-createThe type of payment method, indicating what kind of payment instrument this represents. Common values include card for credit/debit cards, though the specific values depend on the provider's supported payment types.This helps determine what kind of payment flow and validations apply. Cannot be changed after creation as it represents the fundamental type of the payment instrument. |
provider |
enum readonly-after-createThe payment service provider for this payment method. Determines how the payment method will be processed and which provider-specific features are available. One of: stripe, app, none.stripe - Stripe payment method using tokenized card or bank detailsapp - Internal application-managed payment methodnone - No provider, used for manual payment trackingThis value cannot be changed after creation as it fundamentally determines how the payment method integrates with external services. |
status |
enum Current status of the payment method indicating its readiness for use. One of: created, ready.created - Initial state when the payment method is first createdready - Payment method is verified and can be used for chargesThe status typically changes to ready after successful provider verification or when the payment method is confirmed through the payment flow. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List payment methods
How to fetch a list of payment methods:
curl --get 'https://example.booqable.com/api/4/payment_methods'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "eb25bad2-c1b1-45c1-8526-2085a293c457",
"type": "payment_methods",
"attributes": {
"created_at": "2017-06-03T16:17:00.000000+00:00",
"updated_at": "2017-06-03T16:17:00.000000+00:00",
"label_primary": "Visa XXXX1234",
"label_secondary": "12/25",
"status": "created",
"provider": "stripe",
"identifier": "pm_1234567890",
"method_type": null,
"details": {},
"customer_id": "b0815afc-9d5d-405b-8ef8-fd5373dad3e5"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/payment_methods
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_methods]=created_at,updated_at,label_primary |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
label_primary |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
label_secondary |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
method_type |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
provider |
enum eq |
status |
enum eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Create a payment method
How to create a payment method:
curl --request POST
--url 'https://example.booqable.com/api/4/payment_methods'
--header 'content-type: application/json'
--data '{
"data": {
"type": "payment_methods",
"attributes": {
"provider": "app",
"identifier": "pm_123",
"customer_id": "e1f17238-83d4-4660-8f3b-5e95b67094df",
"label_primary": "Test card",
"status": "ready"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "395900e5-12f7-4449-8212-a7dc4c52edf3",
"type": "payment_methods",
"attributes": {
"created_at": "2019-01-15T14:37:00.000000+00:00",
"updated_at": "2019-01-15T14:37:00.000000+00:00",
"label_primary": "Test card",
"label_secondary": null,
"status": "ready",
"provider": "app",
"identifier": "pm_123",
"method_type": null,
"details": {},
"customer_id": "e1f17238-83d4-4660-8f3b-5e95b67094df"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/payment_methods
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_methods]=created_at,updated_at,label_primary |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][customer_id] |
uuid The Customer who owns this payment method. PaymentMethods must belong to a customer to be created (required for Stripe payment methods). When a PaymentMethod is detached (via DELETE endpoint), this relationship is removed, effectively disabling the payment method for future use while preserving the historical record. The customer relationship can only be set during creation and can only be removed through the detach operation. |
data[attributes][details] |
hash Provider-specific details about the payment method stored as a JSON object. The structure and contents vary by provider and method type. For cards, this might include card brand, last four digits, expiration date, and card network metadata. This data is typically populated automatically from provider webhooks or API responses and provides additional context about the payment method without containing sensitive data. |
data[attributes][identifier] |
string Unique identifier for the payment method from the provider's system. For Stripe, this would be the Stripe payment method ID (e.g., "pm_1234567890"). For app payment methods, this could be an internal reference. This identifier is used to reference the actual payment details stored securely with the provider and cannot be changed after creation. |
data[attributes][label_primary] |
string Primary label for displaying the payment method to customers. This is typically the card brand and last four digits (e.g., "Visa •••• 4242") or a custom name given by the customer. If not provided during creation, this may be automatically generated based on the payment method details from the provider. Can be updated after creation to provide custom labeling. |
data[attributes][label_secondary] |
string Secondary label providing additional information about the payment method. Often contains the expiration date for cards (e.g., "Expires 12/2025") or other relevant details. Like the primary label, this can be automatically generated or customized. Useful for helping customers distinguish between multiple similar payment methods. |
data[attributes][method_type] |
string The type of payment method, indicating what kind of payment instrument this represents. Common values include card for credit/debit cards, though the specific values depend on the provider's supported payment types.This helps determine what kind of payment flow and validations apply. Cannot be changed after creation as it represents the fundamental type of the payment instrument. |
data[attributes][provider] |
enum The payment service provider for this payment method. Determines how the payment method will be processed and which provider-specific features are available. One of: stripe, app, none.stripe - Stripe payment method using tokenized card or bank detailsapp - Internal application-managed payment methodnone - No provider, used for manual payment trackingThis value cannot be changed after creation as it fundamentally determines how the payment method integrates with external services. |
data[attributes][status] |
enum Current status of the payment method indicating its readiness for use. One of: created, ready.created - Initial state when the payment method is first createdready - Payment method is verified and can be used for chargesThe status typically changes to ready after successful provider verification or when the payment method is confirmed through the payment flow. |
Includes
This request does not accept any includes
Detach a payment method
How to detach a payment method from customer:
curl --request DELETE
--url 'https://example.booqable.com/api/4/payment_methods/116b5701-21a0-41af-8a36-ca8d5e8767d6'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "116b5701-21a0-41af-8a36-ca8d5e8767d6",
"type": "payment_methods",
"attributes": {
"created_at": "2016-08-19T20:26:00.000000+00:00",
"updated_at": "2016-08-19T20:26:00.000000+00:00",
"label_primary": "Visa XXXX1234",
"label_secondary": "12/25",
"status": "created",
"provider": "stripe",
"identifier": "pm_1234567890",
"method_type": null,
"details": {},
"customer_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/payment_methods/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_methods]=created_at,updated_at,label_primary |
Includes
This request does not accept any includes
Payment refunds
PaymentRefunds represent refund transactions in Booqable. They are used to return funds to customers for previously successful PaymentCharges, either partially or in full.
PaymentRefunds are one of three payment types in Booqable's payment system, alongside PaymentCharges (direct charges) and PaymentAuthorizations (pre-authorizations). While charges collect payment and authorizations reserve funds, refunds reverse successful charges by returning money to the customer.
Refund Capabilities
PaymentRefunds support several refund scenarios:
- Full Refunds: Return the entire charge amount to the customer
- Partial Refunds: Return only a portion of the original charge
- Split Refunds: Separately refund rental amounts and deposits
- Manual Refunds: Record cash or external refunds against any charge
Status Lifecycle
PaymentRefunds follow a specific status lifecycle:
created → Initial state when a refund is created
- Can transition to:
pending,canceled,succeeded,failed - Set during creation based on provider type
- For manual refunds, may transition directly to
succeeded
- Can transition to:
pending → Refund is being processed by provider
- Can transition to:
action_required,succeeded,failed - Indicates the refund has been submitted to the payment provider
- Typically a brief transitional state
- Can transition to:
action_required → Additional action needed to complete refund
- Can transition to:
pending,canceled,succeeded,failed - Rare for refunds but possible with some payment methods
- May require manual intervention or verification
- Can transition to:
succeeded → Refund successfully processed
- Can transition to:
failed,canceled(for corrections only) - Funds have been returned to the customer
- Updates the original charge's refunded amounts
- Can transition to:
failed → Refund attempt failed
- Can transition to:
pending,succeeded(recovery paths) - May occur due to provider issues or invalid payment methods
- Allows retry by transitioning back to pending
- Can transition to:
canceled → Refund was canceled before completion
- Can transition to:
succeeded,failed(for late completions) - Prevents the refund from being processed
- Cannot cancel after refund has succeeded
- Can transition to:
Provider Support
Refunds can be processed through various providers:
- Matching Provider: Refund through the same provider as the original charge
- Manual Provider: Record manual refunds (cash, bank transfer) against any charge type
- Mixed Refunds: Combine provider and manual refunds for flexibility
Refund Validation
The system enforces several rules to ensure refund integrity:
- Cannot refund more than the original charge amount
- Cannot refund more than the remaining refundable amount
- Provider must match the charge provider or be
nonefor manual refunds - Currency must match the original charge currency
Relationships
| Name | Description |
|---|---|
cart |
Cart requiredThe Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
customer |
Customer requiredThe Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
employee |
Employee requiredThe Employee who created or processed this payment. Automatically set by the system and cannot be modified through the API. |
order |
Order requiredThe Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
payment_charge |
Payment charge requiredThe PaymentCharge this refund is applied to. Links the refund to the original successful charge being refunded. This relationship is required for connected refunds but optional for standalone manual refunds. The charge tracks cumulative refunded amounts across all associated refunds. When a refund succeeds, it automatically updates the charge's refunded and refundable amounts. |
payment_method |
Payment method requiredThe PaymentMethod used for this refund. Typically inherited from the original charge, representing where the refund will be sent. For card payments, refunds go back to the original card. For manual refunds, this may be null.The payment method determines how the customer receives their refund and may affect processing time. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
amount_in_cents |
integer Main refund amount in cents (excluding deposit). This represents the portion of the original charge's main amount being refunded. Must be non-negative and cannot exceed the remaining refundable amount on the charge. |
canceled_at |
datetime readonlyTimestamp when the refund was canceled. Will be null for refunds that haven't been canceled. Refunds can only be canceled before they succeed. |
cart_id |
uuid readonly-after-createThe Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
created_at |
datetime readonlyWhen the resource was created. |
currency |
string Three-letter ISO 4217 currency code (e.g., USD, EUR).Always matches the currency of the original charge. Cannot be changed as refunds must be in the same currency as the original payment. |
customer_id |
uuid readonly-after-createThe Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
deposit_in_cents |
integer Deposit refund amount in cents. This represents the portion of the original charge's deposit amount being refunded. Must be non-negative and cannot exceed the remaining refundable deposit on the charge. |
description |
string Human-readable description of the refund reason or details. Use this to provide context about why the refund was issued, special circumstances, or internal notes. This description may be visible to customers on receipts or statements depending on provider configuration. |
employee_id |
uuid readonlyThe Employee who created or processed this payment. Automatically set by the system and cannot be modified through the API. |
expired_at |
datetime readonlyTimestamp when the refund expired. Most refunds don't expire, but this field is available for consistency with other payment types. Typically remains null. |
failed_at |
datetime readonlyTimestamp when the refund attempt failed. Will be null for refunds that haven't failed. Failed refunds can be retried by transitioning back to pending status. |
failure_reason |
string Detailed explanation of why the refund failed. Contains provider-specific error messages or codes that help diagnose the failure. Only populated when status is failed. |
id |
uuid readonlyPrimary key. |
order_id |
uuid readonly-after-createThe Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
payment_charge_id |
uuid readonly-after-createThe PaymentCharge this refund is applied to. Links the refund to the original successful charge being refunded. This relationship is required for connected refunds but optional for standalone manual refunds. The charge tracks cumulative refunded amounts across all associated refunds. When a refund succeeds, it automatically updates the charge's refunded and refundable amounts. |
payment_method_id |
uuid readonlyThe PaymentMethod used for this refund. Typically inherited from the original charge, representing where the refund will be sent. For card payments, refunds go back to the original card. For manual refunds, this may be null.The payment method determines how the customer receives their refund and may affect processing time. |
provider |
enum The payment service provider processing this refund. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - Manual refund (cash, bank transfer, etc.)For connected refunds, this usually matches the original charge provider. Manual refunds always use none regardless of the original charge provider. |
provider_id |
string Unique identifier from the payment provider for this refund. For Stripe refunds, this contains the Refund ID. Use this to reconcile with external payment systems or for support inquiries with the payment provider. |
provider_link |
string Direct link to view this refund in the provider's dashboard. Useful for support staff to quickly access refund details in the external payment system. Only available for provider-processed refunds. |
provider_method |
string The payment method type used for this refund. Typically matches the original charge's payment method (e.g., card, ideal, bancontact). For manual refunds, this may indicate the refund method (e.g., cash, bank_transfer). |
provider_secret |
string Secret token used for client-side refund processing, if applicable. Most refunds are processed server-side and don't require client secrets. This field is rarely used but maintained for consistency with other payment types. |
reason |
string The reason code for this refund, used for reporting and analysis. Common values include requested_by_customer, duplicate, fraudulent. The specific values available may depend on your payment provider configuration. |
status |
enum Current status of the refund in its lifecycle. One of: created, pending, action_required, succeeded, failed, canceled.Status transitions follow specific rules - for example, a refund cannot be canceled after it has succeeded. |
succeeded_at |
datetime Timestamp when the refund was successfully processed. Will be null for refunds that haven't succeeded yet. Once set, the refund is complete and funds have been returned to the customer. |
total_in_cents |
integer Total refund amount in cents. Always equals amount_in_cents + deposit_in_cents. This is the total amount being returned to the customer. |
type |
string readonlyAlways returns payment_refunds.To retrieve refunds along with other payment types, use the Payments endpoint which returns all payment types. |
updated_at |
datetime readonlyWhen the resource was last updated. |
Create a payment refund
How to create a payment refund:
curl --request POST
--url 'https://example.booqable.com/api/4/payment_refunds'
--header 'content-type: application/json'
--data '{
"data": {
"type": "payment_refunds",
"attributes": {
"provider": "none",
"amount_in_cents": 10000,
"deposit_in_cents": 5000
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "f7983fdf-6655-4adf-8ee8-12f3d3e51898",
"type": "payment_refunds",
"attributes": {
"created_at": "2014-04-24T08:32:00.000000+00:00",
"updated_at": "2014-04-24T08:32:00.000000+00:00",
"type": "payment_refunds",
"provider": "none",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 10000,
"deposit_in_cents": 5000,
"total_in_cents": 15000,
"currency": "usd",
"succeeded_at": "2014-04-24T08:32:00.000000+00:00",
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": "a169cc22-50a0-4bf6-8a15-1516035f6501",
"customer_id": null,
"status": "succeeded",
"description": null,
"failure_reason": null,
"reason": null,
"payment_charge_id": null,
"payment_method_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/payment_refunds
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_refunds]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,customer,employee |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer Main refund amount in cents (excluding deposit). This represents the portion of the original charge's main amount being refunded. Must be non-negative and cannot exceed the remaining refundable amount on the charge. |
data[attributes][cart_id] |
uuid The Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
data[attributes][currency] |
string Three-letter ISO 4217 currency code (e.g., USD, EUR).Always matches the currency of the original charge. Cannot be changed as refunds must be in the same currency as the original payment. |
data[attributes][customer_id] |
uuid The Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
data[attributes][deposit_in_cents] |
integer Deposit refund amount in cents. This represents the portion of the original charge's deposit amount being refunded. Must be non-negative and cannot exceed the remaining refundable deposit on the charge. |
data[attributes][failure_reason] |
string Detailed explanation of why the refund failed. Contains provider-specific error messages or codes that help diagnose the failure. Only populated when status is failed. |
data[attributes][order_id] |
uuid The Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
data[attributes][payment_charge_id] |
uuid The PaymentCharge this refund is applied to. Links the refund to the original successful charge being refunded. This relationship is required for connected refunds but optional for standalone manual refunds. The charge tracks cumulative refunded amounts across all associated refunds. When a refund succeeds, it automatically updates the charge's refunded and refundable amounts. |
data[attributes][provider] |
enum The payment service provider processing this refund. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - Manual refund (cash, bank transfer, etc.)For connected refunds, this usually matches the original charge provider. Manual refunds always use none regardless of the original charge provider. |
data[attributes][provider_id] |
string Unique identifier from the payment provider for this refund. For Stripe refunds, this contains the Refund ID. Use this to reconcile with external payment systems or for support inquiries with the payment provider. |
data[attributes][provider_link] |
string Direct link to view this refund in the provider's dashboard. Useful for support staff to quickly access refund details in the external payment system. Only available for provider-processed refunds. |
data[attributes][provider_method] |
string The payment method type used for this refund. Typically matches the original charge's payment method (e.g., card, ideal, bancontact). For manual refunds, this may indicate the refund method (e.g., cash, bank_transfer). |
data[attributes][provider_secret] |
string Secret token used for client-side refund processing, if applicable. Most refunds are processed server-side and don't require client secrets. This field is rarely used but maintained for consistency with other payment types. |
data[attributes][reason] |
string The reason code for this refund, used for reporting and analysis. Common values include requested_by_customer, duplicate, fraudulent. The specific values available may depend on your payment provider configuration. |
data[attributes][status] |
enum Current status of the refund in its lifecycle. One of: created, pending, action_required, succeeded, failed, canceled.Status transitions follow specific rules - for example, a refund cannot be canceled after it has succeeded. |
data[attributes][succeeded_at] |
datetime Timestamp when the refund was successfully processed. Will be null for refunds that haven't succeeded yet. Once set, the refund is complete and funds have been returned to the customer. |
data[attributes][total_in_cents] |
integer Total refund amount in cents. Always equals amount_in_cents + deposit_in_cents. This is the total amount being returned to the customer. |
Includes
This request accepts the following includes:
customeremployee-
orderdocumentspayments
payment_chargepayment_method
Update a payment refund
How to update a payment refund:
curl --request PUT
--url 'https://example.booqable.com/api/4/payment_refunds/d296895a-e933-4609-8b59-6850e2d29497'
--header 'content-type: application/json'
--data '{
"data": {
"id": "d296895a-e933-4609-8b59-6850e2d29497",
"type": "payment_refunds",
"attributes": {
"status": "succeeded"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "d296895a-e933-4609-8b59-6850e2d29497",
"type": "payment_refunds",
"attributes": {
"created_at": "2020-11-02T14:47:07.000000+00:00",
"updated_at": "2020-11-02T14:47:07.000000+00:00",
"type": "payment_refunds",
"provider": "none",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": "2020-11-02T14:47:07.000000+00:00",
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "succeeded",
"description": null,
"failure_reason": null,
"reason": null,
"payment_charge_id": null,
"payment_method_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/payment_refunds/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_refunds]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,customer,employee |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][amount_in_cents] |
integer Main refund amount in cents (excluding deposit). This represents the portion of the original charge's main amount being refunded. Must be non-negative and cannot exceed the remaining refundable amount on the charge. |
data[attributes][cart_id] |
uuid The Cart this payment is associated with. Once a cart is checked out and becomes an order, payments should be associated with the order instead. Can only be set during payment creation. |
data[attributes][currency] |
string Three-letter ISO 4217 currency code (e.g., USD, EUR).Always matches the currency of the original charge. Cannot be changed as refunds must be in the same currency as the original payment. |
data[attributes][customer_id] |
uuid The Customer this payment belongs to. Can only be set during creation. When not specified, it's inherited from the associated order or cart. |
data[attributes][deposit_in_cents] |
integer Deposit refund amount in cents. This represents the portion of the original charge's deposit amount being refunded. Must be non-negative and cannot exceed the remaining refundable deposit on the charge. |
data[attributes][failure_reason] |
string Detailed explanation of why the refund failed. Contains provider-specific error messages or codes that help diagnose the failure. Only populated when status is failed. |
data[attributes][order_id] |
uuid The Order this payment is associated with. Most payments are order-related. Can only be set during payment creation. Either order or cart should be specified, not both. |
data[attributes][payment_charge_id] |
uuid The PaymentCharge this refund is applied to. Links the refund to the original successful charge being refunded. This relationship is required for connected refunds but optional for standalone manual refunds. The charge tracks cumulative refunded amounts across all associated refunds. When a refund succeeds, it automatically updates the charge's refunded and refundable amounts. |
data[attributes][provider] |
enum The payment service provider processing this refund. One of: stripe, app, none.stripe - Processed through Stripeapp - Processed through a third-party payment appnone - Manual refund (cash, bank transfer, etc.)For connected refunds, this usually matches the original charge provider. Manual refunds always use none regardless of the original charge provider. |
data[attributes][provider_id] |
string Unique identifier from the payment provider for this refund. For Stripe refunds, this contains the Refund ID. Use this to reconcile with external payment systems or for support inquiries with the payment provider. |
data[attributes][provider_link] |
string Direct link to view this refund in the provider's dashboard. Useful for support staff to quickly access refund details in the external payment system. Only available for provider-processed refunds. |
data[attributes][provider_method] |
string The payment method type used for this refund. Typically matches the original charge's payment method (e.g., card, ideal, bancontact). For manual refunds, this may indicate the refund method (e.g., cash, bank_transfer). |
data[attributes][provider_secret] |
string Secret token used for client-side refund processing, if applicable. Most refunds are processed server-side and don't require client secrets. This field is rarely used but maintained for consistency with other payment types. |
data[attributes][reason] |
string The reason code for this refund, used for reporting and analysis. Common values include requested_by_customer, duplicate, fraudulent. The specific values available may depend on your payment provider configuration. |
data[attributes][status] |
enum Current status of the refund in its lifecycle. One of: created, pending, action_required, succeeded, failed, canceled.Status transitions follow specific rules - for example, a refund cannot be canceled after it has succeeded. |
data[attributes][succeeded_at] |
datetime Timestamp when the refund was successfully processed. Will be null for refunds that haven't succeeded yet. Once set, the refund is complete and funds have been returned to the customer. |
data[attributes][total_in_cents] |
integer Total refund amount in cents. Always equals amount_in_cents + deposit_in_cents. This is the total amount being returned to the customer. |
Includes
This request accepts the following includes:
customeremployee-
orderdocumentspayments
payment_chargepayment_method
Delete a payment refund
How to delete a payment refund:
curl --request DELETE
--url 'https://example.booqable.com/api/4/payment_refunds/4e0fcade-0031-4482-8298-8812aef4a22f'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "4e0fcade-0031-4482-8298-8812aef4a22f",
"type": "payment_refunds",
"attributes": {
"created_at": "2014-08-09T02:36:03.000000+00:00",
"updated_at": "2014-08-09T02:36:03.000000+00:00",
"type": "payment_refunds",
"provider": "none",
"provider_id": null,
"provider_method": null,
"provider_secret": null,
"provider_link": null,
"amount_in_cents": 5000,
"deposit_in_cents": 0,
"total_in_cents": 5000,
"currency": "usd",
"succeeded_at": null,
"failed_at": null,
"canceled_at": null,
"expired_at": null,
"cart_id": null,
"order_id": null,
"employee_id": null,
"customer_id": null,
"status": "pending",
"description": null,
"failure_reason": null,
"reason": null,
"payment_charge_id": null,
"payment_method_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/payment_refunds/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[payment_refunds]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=order,customer,employee |
Includes
This request accepts the following includes:
customeremployee-
orderdocumentspayments
payment_chargepayment_method
Photos
Photos are displayed on documents and in the online store to let customers see how products look.
Relationships
| Name | Description |
|---|---|
owner |
Product group, Bundle requiredThe thing pictured in this photo. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
coordinates |
hash Focal point coordinates ( { x: 10, y: 100 }). To ensure that a key part of an image stays visible, you can set the image's focal point. The focal point sets the focus of an image, giving you control over where the image is centered. |
created_at |
datetime readonlyWhen the resource was created. |
height |
integer readonlyHeight of the photo in pixels. |
id |
uuid readonlyPrimary key. |
large_url |
string readonlyURL to large stored image (max 500x500). |
original_filename |
string writeonlyThe original filename of the uploaded image. This is used to preserve the user's original filename when uploading images via base64. The extension may be corrected based on the actual image format detected from the file content. |
original_url |
string readonlyURL to original stored image. |
owner_id |
uuid readonly-after-createThe thing pictured in this photo. |
owner_type |
enum readonly-after-createThe resource type of the owner. One of: product_groups, bundles. |
photo |
carrierwave_file An object describing the photo. |
photo_base64 |
string writeonlyBase64 encoded photo. |
position |
integer Which position the photo has in the album. |
preview |
string readonlyBase64 encoded preview. |
remote_photo_url |
string writeonlyURL to an image on the web. |
updated_at |
datetime readonlyWhen the resource was last updated. |
width |
integer readonlyWidth of the photo in pixels. |
xlarge_url |
string readonlyURL to xlarge stored image (max 2000x2000). |
List photos
How to fetch a list of photos:
curl --get 'https://example.booqable.com/api/4/photos'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "1ba0ace1-dcf6-4d18-8296-444c10c904b1",
"type": "photos",
"attributes": {
"created_at": "2015-06-17T07:25:01.000000+00:00",
"updated_at": "2015-06-17T07:25:01.000000+00:00",
"original_url": "/uploads/84696b61e5664464f6ccb00e1fda1b0b/photo/photo/1ba0ace1-dcf6-4d18-8296-444c10c904b1/upload.png",
"large_url": "/uploads/84696b61e5664464f6ccb00e1fda1b0b/photo/photo/1ba0ace1-dcf6-4d18-8296-444c10c904b1/large_upload.jpg",
"xlarge_url": "/uploads/84696b61e5664464f6ccb00e1fda1b0b/photo/photo/1ba0ace1-dcf6-4d18-8296-444c10c904b1/xlarge_upload.jpg",
"coordinates": {
"x": "0.00",
"y": "0.00"
},
"preview": "iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABcVBMVEX///7+///////+//7//v///v7+/v7+/v/9/v73/f78/v7Z8v6H2/1g1/184v3P9f74+/602v5XuP01tvwvvvwoxfw80f2b6v7z/P7t8f6Zu/5VnP5Jof1Eqf0+sf03ufwvwPwtyf1x3v3h+P7k5f+Pnf9ihP5cjP5Wlf5PnP5Io/5Cq/08s/01u/wswvxY1P3S9P7k3P6Nf/JlYtxbZMxVachPb8xTgNxem/VRoP5FpP1Arf06tfwxvPxPzf3M8f7p4PmMadRgQ69YR6NSSaBQT6F1fLe7w93g6PfD2v57s/5NoP1Ep/0/r/1Uyf3Z8/76+PygechlM6RiOaJcPKFpVKutp9Lw8Pfy9v6szf5fpP5IoP1Dqf06sP13zv32/P7p3fF8OqtqKKFsNaWRcL7a0ur9/f7X5v6CtP5Rnv1Fov1NsP3a7/728fmtfsmcZ7/JsN328vn09/681f6Ctv6Ow/7v9/78+v37+fz6+/76/P7k06ScAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+kLCgkdKVf9/mAAAAGRSURBVCjPNVIHVxYxENzb7F4+sCHNLk1RQVFQ7A1EARvYKKIiKNiwUKy/3pm9j7x395JMMmU3IlIUWiiGiKRCTS2JcKlAMDAXF3ETKZMkNyPKS/hwXLEhKblLhWigwelSp01g45XALOOCePxJTigQEDikcs4k9gpNajEVSinVchbhHIcKbNcaGsOtukMwTDCHljt27tq9p4Z8iRwW7KpZm/Y2t7S2te/brwDIKhFW5cDBQ4ePHO3o7OruqZzm0BU5drz3xMlTff2nzwycPUcPtCBZdHDo/IXhi5cuX7l67fqNm7dUk9FS1tsjo3fG7t4bn5i8/+Dho5bHU5pCR6efPH32/MXMLFZz8y8XXr1+swgLzPN2afnd+5XVUK59+Pjp85c11IrI12/ff6xXYc10Y3Pr5y+VMrz9/lPSOQsCgfLvP8Ylgqge3o2xWQ/84FjQJ60KrznXG1bgrOl287TeXq4Zx6LmxfZZIJDyDB3ja8laJuzyFURP8GpgghUnJRZsH42HHalaCwQ1dDbWLfF9+H+O8CGkTfhjrQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNS0xMS0xMFQwOToyOTo0MSswMDowMHPnfMIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjUtMTEtMTBUMDk6Mjk6NDErMDA6MDACusR+AAAAAElFTkSuQmCC",
"position": 1,
"width": null,
"height": null,
"photo": {
"url": "/uploads/84696b61e5664464f6ccb00e1fda1b0b/photo/photo/1ba0ace1-dcf6-4d18-8296-444c10c904b1/upload.png"
},
"owner_id": "182cbf22-6a51-4729-81a3-190d3cbb3c57",
"owner_type": "product_groups"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/photos
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[photos]=created_at,updated_at,original_url |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a photo
How to fetch a photo:
curl --get 'https://example.booqable.com/api/4/photos/93237a3f-2869-4ac3-8dbb-fabd864e9f81'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "93237a3f-2869-4ac3-8dbb-fabd864e9f81",
"type": "photos",
"attributes": {
"created_at": "2022-08-01T02:59:00.000000+00:00",
"updated_at": "2022-08-01T02:59:00.000000+00:00",
"original_url": "/uploads/ed619234e7d3d43630945e706eff6913/photo/photo/93237a3f-2869-4ac3-8dbb-fabd864e9f81/upload.png",
"large_url": "/uploads/ed619234e7d3d43630945e706eff6913/photo/photo/93237a3f-2869-4ac3-8dbb-fabd864e9f81/large_upload.jpg",
"xlarge_url": "/uploads/ed619234e7d3d43630945e706eff6913/photo/photo/93237a3f-2869-4ac3-8dbb-fabd864e9f81/xlarge_upload.jpg",
"coordinates": {
"x": "0.00",
"y": "0.00"
},
"preview": "iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABcVBMVEX///7+///////+//7//v///v7+/v7+/v/9/v73/f78/v7Z8v6H2/1g1/184v3P9f74+/602v5XuP01tvwvvvwoxfw80f2b6v7z/P7t8f6Zu/5VnP5Jof1Eqf0+sf03ufwvwPwtyf1x3v3h+P7k5f+Pnf9ihP5cjP5Wlf5PnP5Io/5Cq/08s/01u/wswvxY1P3S9P7k3P6Nf/JlYtxbZMxVachPb8xTgNxem/VRoP5FpP1Arf06tfwxvPxPzf3M8f7p4PmMadRgQ69YR6NSSaBQT6F1fLe7w93g6PfD2v57s/5NoP1Ep/0/r/1Uyf3Z8/76+PygechlM6RiOaJcPKFpVKutp9Lw8Pfy9v6szf5fpP5IoP1Dqf06sP13zv32/P7p3fF8OqtqKKFsNaWRcL7a0ur9/f7X5v6CtP5Rnv1Fov1NsP3a7/728fmtfsmcZ7/JsN328vn09/681f6Ctv6Ow/7v9/78+v37+fz6+/76/P7k06ScAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+kLCgkdKs70r9oAAAGRSURBVCjPNVIHVxYxENzb7F4+sCHNLk1RQVFQ7A1EARvYKKIiKNiwUKy/3pm9j7x395JMMmU3IlIUWiiGiKRCTS2JcKlAMDAXF3ETKZMkNyPKS/hwXLEhKblLhWigwelSp01g45XALOOCePxJTigQEDikcs4k9gpNajEVSinVchbhHIcKbNcaGsOtukMwTDCHljt27tq9p4Z8iRwW7KpZm/Y2t7S2te/brwDIKhFW5cDBQ4ePHO3o7OruqZzm0BU5drz3xMlTff2nzwycPUcPtCBZdHDo/IXhi5cuX7l67fqNm7dUk9FS1tsjo3fG7t4bn5i8/+Dho5bHU5pCR6efPH32/MXMLFZz8y8XXr1+swgLzPN2afnd+5XVUK59+Pjp85c11IrI12/ff6xXYc10Y3Pr5y+VMrz9/lPSOQsCgfLvP8Ylgqge3o2xWQ/84FjQJ60KrznXG1bgrOl287TeXq4Zx6LmxfZZIJDyDB3ja8laJuzyFURP8GpgghUnJRZsH42HHalaCwQ1dDbWLfF9+H+O8CGkTfhjrQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNS0xMS0xMFQwOToyOTo0MiswMDowMEIPZl8AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjUtMTEtMTBUMDk6Mjk6NDIrMDA6MDAzUt7jAAAAAElFTkSuQmCC",
"position": 1,
"width": null,
"height": null,
"photo": {
"url": "/uploads/ed619234e7d3d43630945e706eff6913/photo/photo/93237a3f-2869-4ac3-8dbb-fabd864e9f81/upload.png"
},
"owner_id": "850b4eb4-0a7a-4316-8eef-e66a40d0e055",
"owner_type": "product_groups"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/photos/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[photos]=created_at,updated_at,original_url |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
owner
Create a photo
How to create a photo:
curl --request POST
--url 'https://example.booqable.com/api/4/photos'
--header 'content-type: application/json'
--data '{
"data": {
"type": "photos",
"attributes": {
"owner_id": "5ef74fb8-c1c9-47af-8fac-bcab35a7a867",
"owner_type": "product_groups",
"photo_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAFwJJREFUeF7tnX+MHsV5x5+9s7mzTXxnjO/8C2N+2wcGwgW3wY1rkahNRBJRIVCSNlEihJQgJY3SSqWNhCr1HyI1ilI1IqRKFJQmVSE/SgiYmIRE/lXXmACWsR0w4J/x+cfhc2zOd7bvtnrefed9Z+ed3Z2dndmd3X3uH8zd7uzM93k+8zzPzLz7er7v+0A/pAApIFXAI0DIM0iBaAUIEOe9AwO81+hl+1/hfxsbAv8AY42WuyECpNz2o95bVoAAsSwwNV9uBRQBodhbbjNT73UVUAREt3m6r1YKVHAezQ2QCmpXK9+3M9g0XpHmWnO9zQ0QcRXG3BCoJVLAngK5AmJvGC63rDPz6dzjsgbl7VtpASEXKo/TldlWpQVEzz3KbCpxxFUai7o18x51zQBRNwRdWTMFIsgjQGrmB2rDzXueVutV6qsMnM0hQFKrTjfEK1AiuBS6SoBU1d8VjF/VoZscFwFiUs2ktshpkxRy7u+FA0I+45xPWOlQWe1cOCBWrCE0Wlbj5KGNW8/QtZTufcmjrwUgyTLQFfoKhJ0z+D9bDmur3ejREyD6nkF35qVA/ly0RkaA5GVkek4pFSBASmk2hU4XOOsq9I67xO2OEiDprElX10wBAqRmBqfhplOg1oC4HdzTGZKutqNArQGxIym1WiUFCJAqWbNSY3EjvhMgCk7lhqkUOkqXGFeAADEuKTXoigImJjYCxBVrUj8MKmACjaA7BIhBsyQ1Zc5sSU9y9e/lU4AAcdWXqF9OKECAOGEGW50o34xtSwnddgkQXeXovlooQIDUwsw4yDJHk+L6ToCkBKQ4U7GOFt+DlJKV+vLcACGzuugnEVYhY7WMlRsgLroH9YkUSFKAAElSKOvfVWZjlWuy9sP0/WXss4YGBIiGaHRLfRQgQOpjaxqphgIEiIZoxd+Sb36T79OKV5fvAQHilj0q05vyQBXfUwKkSJdM5UWpLi5yVJV6NgFSKXPSYEwrQICYVpTaq5QCAiAUxitlXRpMZgUogmSWkBpwUgFDcz0B4qR1qVOuKFAwIIYwL0RNB/vuYJeMmKbAcRUMiBH5OhspUFBLI6JmC1KgmoDoiklg6SpX2fsIkMqalgZmYr4jQMiPSIEYBQiQWPcwMQeR/5VZAScBIbcss0tVq+9OAlItiVVGQ1OCikpFXEOA5Ko6gZBabuuS0XH31DahG0gBpkCtIoj1yYj8ypIChiyn0UytALFkPWq2wgoQIBU2Lg0tuwIESHYNrbWgkRFY60tdGyZA6mp5GreSAnJAaOpSEi/rRaMXAc5OAxyY8OGE78GJCRQ++FnQ68F1PQB9XQCXdgHMn5H1aVnur69DUATJ4jcp70UgjlwE2Hrah33jAPsnAXaN+3BxBsCMi+3G8P/xZ94sr/HfoV6A63sAVvR48L5ZAFdekvLBjl5eBuwcBqQM8ql5HoKx6R2AF0d9+Om4D11TnfdNdwe/8wMmGtCIPwyYu/sAPtALsHZu82K1btBVUQrEuJrDgJTZnoHiPBjPjLbTpynO+ae72uMUIYkChUUXBOVjcz24uVdfq+pMQ/oaxN1ZGUBcM/T2UYCnjvuw/kQbDDQED4QqKLJowoyKUeUz8wA+1e8VXKekcVDXrBXd98oAksY8Nq/FqPH0YYB/OzgNM8/LgeAhwb4wUMTfq6RdLJpgnfLxuR7c02dzdPVrmwAxaHOMGj/c78O2Uz50TbfhUAVCBopO2vU3/V5lCnmD5tFqigDRki18UyNq7AN49PA0zLgQ/I05Np9WqaRXptKuhwY8WDen6OXhcn91KNouDIix1NBYQwbc124TGDV+useHLafbtYas8Ga/i4ompusTrE2wiKdoks3+FEE09TtzDuAnBwD+4+1puGSy3cjFmdyqlGSFKgkUVYDS1CcYTWpTmxiem6sLiGGheI5Y1NjOrVCx/Qu8LgoSPvWSgRKVXkUV8vL6pHPg+UcTi+JrTmi6t2UHpDpaJGrIosaLbwK8Pj4dup45twoouvWJKihRy8Jr5nlwfx9tMCYamrsgOyBpnlbia98YAfjuPh9ePuKD16TA9/zwvgamV81SJA0oeaZd5dw3Kc5xCBAF7X/7NsCTuwHeHuMK8dbRkDAk/CyP/24dHeFqE7EgZxHFJCghQIVjKwgJ7pv83YJsu/AK0pX+EgIkxoSYUv1mD8C39/jQ3Tw/hY4nPx4SDQrvrHE1SlZQZP0KQSoBRbWAr1EmHfIIAiQCEEypfvYSwJbjsqgR3KQCCl9466Rd4nOyFvJifcIK+M9fVqajKvkFJgJEovWmPQBPvOjDkfPBH6OjhhySRprVHT6DlRUU1eVf3Y1GLOAp5ep0BgKE0wRTqh+/BPD0Xh+6m5/PEB076vStSjTh65O80i4+AvGrZ7Jj9RhNVFOu/ObwYp9EgDT1ZynVSweCmT9uxk4bUcTVrihQ+P2TNIW8ybSLUq4wkAQIALCUanQsEEfF4eIgca0+0Um7KOUKfKHWgLCU6rmdfuu4yFRz+TYOFFtpF6t32ByW9diKaoEfdWwFo8nXB2u2sSgs19UWEEypNmwH2PZmUG/wTs9DwoOSV9rFg6Kbdqn0W/b5E3H/pO51iWFAyrFavns/wE82+vDmsXC+yUMSrETJ/x4FCnOu1oYfd3/W/RPVaKIaNaIAivr8yecWelDHpWDDgBS74qDy9B2/A/jx/wKMNnfFL0jeEBIHilZ9gqd6vfauusqKl4vLwne/x4MvLqnOh7FUpvPaAIL1xgvbAH62w4eeic5VKlOglKU+Ud1XESPKTbM9eHh5fY6oOA6ICuPJcePsyQl4fGsv7HwVDxoG14vpEGtFBCVr2sWeZWP/JK/6RNw/QUg+uagenzFxHJCGewX5iebPyRGARzf4cGS/vAGxNsCrTEUTPs+XPYefnfNIu1TrE5VlYTyy8veDHnx+UN82mibN9bYSAKKvx943AL6/AeDc4faxj8lZne2pRhNx6Vcs5LXqE+6FcdGHDYVj9dyhQ53zXarpVRIoF2YGkNw7v7rnuCoLCBbj658HGD3lt9IpHg2ToEStdsXN2CZ34/mUEf+tuuKV5W0rjbF1B6nqR+d58I9XVBOSBECypTf6c7/+nawYf2FDu94QHYi1LoMkqj5Jm3bx0SZuWRgTlKmItyuqpF1iGscrpwOKShQU+8UgcXaFK4MbVyqCIBxbfwOwfqPfeGmbrJ4QDwniNSajiZh2qYAi3iMWxVlAkUHSgJLbozH1+fgb51RjhYvnqTKAND7c9AzApq3hY+ZsRhUjQN6gqMzMadOuINq5VZ+snFsNSJjflBiQNue4jLv+2V7Y/ooPMycBLvREp2g8KKqQsNZ0VrwKqU+8doSIKuLF+ijrpxn59hCSLy2uxhmuEgMSuC0u4z73pA+793ZCoQqKrEaJSrvEekKWxrGeuHS+S2W1ixXevLPrFvJVgaTUgDA49u0EOB/xpTIqkIyPH2n49MTkaIuyc+dPSsPQuXNHoWtgWftvPsDM7tmt/7+kb0nr3zP6F3a0oXJamK9botIuBrVKfaJ7bCUKlKh0Ufx9FSApLSAIx4bHfXh9X9gHo0BpzPTN1Ovddw/BWTgF3ul3YHzWNEydOhp6ly5eK+5Sy6IMe7LsWvxbT38AkndpP8yeuaDxb4Qmj7Qr6G8+9UlclJnsBfjecq+0X/ZTICD6a29RcPCo8KCcHzsIZ7vPwrnzx2H83SBahFZxhFO7fDtRzi+rX6Kuneqahu6mF4nQePPbUUZlZk5byKt+mlGcFGSRSfe1RFj3fefackJSICDSDCbxlwyOA7sAcHaK+jk73oZi8o9HOmdtCRT88qrYriooUdex9hAW/mf23OWtCDM9GE7J4vZP4l7xo5J2iWlcVDSUHd3XWRbOBxL9STfKj0oFCA+HOCAGCwPjzMjLoQ9BiVGj5bAGQEkTTRr9ECBhfWGw9C5dFRqeKih4E9vdbvxbugFpNu0SnxMXBW1CEqBRRkAM9TkJDgTjxNRbcPGdZgoV8bXJYv4fBU5cNBHTEebNOqAsW3wZXLmkHxYtmAODl89pgXFwrBfO9SyDQ6M+HD8b/Jp3ePvH6gPDJe7G466j8DI9PjqJfUZInhjqyvS9iolphsELrEYQQ2wA7nP8z3/1wKHtnSMfnT4I7xza1FjF8rkZkzeSTK+8QeGhWrK0H/701iVw4zUL4OahpfAeyQFKvB43P0dOA+z5A8DeowDbjgYnBPIAxeb+ybWXl2cz0SogJkBGJ9nxI4CXn223NjnbhzMnX4N3/VMwNnmgo75wARTZe6/W3LIMbnnvQrjz/ddHQhGl2ZkJgEMjAP93GOB3b/kwMh6+Uny7vO3Pn8QV8WK0k0UUhOTrV7v/6UTnAdn+BMDm/247w/mJE3B0ai+cGQ+DIYsIqqDI7tVJvWQFOqYUCMYH110dGy3STCb4wonN+zpBUU27rNcnCWkXe/5d8z34ynXyU8Cmso80usqubQLiSnfCXdz9PMBz327/7uT4Ljhx+lWYmhGct4pMk7jhiJDEpV6qaVfDwDFLwyydWn27WTBEA2YFJaqIT6p3WD8S65Nmyhu3T/KhJR7861XufujK2QiCn+fY/S2Ak2MAfNQQnUTVqVWjSSx4wsOjILnuhgH4sw8t10qldGY8fEvLL14LahT2ylRxIjC6f4KNN30668d+EZ4vL+2Czy7XGbn9e5wEBFesNn4NYP/BAI6DxzbAxGz5KV0mUZGgsIiCYAwPLYSPfvh6uPTymE0aC3bFWu2V/cFLt+Pqk6z7J600Dt/Swo1DNZrIohOmod8acnMj0TlAcMXq59/tgZHtHmBKdXLs1Y5PBLIUS+ZnuYPiA0zPALjtjmXw4F+vhcs7j19ZwCG6Sfa2yKRCXkx72P5JER/7Reg+MMeDr6xyr2h3DhAsyl94/AT8cfpYAw7+R1wZCoHC1R2qRbeJtOuaoQG4+54hYwW4KZpY2vXiofivYQgBwb2/S2WTUZbG6dYnCMlHFkQX7Um62KqinQLk9S0jsO17C2HHjh+2NqhUDg1GRRQb0YTVKJgWfOKvbi4knUpyFvZ39g1Zz+8KNhtd3z9BSL60zK16xBlAMLV69pHjsPn5TR0nabNAkqboVokoCN1tty2FtR+/FtYML1X11UKvY1/tgNEET7nIQIl6barsjS/t1xWpfe1cmvoEjwx9Z2UXrJ5fqGSthzsDyKYfvQ1Pfm1r6/yU8rENoVjMWp/IloVZKnHFvD4Y/siVcNc9N6fe6DNr7vQJhelowhYm4k4L4zUqH9QSP82IS79R+yNmdUxuzQlAcNXqsS88A8feGmsAgiuILHNWBSW2PuF0UK1PGsZtruNjn2653XLUSO/zydaVXKESTZhj29iNx7aTIgq+lO6rN3XB3QNaQwxuMqSnE4D8/BuvwK++/1pLDfF1n0qQNKnKAooMnkWDrkSNDM4i3CpGk0Y04M6xqe7Ih+7pbk5swoe0+EI+zfmu1fM9ePiW4t+1VTggfPQQXUALFCGsBwaK3kOJiig4y930/qXwwBfWFb50aw6NcEtx0UR07KhoIsIVVZ/ofOz3H27NGEUMCFc4IGL0kI0pb1AGFlcvakT5io1owtcnSdGJ9UuWdr1voPgoUigguHL1zQd+Daf2jMH5mFf18LMZE1SWdon5bdS1ccvCK9ZWO2pEgSJGkyTHzqM+QWi+Oay4omWo5hD1KRQQ3Pf49wd/3fp+wCRITIIiQjL/ivpEDd1oIupv9HwXd16Rjyb3X9MFn11hIFfSbKJQQDC92vhYuzjHMahAogqK6v7JXX+5Ev78/uHK1hppfSMpmpiuT+IK+TV9Hnx12CtsWb0wQDD3feqhLfDKL+Vf3GEbFDRK39VzHdnXSOvC9q+X1Sam066k9tiE+Y3VimmWBVkKAwTrj8fu+xUcO3w6tMQojtE0KDMuBF+Q8+G7VlDUUHAoFk1eOhBeCcy6LKyyG4/dQ1v9y1AXrLtKobOmLuHqGScAEWcS2ThVQFFZ7Zpzw1x44MHbYdFtC62EbUu1oinTa7WjEk3i0q6GfRO+KChuR/4zK4urQ5wBhFlOPIatE1FEUFio/ti9N8Kdn16R+2c1tLzSwZtktUlSmpRmtQvbkr0NUgcQUxNVGBBTrSoa9z//dgvsXC+vQeJACaIJfyCl84EICX66Dgv1O9Ysh9X3XQPXryn4wxqKurh8Gftg1s43ADZyX21nEhSEhLWHdnxkbQ1rEBQADyg+/c9bI/0hazQZvLof1t47BO/9i0UUNQxTF5V2mQbl2ku74JE7wUo6rCJJYSkWdg6PmTz+qV80CvW4n+RoEr4bwVi1dgnc8clbaelWxQsyXMNeHPHsruCdXSy9VX0bZNK3aX3iVq+++yBoF9wL2fxoeC8kyl5JEWXR4j5Y/sFFtDqVweF1b+U/wci/WTUtKPzm41X9Hnx5GOC6vDNjF1axmCFwufepf9oBr/72gLJtRNEZGKvWLaE6Q1lFwxf6AI2X2x0L3rDCPpzFnpJ2WRiXdx/6Ey/f5V2JJIWmWKw/mGr98uHNqSGZt5JSKcNubqQ5rE8QFPYWSPZuYdX6BOG4b7iI1KpzlcoJQFA4jCQv/GAvvPH04ciaBGchjBaDq+Y1VqUW39BvsPjOeQnPiCsmNBIzpLxGizUKe7cwvohbfCURjoDVLQjGsvke3DsEhUUOURdnAOFTrj/8fgz2bh+BC+NTcO74BMwa6IWBqy6DwStnGYYiDy+lZ6AC7EXcI6cA9o0CnBDWZVYsApg7D2B4YXErVjJLuQFIXtOZs75aTwEQGvyJert9vuaS28ANQPJVgp7mogKOzhEEiIvOQn1yRgEFQBxFW1XCkndfdZh0nR0FFACx82BqlRQogwIESBmsRH0sTIFqAkJpVWEO1X5wNYxQTUAccA/qQl4K2AWRALFmR7uG0+u2i33SG0ledxEgeSlNzymlAoYBoRnKihc4Jqtj3UkteZr+xwCSppnUfaQbSIFSKGA4gpRizNRJUkBZAQJEWaoKXEhJQWojEiCpJavLDTWmyaWP3NbF3Wic5VTAkQhierYy3V7JjFvD4dsasiOAlMwBXemuLa9wZXwO9IMAkRqBPM8B33SiC/kBUrjPFd4BJwxOnUinQH6ApOsXXa2gACGvIFLGSwiQjALS7dVWwCAgNJ9V21XqOTqDgNRTQBp1tRUgQKptXxpdRgUIkIwC0u3VVoAAqbZ9aXQZFSBAMgro8u20bJLFOoF6BEgWDeneyitAgFTexDTALAoQIFnUo3srrwABUnkTmxtgHWsaAsSc/zjRUvFOXHwPwGAXCBAn3Np+Jwz6jP3OWniC7vg7AdFtycKgqElSoGgFKIIUbQF6vr4COUzmBIi+eejOiijQ5qyTODuA5EA22ianx1TEDWgYOgrYAUSnJ3QPKeCgAu4CwoUHihQOek5NuuQuIDUxAA3TbQXqCQiFJCteWUVZPX/a98GzolfJGq2ieUtmgsTuqttI/cr4h9YzgiQagi4gBQIFCBDyBFIgRoFaAhKEX1NBuFNdey2TL+etQPkAqbL3VXlseXu2oeeVDxBDA69XM0Serr0JEF3l6L5aKECA1MLMNMhkBeRRlgBJVq74KyhDKswGdgGpkWFrNNTCnLWIB9sFpIgR0TNJAYMK5AsITbMGTUdN5aFAvoDkMaLaPINmmzxMTYDkoXLaZ5DvSxSzJUp8uzUExJbQaSmg68ugQA0BccEsFYG0IsOI8whv2vf9wj8OUgGhKzAEF2YO5/pAEcQ5k0R0iAgsxFIOA0IeUYhH0ENDCjgMCFnKLQWKm7CKezJ9ojC9DxZprfS9bd5Ryk5rj9bIjU3JKIIYUZMa0VHA9ic7dfok3kOAZFGRJuYs6pXi3v8HOZ5zbDYLrEsAAAAASUVORK5CYII=\n",
"original_filename": "my_product_image.png"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "a8eb63bc-693b-4335-865c-8dbf5462fc14",
"type": "photos",
"attributes": {
"created_at": "2024-05-28T22:17:00.000000+00:00",
"updated_at": "2024-05-28T22:17:00.000000+00:00",
"original_url": "/uploads/354d68b26fcffd8f9a3c21cae0ba8d0d/photo/photo/a8eb63bc-693b-4335-865c-8dbf5462fc14/my_product_image.png",
"large_url": "/uploads/354d68b26fcffd8f9a3c21cae0ba8d0d/photo/photo/a8eb63bc-693b-4335-865c-8dbf5462fc14/large_my_product_image.jpg",
"xlarge_url": "/uploads/354d68b26fcffd8f9a3c21cae0ba8d0d/photo/photo/a8eb63bc-693b-4335-865c-8dbf5462fc14/xlarge_my_product_image.jpg",
"coordinates": {
"x": 0,
"y": 0
},
"preview": "iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABcVBMVEX///7+///////+//7//v///v7+/v7+/v/9/v73/f78/v7Z8v6H2/1g1/184v3P9f74+/602v5XuP01tvwvvvwoxfw80f2b6v7z/P7t8f6Zu/5VnP5Jof1Eqf0+sf03ufwvwPwtyf1x3v3h+P7k5f+Pnf9ihP5cjP5Wlf5PnP5Io/5Cq/08s/01u/wswvxY1P3S9P7k3P6Nf/JlYtxbZMxVachPb8xTgNxem/VRoP5FpP1Arf06tfwxvPxPzf3M8f7p4PmMadRgQ69YR6NSSaBQT6F1fLe7w93g6PfD2v57s/5NoP1Ep/0/r/1Uyf3Z8/76+PygechlM6RiOaJcPKFpVKutp9Lw8Pfy9v6szf5fpP5IoP1Dqf06sP13zv32/P7p3fF8OqtqKKFsNaWRcL7a0ur9/f7X5v6CtP5Rnv1Fov1NsP3a7/728fmtfsmcZ7/JsN328vn09/681f6Ctv6Ow/7v9/78+v37+fz6+/76/P7k06ScAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+kLCgkdK7nzn0wAAAGRSURBVCjPNVIHVxYxENzb7F4+sCHNLk1RQVFQ7A1EARvYKKIiKNiwUKy/3pm9j7x395JMMmU3IlIUWiiGiKRCTS2JcKlAMDAXF3ETKZMkNyPKS/hwXLEhKblLhWigwelSp01g45XALOOCePxJTigQEDikcs4k9gpNajEVSinVchbhHIcKbNcaGsOtukMwTDCHljt27tq9p4Z8iRwW7KpZm/Y2t7S2te/brwDIKhFW5cDBQ4ePHO3o7OruqZzm0BU5drz3xMlTff2nzwycPUcPtCBZdHDo/IXhi5cuX7l67fqNm7dUk9FS1tsjo3fG7t4bn5i8/+Dho5bHU5pCR6efPH32/MXMLFZz8y8XXr1+swgLzPN2afnd+5XVUK59+Pjp85c11IrI12/ff6xXYc10Y3Pr5y+VMrz9/lPSOQsCgfLvP8Ylgqge3o2xWQ/84FjQJ60KrznXG1bgrOl287TeXq4Zx6LmxfZZIJDyDB3ja8laJuzyFURP8GpgghUnJRZsH42HHalaCwQ1dDbWLfF9+H+O8CGkTfhjrQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNS0xMS0xMFQwOToyOTo0MyswMDowMOR4besAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjUtMTEtMTBUMDk6Mjk6NDMrMDA6MDCVJdVXAAAAAElFTkSuQmCC",
"position": 2,
"width": null,
"height": null,
"photo": {
"url": "/uploads/354d68b26fcffd8f9a3c21cae0ba8d0d/photo/photo/a8eb63bc-693b-4335-865c-8dbf5462fc14/my_product_image.png"
},
"owner_id": "5ef74fb8-c1c9-47af-8fac-bcab35a7a867",
"owner_type": "product_groups"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/photos
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[photos]=created_at,updated_at,original_url |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][coordinates] |
hash Focal point coordinates ( { x: 10, y: 100 }). To ensure that a key part of an image stays visible, you can set the image's focal point. The focal point sets the focus of an image, giving you control over where the image is centered. |
data[attributes][original_filename] |
string The original filename of the uploaded image. This is used to preserve the user's original filename when uploading images via base64. The extension may be corrected based on the actual image format detected from the file content. |
data[attributes][owner_id] |
uuid The thing pictured in this photo. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: product_groups, bundles. |
data[attributes][photo] |
carrierwave_file An object describing the photo. |
data[attributes][photo_base64] |
string Base64 encoded photo. |
data[attributes][position] |
integer Which position the photo has in the album. |
data[attributes][remote_photo_url] |
string URL to an image on the web. |
Includes
This request accepts the following includes:
owner
Update a photo
How to update a photo:
curl --request PUT
--url 'https://example.booqable.com/api/4/photos/f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0'
--header 'content-type: application/json'
--data '{
"data": {
"id": "f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0",
"type": "photos",
"attributes": {
"coordinates": {
"x": 10,
"y": 100
}
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0",
"type": "photos",
"attributes": {
"created_at": "2024-12-16T09:31:00.000000+00:00",
"updated_at": "2024-12-16T09:31:00.000000+00:00",
"original_url": "/uploads/8188eebd3991392b266b288655dfde98/photo/photo/f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0/upload.png",
"large_url": "/uploads/8188eebd3991392b266b288655dfde98/photo/photo/f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0/large_upload.jpg",
"xlarge_url": "/uploads/8188eebd3991392b266b288655dfde98/photo/photo/f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0/xlarge_upload.jpg",
"coordinates": {
"x": 10,
"y": 100
},
"preview": "iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABcVBMVEX///7+///////+//7//v///v7+/v7+/v/9/v73/f78/v7Z8v6H2/1g1/184v3P9f74+/602v5XuP01tvwvvvwoxfw80f2b6v7z/P7t8f6Zu/5VnP5Jof1Eqf0+sf03ufwvwPwtyf1x3v3h+P7k5f+Pnf9ihP5cjP5Wlf5PnP5Io/5Cq/08s/01u/wswvxY1P3S9P7k3P6Nf/JlYtxbZMxVachPb8xTgNxem/VRoP5FpP1Arf06tfwxvPxPzf3M8f7p4PmMadRgQ69YR6NSSaBQT6F1fLe7w93g6PfD2v57s/5NoP1Ep/0/r/1Uyf3Z8/76+PygechlM6RiOaJcPKFpVKutp9Lw8Pfy9v6szf5fpP5IoP1Dqf06sP13zv32/P7p3fF8OqtqKKFsNaWRcL7a0ur9/f7X5v6CtP5Rnv1Fov1NsP3a7/728fmtfsmcZ7/JsN328vn09/681f6Ctv6Ow/7v9/78+v37+fz6+/76/P7k06ScAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+kLCgkdLCeXCu8AAAGRSURBVCjPNVIHVxYxENzb7F4+sCHNLk1RQVFQ7A1EARvYKKIiKNiwUKy/3pm9j7x395JMMmU3IlIUWiiGiKRCTS2JcKlAMDAXF3ETKZMkNyPKS/hwXLEhKblLhWigwelSp01g45XALOOCePxJTigQEDikcs4k9gpNajEVSinVchbhHIcKbNcaGsOtukMwTDCHljt27tq9p4Z8iRwW7KpZm/Y2t7S2te/brwDIKhFW5cDBQ4ePHO3o7OruqZzm0BU5drz3xMlTff2nzwycPUcPtCBZdHDo/IXhi5cuX7l67fqNm7dUk9FS1tsjo3fG7t4bn5i8/+Dho5bHU5pCR6efPH32/MXMLFZz8y8XXr1+swgLzPN2afnd+5XVUK59+Pjp85c11IrI12/ff6xXYc10Y3Pr5y+VMrz9/lPSOQsCgfLvP8Ylgqge3o2xWQ/84FjQJ60KrznXG1bgrOl287TeXq4Zx6LmxfZZIJDyDB3ja8laJuzyFURP8GpgghUnJRZsH42HHalaCwQ1dDbWLfF9+H+O8CGkTfhjrQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNS0xMS0xMFQwOToyOTo0NCswMDowMCHfU2UAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjUtMTEtMTBUMDk6Mjk6NDQrMDA6MDBQguvZAAAAAElFTkSuQmCC",
"position": 1,
"width": null,
"height": null,
"photo": {
"url": "/uploads/8188eebd3991392b266b288655dfde98/photo/photo/f25879e9-ea1c-4b0f-8cc7-9b2eb23b96c0/upload.png"
},
"owner_id": "266622d8-4266-4054-8c2c-617ae1a4b11e",
"owner_type": "product_groups"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/photos/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[photos]=created_at,updated_at,original_url |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][coordinates] |
hash Focal point coordinates ( { x: 10, y: 100 }). To ensure that a key part of an image stays visible, you can set the image's focal point. The focal point sets the focus of an image, giving you control over where the image is centered. |
data[attributes][original_filename] |
string The original filename of the uploaded image. This is used to preserve the user's original filename when uploading images via base64. The extension may be corrected based on the actual image format detected from the file content. |
data[attributes][owner_id] |
uuid The thing pictured in this photo. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: product_groups, bundles. |
data[attributes][photo] |
carrierwave_file An object describing the photo. |
data[attributes][photo_base64] |
string Base64 encoded photo. |
data[attributes][position] |
integer Which position the photo has in the album. |
data[attributes][remote_photo_url] |
string URL to an image on the web. |
Includes
This request accepts the following includes:
owner
Delete a photo
How to delete a photo:
curl --request DELETE
--url 'https://example.booqable.com/api/4/photos/d9aa6a55-20cb-4b4e-8dc1-b546e4d3abf0'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "d9aa6a55-20cb-4b4e-8dc1-b546e4d3abf0",
"type": "photos",
"attributes": {
"created_at": "2025-11-22T09:49:03.000000+00:00",
"updated_at": "2025-11-22T09:49:03.000000+00:00",
"original_url": "/uploads/5e3caf7997ce0b0563ffc6e824afbe2a/photo/photo/d9aa6a55-20cb-4b4e-8dc1-b546e4d3abf0/upload.png",
"large_url": "/uploads/5e3caf7997ce0b0563ffc6e824afbe2a/photo/photo/d9aa6a55-20cb-4b4e-8dc1-b546e4d3abf0/large_upload.jpg",
"xlarge_url": "/uploads/5e3caf7997ce0b0563ffc6e824afbe2a/photo/photo/d9aa6a55-20cb-4b4e-8dc1-b546e4d3abf0/xlarge_upload.jpg",
"coordinates": {
"x": "0.00",
"y": "0.00"
},
"preview": "iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABcVBMVEX///7+///////+//7//v///v7+/v7+/v/9/v73/f78/v7Z8v6H2/1g1/184v3P9f74+/602v5XuP01tvwvvvwoxfw80f2b6v7z/P7t8f6Zu/5VnP5Jof1Eqf0+sf03ufwvwPwtyf1x3v3h+P7k5f+Pnf9ihP5cjP5Wlf5PnP5Io/5Cq/08s/01u/wswvxY1P3S9P7k3P6Nf/JlYtxbZMxVachPb8xTgNxem/VRoP5FpP1Arf06tfwxvPxPzf3M8f7p4PmMadRgQ69YR6NSSaBQT6F1fLe7w93g6PfD2v57s/5NoP1Ep/0/r/1Uyf3Z8/76+PygechlM6RiOaJcPKFpVKutp9Lw8Pfy9v6szf5fpP5IoP1Dqf06sP13zv32/P7p3fF8OqtqKKFsNaWRcL7a0ur9/f7X5v6CtP5Rnv1Fov1NsP3a7/728fmtfsmcZ7/JsN328vn09/681f6Ctv6Ow/7v9/78+v37+fz6+/76/P7k06ScAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+kLCgkdLVCQOnkAAAGRSURBVCjPNVIHVxYxENzb7F4+sCHNLk1RQVFQ7A1EARvYKKIiKNiwUKy/3pm9j7x395JMMmU3IlIUWiiGiKRCTS2JcKlAMDAXF3ETKZMkNyPKS/hwXLEhKblLhWigwelSp01g45XALOOCePxJTigQEDikcs4k9gpNajEVSinVchbhHIcKbNcaGsOtukMwTDCHljt27tq9p4Z8iRwW7KpZm/Y2t7S2te/brwDIKhFW5cDBQ4ePHO3o7OruqZzm0BU5drz3xMlTff2nzwycPUcPtCBZdHDo/IXhi5cuX7l67fqNm7dUk9FS1tsjo3fG7t4bn5i8/+Dho5bHU5pCR6efPH32/MXMLFZz8y8XXr1+swgLzPN2afnd+5XVUK59+Pjp85c11IrI12/ff6xXYc10Y3Pr5y+VMrz9/lPSOQsCgfLvP8Ylgqge3o2xWQ/84FjQJ60KrznXG1bgrOl287TeXq4Zx6LmxfZZIJDyDB3ja8laJuzyFURP8GpgghUnJRZsH42HHalaCwQ1dDbWLfF9+H+O8CGkTfhjrQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNS0xMS0xMFQwOToyOTo0NSswMDowMIeoWNEAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjUtMTEtMTBUMDk6Mjk6NDUrMDA6MDD29eBtAAAAAElFTkSuQmCC",
"position": 1,
"width": null,
"height": null,
"photo": {
"url": "/uploads/5e3caf7997ce0b0563ffc6e824afbe2a/photo/photo/d9aa6a55-20cb-4b4e-8dc1-b546e4d3abf0/upload.png"
},
"owner_id": "98ee3afa-9bdc-4ccd-850a-61157c8e2a39",
"owner_type": "product_groups"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/photos/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[photos]=created_at,updated_at,original_url |
Includes
This request does not accept any includes
Plannings
Plannings track the quantitative planned activities (order or downtime) of an item. Planned activities will make an item unavailable for other activities during a given period. Planning records are never directly created or updated. The item can either be a Product or a Bundle.
Product Plannings vs Bundle Plannings
There are two types of Plannings:
Product Plannings: These represent the planning of a single Product.
Bundle Plannings: These represent the planning of a Bundle (a group of Products). Some attributes are omitted for Bundle Plannings because they don't apply at the Bundle level.
Nested Plannings
Nested Plannings contain information about individual Products in a Bundle. Note that nested Plannings cannot be deleted directly; the parent Line should be deleted instead.
When a Bundle is booked:
- A parent Planning is created for the Bundle itself
- Nested Plannings are created for each Product within the Bundle
- The nested Plannings have their parent_planning_id set to the ID of the parent Planning
Reservation vs Planning Dates
Plannings use two sets of dates that serve different purposes:
starts_at/stops_at: When actions (pickup/return) are planned to occur. These are typically shown to customers and staff as the scheduled dates.reserved_from/reserved_till: When items are actually unavailable/available in the system. These may differ from the planned dates due to buffer times.
Relationships
| Name | Description |
|---|---|
downtime |
Downtime optionalThe Downtime this Planning belongs to. This association is present when planning_type: "downtime". A downtime represents a period when items are unavailable for rental due to maintenance, repairs, or other operational reasons. It is not associated with a customer order. |
item |
Item requiredThe Product or Bundle that was booked. |
nested_plannings |
Plannings hasmanyWhen item is a Bundle, then there is a nested planning that corresponds for each BundleItem. |
order |
Order optionalThe Order this Planning belongs to. |
order_line |
Line optionalThe Line which holds financial information for this Planning. |
parent_planning |
Planning requiredWhen present, this Planning is part of a Bundle and corresponds to a BundleItem. Inverse of the nested_plannings relation. |
start_location |
Location requiredThe Location where the planned activity begins. For order plannings, this is where the customer will pick up the item. |
stock_item_plannings |
Stock item plannings hasmanyThe StockItems specified for this Planning, and their current status. For trackable products, this association contains the specific inventory items assigned to this planning. The number of StockItemPlannings can be less than planning.quantity. This is because stock items may not yet be specified (assigned) for this planning.For order plannings, stock items are typically specified through the OrderFulfillments resource, which creates the corresponding StockItemPlannings linking specific inventory items to this planning. |
stop_location |
Location requiredThe Location where the planned activity ends. For order plannings, this is where the customer will return the product. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether planning is archived. Note that there are two concepts of "archiving". The archived attribute is set to true when a Planning is removed from an Order through the Lines resource. When an Order is archived, status of Plannings is set to archived, but the archived attribute remains false. |
archived_at |
datetime readonly nullableWhen the planning was archived. Indicates when the archived attribute was set to true. |
created_at |
datetime readonlyWhen the resource was created. |
downtime_id |
uuid readonly nullableThe Downtime this Planning belongs to. This association is present when planning_type: "downtime". A downtime represents a period when items are unavailable for rental due to maintenance, repairs, or other operational reasons. It is not associated with a customer order. |
fulfillment_type |
string writeonlyThe type of fulfillment for this planning. |
id |
uuid readonlyPrimary key. |
item_id |
uuid readonlyThe Product or Bundle that was booked. |
item_name |
string writeonlyAllows sorting plannings by item name. |
location_shortage_amount |
integer Amount of items short at the specific location. This represents how many more items would be needed at the start_location to fully satisfy this planning. A value greater than zero indicates a location shortage. This attribute is omitted when this is a parent planning for a Bundle. |
order_id |
uuid readonly nullableThe Order this Planning belongs to. |
order_number |
integer writeonlyAllows sorting plannings by order number. |
parent_planning_id |
uuid readonlyWhen present, this Planning is part of a Bundle and corresponds to a BundleItem. Inverse of the nested_plannings relation. |
planning_type |
enum readonlyType of planning. Can be order for regular rental plannings created through Orders, or downtime for operational periods when items are unavailable due to maintenance, repairs, or other reasons. Downtime plannings don't belong to an order and are managed separately.One of: order, downtime. |
quantity |
integer readonlyTotal planned quantity of items. This affects availability calculations and represents how many items are being booked/reserved. Changing this value may result in shortages if additional items are not available for the rental period. |
reserved |
boolean readonlyWhether items are reserved. When true, this Planning affects availability calculations and the items are not available for other plannings during the reserved period. For order plannings, this is set to true when an Order transitions from draft to reserved status. |
reserved_from |
datetime readonlyWhen the items actually become unavailable in the system. May differ from starts_at due to buffer time. This is the actual time used for availability calculations. |
reserved_till |
datetime readonlyWhen the items actually become available again in the system. May differ from stops_at due to buffer time. This is the actual time used for availability calculations. |
shortage_amount |
integer Amount of items short across all locations in the same cluster. This represents how many more items would be needed in total to satisfy this planning. A value greater than zero indicates a system-wide shortage that can't be solved by transfers between locations. This attribute is omitted when this is a parent planning for a Bundle. |
start_location_id |
uuid readonlyThe Location where the planned activity begins. For order plannings, this is where the customer will pick up the item. |
started |
integer Amount of items that have begun their planned activity. For order plannings, this represents items picked up or delivered to the customer. This value increases when staff performs start actions. Cannot exceed quantity. When all items are started (started equals quantity), the Planning is considered fully started. This attribute is omitted when this is a parent planning for a Bundle. |
starts_at |
datetime readonlyWhen the planned activity is scheduled to begin. For order plannings, this represents when pickup/delivery is planned to occur and is shown to staff and customers as the beginning of the rental. |
status |
enum readonlyStatus of this planning. A planning can become "stopped" before the order it belongs to is stopped. Otherwise, the status mostly follows the status of the order. Note that there are two concepts of "archiving". The archived attribute is set to true when a Planning is removed from an Order through the Lines resource. When an Order is archived, status of Plannings is set to archived, but the archived attribute remains false.One of: new, draft, reserved, started, stopped, archived, canceled. |
stop_location_id |
uuid readonlyThe Location where the planned activity ends. For order plannings, this is where the customer will return the product. |
stopped |
integer Amount of items that have completed their planned activity. For order plannings, this represents items returned by the customer. This value increases when staff performs stop actions. Cannot exceed quantity and started (items must be started before they can be stopped). When all items are stopped (stopped equals quantity), the Planning is considered fully completed.For order plannings with Products that have product_type == consumable, items are never returned, and the stopped attribute will always remain zero.This attribute is omitted when this is a parent planning for a Bundle. |
stops_at |
datetime readonlyWhen the planned activity is scheduled to end. For order plannings, this represents when return is planned to occur and is shown to staff and customers as the end of the rental. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List plannings
How to fetch a list of plannings:
curl --get 'https://example.booqable.com/api/4/plannings'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "61b93896-5b57-455e-84fe-39f48ce6f4ab",
"type": "plannings",
"attributes": {
"created_at": "2018-03-21T05:17:00.000000+00:00",
"updated_at": "2018-03-21T05:17:00.000000+00:00",
"archived": false,
"archived_at": null,
"planning_type": "order",
"quantity": 1,
"starts_at": "1972-08-10T07:48:00.000000+00:00",
"stops_at": "1972-09-09T07:48:00.000000+00:00",
"reserved_from": "1972-08-10T07:48:00.000000+00:00",
"reserved_till": "1972-09-09T07:48:00.000000+00:00",
"reserved": true,
"status": "reserved",
"started": 0,
"stopped": 0,
"location_shortage_amount": 0,
"shortage_amount": 0,
"order_id": "ead6ad3f-bdc9-47c1-86d3-7f825d8f0769",
"downtime_id": null,
"item_id": "bc366da1-7df4-4bc5-846b-8d94a52be19b",
"start_location_id": "91d91031-83d2-483b-8d80-12ce62a11b4f",
"stop_location_id": "91d91031-83d2-483b-8d80-12ce62a11b4f",
"parent_planning_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/plannings
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[plannings]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=order,item,downtime |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
downtime_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
item_id |
uuid eq, not_eq |
item_type |
string eq, not_eq |
location_shortage_amount |
integer eq, not_eq, gt, gte, lt, lte |
order_id |
uuid eq, not_eq |
parent_planning_id |
uuid eq, not_eq |
planning_type |
string eq, not_eq |
product_type |
string eq, not_eq |
q |
string eq |
quantity |
integer eq, not_eq, gt, gte, lt, lte |
reserved |
boolean eq |
reserved_from |
datetime eq, not_eq, gt, gte, lt, lte |
reserved_till |
datetime eq, not_eq, gt, gte, lt, lte |
shortage_amount |
integer eq, not_eq, gt, gte, lt, lte |
start_location_id |
uuid eq, not_eq |
started |
integer eq, not_eq, gt, gte, lt, lte |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
stop_location_id |
uuid eq, not_eq |
stopped |
integer eq, not_eq, gt, gte, lt, lte |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
status |
array count |
total |
array count |
Includes
This request accepts the following includes:
downtime-
itemphoto
-
ordercustomer
order_linestart_locationstop_location
Search plannings
Use advanced search to make logical filter groups with and/or operators.
How to search for plannings:
curl --request POST
--url 'https://example.booqable.com/api/4/plannings/search'
--header 'content-type: application/json'
--data '{
"fields": {
"plannings": "id"
},
"filter": {
"conditions": {
"operator": "or",
"attributes": [
{
"operator": "and",
"attributes": [
{
"starts_at": {
"gte": "2025-11-11T09:29:52Z"
}
},
{
"starts_at": {
"lte": "2025-11-14T09:29:52Z"
}
}
]
},
{
"operator": "and",
"attributes": [
{
"stops_at": {
"gte": "2025-11-11T09:29:52Z"
}
},
{
"stops_at": {
"lte": "2025-11-14T09:29:52Z"
}
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "b256e1d6-5a03-4c89-8561-d96d00867c8b"
},
{
"id": "68589e0b-87d0-47f5-81fc-bc562e69965d"
}
]
}
HTTP Request
POST /api/4/plannings/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[plannings]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=order,item,downtime |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
downtime_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
item_id |
uuid eq, not_eq |
item_type |
string eq, not_eq |
location_shortage_amount |
integer eq, not_eq, gt, gte, lt, lte |
order_id |
uuid eq, not_eq |
parent_planning_id |
uuid eq, not_eq |
planning_type |
string eq, not_eq |
product_type |
string eq, not_eq |
q |
string eq |
quantity |
integer eq, not_eq, gt, gte, lt, lte |
reserved |
boolean eq |
reserved_from |
datetime eq, not_eq, gt, gte, lt, lte |
reserved_till |
datetime eq, not_eq, gt, gte, lt, lte |
shortage_amount |
integer eq, not_eq, gt, gte, lt, lte |
start_location_id |
uuid eq, not_eq |
started |
integer eq, not_eq, gt, gte, lt, lte |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
stop_location_id |
uuid eq, not_eq |
stopped |
integer eq, not_eq, gt, gte, lt, lte |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
status |
array count |
total |
array count |
Includes
This request accepts the following includes:
downtime-
itemphoto
-
ordercustomer
order_linestart_locationstop_location
Fetch a planning
How to fetch a planning:
curl --get 'https://example.booqable.com/api/4/plannings/7ab088ea-e88a-4452-8ab3-d8593ea31603'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "7ab088ea-e88a-4452-8ab3-d8593ea31603",
"type": "plannings",
"attributes": {
"created_at": "2023-04-14T01:42:01.000000+00:00",
"updated_at": "2023-04-14T01:42:01.000000+00:00",
"archived": false,
"archived_at": null,
"planning_type": "order",
"quantity": 1,
"starts_at": "1977-09-03T04:13:01.000000+00:00",
"stops_at": "1977-10-03T04:13:01.000000+00:00",
"reserved_from": "1977-09-03T04:13:01.000000+00:00",
"reserved_till": "1977-10-03T04:13:01.000000+00:00",
"reserved": true,
"status": "reserved",
"started": 0,
"stopped": 0,
"location_shortage_amount": 0,
"shortage_amount": 0,
"order_id": "73a043aa-a655-48a0-8936-f1c8ded729d7",
"downtime_id": null,
"item_id": "ab4d2f98-31a4-4d84-8750-a8b3c4408a4a",
"start_location_id": "090a3ed2-c86a-468d-8d55-d59c162f9276",
"stop_location_id": "090a3ed2-c86a-468d-8d55-d59c162f9276",
"parent_planning_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/plannings/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[plannings]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=order,item,downtime |
Includes
This request accepts the following includes:
downtime-
itemphoto
nested_plannings-
ordercustomer
order_lineparent_planningstart_locationstop_location
Price rules
A price rule contains a single pricing adjustment rule and belongs to a PriceRuleset.
A price rule can have one of these types:
- range_of_days: Adjust pricing for certain days of the week,
match_strategycan be one ofwithin, overlap, spanand must be used in combination withfrom_day,till_day,from_time,till_timeandvalue`. - range_of_dates: Adjust pricing for certain calendar days,
match_strategycan be one ofwithin, overlap, spanand must be used in combination withfrom,tillandvalue. - exclude_week_days: Do not charge for certain days of the week,
match_strategycan be one ofwithin, overlap, spanand must be used in combination withfrom_day,till_day,from_time,till_time`. - exclude_date_range: Do not charge for certain calendar days,
match_strategycan be one ofwithin, overlap, spanand must be used in combination withfrom,till. - pickup_day: Rule determines if entire day is charged based on pickup day time,
match_strategymust bestarts_within,chargedetermines if day is charged when beforetimeor not charged if aftertime. - return_day: Rule determines if entire day is charged based on return day time,
match_strategymust bestops_within,chargedetermines if day is charged when beforetimeor not charged if aftertime.
and these match strategies:
- starts_within: Used with
pickup_dayrules - stops_within: Used with
return_dayrules - within: Rule is applied when the rule period fits within the order period.
- overlap: Rule is applied for the part of the rule period that overlaps the order period.
- span: Rule is applied when the rule period spans over the order period.
as well as these adjustment strategies:
- charge: Applies
chargeattribute to determine rule effect, either charges or doesn't charge. Used bypickup_dayandreturn_dayrules types. - percentage: Applies
valueattribute to determine the percentage change to the pricing over the rule period. Used byrange_of_days,range_of_daterule types.
Relationships
| Name | Description |
|---|---|
price_ruleset |
Price ruleset requiredThe advanced pricing ruleset this rule is part of. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
adjustment_strategy |
enum Determines whether a price rule adjusts prices by percentage or exact cent amounts. One of: percentage, charge. |
charge |
boolean Determines effect of rules using charge attribute. |
created_at |
datetime readonlyWhen the resource was created. |
from |
datetime Defines start of period, used by range_of_dates rule type. |
from_day |
integer Defines start of period in weekdays, 0 is monday, used by range_of_days rule type. |
from_time |
string Defines start of period time, used by range_of_days rule type. Format is a HH:mm string, independent of time display settings. |
id |
uuid readonlyPrimary key. |
match_strategy |
enum Determines how dates are matched to the rule. One of: starts_within, stops_within, overlap, span, within. |
max_duration |
integer Rule will only be applied when order period is smaller than max duration in seconds. |
min_duration |
integer Rule will only be applied when order period is greater than min duration in seconds. |
name |
string Name of the rule. |
price_ruleset_id |
uuid readonly-after-createWhich ruleset this rule belongs to. |
rule_type |
enum Determines rule behaviour. One of: range_of_days, range_of_dates, exclude_date_range, exclude_week_days, pickup_day, return_day. |
stacked |
boolean If a ruleset consists of multiple rules that adjust the product price, determines if rule should interact with other rules. |
till |
datetime Defines end of period, used by range_of_dates rule type. |
till_day |
integer Defines end of period in weekdays, 0 is monday, used by range_of_days rule type. |
till_time |
string Defines end of period time, used by range_of_days rule type. Format is a HH:mm string, independent of time display settings. |
time |
string Defines time for adjustment, used by pickup_day and return_day rule types. Format is a HH:mm string, independent of time display settings. |
updated_at |
datetime readonlyWhen the resource was last updated. |
value |
float Adjustment value in percent. |
Create a price rule
How to create a price rule:
curl --request POST
--url 'https://example.booqable.com/api/4/price_rules'
--header 'content-type: application/json'
--data '{
"data": {
"type": "price_rules",
"attributes": {
"price_ruleset_id": "7d2b2786-70ba-41b4-82cc-05cbe8cacb34",
"name": "Off season",
"rule_type": "range_of_dates",
"match_strategy": "span",
"value": 25,
"from": "2014-12-05T04:39:00.000000+00:00",
"till": "2015-02-04T04:39:00.000000+00:00"
}
},
"include": "price_rules"
}'
A 201 status response looks like this:
{
"data": {
"id": "496355f5-1c79-4b05-86e8-fb9f00c27d78",
"type": "price_rules",
"attributes": {
"created_at": "2015-01-05T04:39:00.000000+00:00",
"updated_at": "2015-01-05T04:39:00.000000+00:00",
"name": "Off season",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 25.0,
"from": "2014-12-05T04:39:00.000000+00:00",
"till": "2015-02-04T04:39:00.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "7d2b2786-70ba-41b4-82cc-05cbe8cacb34"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/price_rules
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rules]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=price_ruleset |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][adjustment_strategy] |
enum Determines whether a price rule adjusts prices by percentage or exact cent amounts. One of: percentage, charge. |
data[attributes][charge] |
boolean Determines effect of rules using charge attribute. |
data[attributes][from] |
datetime Defines start of period, used by range_of_dates rule type. |
data[attributes][from_day] |
integer Defines start of period in weekdays, 0 is monday, used by range_of_days rule type. |
data[attributes][from_time] |
string Defines start of period time, used by range_of_days rule type. Format is a HH:mm string, independent of time display settings. |
data[attributes][match_strategy] |
enum Determines how dates are matched to the rule. One of: starts_within, stops_within, overlap, span, within. |
data[attributes][max_duration] |
integer Rule will only be applied when order period is smaller than max duration in seconds. |
data[attributes][min_duration] |
integer Rule will only be applied when order period is greater than min duration in seconds. |
data[attributes][name] |
string Name of the rule. |
data[attributes][price_ruleset_id] |
uuid Which ruleset this rule belongs to. |
data[attributes][rule_type] |
enum Determines rule behaviour. One of: range_of_days, range_of_dates, exclude_date_range, exclude_week_days, pickup_day, return_day. |
data[attributes][stacked] |
boolean If a ruleset consists of multiple rules that adjust the product price, determines if rule should interact with other rules. |
data[attributes][till] |
datetime Defines end of period, used by range_of_dates rule type. |
data[attributes][till_day] |
integer Defines end of period in weekdays, 0 is monday, used by range_of_days rule type. |
data[attributes][till_time] |
string Defines end of period time, used by range_of_days rule type. Format is a HH:mm string, independent of time display settings. |
data[attributes][time] |
string Defines time for adjustment, used by pickup_day and return_day rule types. Format is a HH:mm string, independent of time display settings. |
data[attributes][value] |
float Adjustment value in percent. |
Includes
This request accepts the following includes:
-
price_rulesetprice_rules
Update a price rule
How to update a price rule:
curl --request PUT
--url 'https://example.booqable.com/api/4/price_rules/03a98195-fad9-4128-8b3d-f8fca9458b1e'
--header 'content-type: application/json'
--data '{
"data": {
"id": "03a98195-fad9-4128-8b3d-f8fca9458b1e",
"type": "price_rules",
"attributes": {
"value": 10
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "03a98195-fad9-4128-8b3d-f8fca9458b1e",
"type": "price_rules",
"attributes": {
"created_at": "2022-06-25T00:41:07.000000+00:00",
"updated_at": "2022-06-25T00:41:07.000000+00:00",
"name": "Holidays",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 10.0,
"from": "2027-07-15T15:12:07.000000+00:00",
"till": "2027-09-14T15:12:07.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "8a88d3b1-8d95-45c3-8d9c-37f4189f8e18"
},
"relationships": {}
},
"meta": {}
}
Updating a price rule:
curl --request PUT
--url 'https://example.booqable.com/api/4/price_rules/ad06b6c5-c179-4a32-8260-11b998f79946'
--header 'content-type: application/json'
--data '{
"data": {
"id": "ad06b6c5-c179-4a32-8260-11b998f79946",
"type": "price_rules",
"attributes": {
"id": "ad06b6c5-c179-4a32-8260-11b998f79946",
"name": "Off season"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "ad06b6c5-c179-4a32-8260-11b998f79946",
"type": "price_rules",
"attributes": {
"created_at": "2020-09-12T03:59:01.000000+00:00",
"updated_at": "2020-09-12T03:59:01.000000+00:00",
"name": "Off season",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 5.0,
"from": "2025-10-02T18:30:01.000000+00:00",
"till": "2025-12-02T18:30:01.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "da082b15-8901-48df-8450-683f48eb006e"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/price_rules/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rules]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=price_ruleset |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][adjustment_strategy] |
enum Determines whether a price rule adjusts prices by percentage or exact cent amounts. One of: percentage, charge. |
data[attributes][charge] |
boolean Determines effect of rules using charge attribute. |
data[attributes][from] |
datetime Defines start of period, used by range_of_dates rule type. |
data[attributes][from_day] |
integer Defines start of period in weekdays, 0 is monday, used by range_of_days rule type. |
data[attributes][from_time] |
string Defines start of period time, used by range_of_days rule type. Format is a HH:mm string, independent of time display settings. |
data[attributes][match_strategy] |
enum Determines how dates are matched to the rule. One of: starts_within, stops_within, overlap, span, within. |
data[attributes][max_duration] |
integer Rule will only be applied when order period is smaller than max duration in seconds. |
data[attributes][min_duration] |
integer Rule will only be applied when order period is greater than min duration in seconds. |
data[attributes][name] |
string Name of the rule. |
data[attributes][price_ruleset_id] |
uuid Which ruleset this rule belongs to. |
data[attributes][rule_type] |
enum Determines rule behaviour. One of: range_of_days, range_of_dates, exclude_date_range, exclude_week_days, pickup_day, return_day. |
data[attributes][stacked] |
boolean If a ruleset consists of multiple rules that adjust the product price, determines if rule should interact with other rules. |
data[attributes][till] |
datetime Defines end of period, used by range_of_dates rule type. |
data[attributes][till_day] |
integer Defines end of period in weekdays, 0 is monday, used by range_of_days rule type. |
data[attributes][till_time] |
string Defines end of period time, used by range_of_days rule type. Format is a HH:mm string, independent of time display settings. |
data[attributes][time] |
string Defines time for adjustment, used by pickup_day and return_day rule types. Format is a HH:mm string, independent of time display settings. |
data[attributes][value] |
float Adjustment value in percent. |
Includes
This request accepts the following includes:
-
price_rulesetprice_rules
Archive a price rule
How to archive a price ruleset:
curl --request DELETE
--url 'https://example.booqable.com/api/4/price_rules/dcba05ea-7016-4ed4-8034-a823d01f4d26'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "dcba05ea-7016-4ed4-8034-a823d01f4d26",
"type": "price_rules",
"attributes": {
"created_at": "2020-12-18T05:52:07.000000+00:00",
"updated_at": "2020-12-18T05:52:07.000000+00:00",
"name": "Holidays",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 5.0,
"from": "2026-01-07T20:23:07.000000+00:00",
"till": "2026-03-09T20:23:07.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "0f77bbbc-4358-4a67-85a9-ca319b75a498"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/price_rules/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rules]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=price_ruleset |
Includes
This request accepts the following includes:
-
price_rulesetprice_rules
Price rulesets
Price rulesets are used to create elaborate pricing adjustments using the advanced pricing feature.
Relationships
| Name | Description |
|---|---|
price_rules |
Price rules hasmanyThe rules included in this ruleset. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the price ruleset is archived. |
archived_at |
datetime readonly nullableWhen the price ruleset was archived. |
created_at |
datetime readonlyWhen the resource was created. |
description |
string Description of the ruleset. |
id |
uuid readonlyPrimary key. |
make_name_unique |
boolean writeonlyWhen true, a unique name will be generated when a PriceRuleset with the same name already exists. |
name |
string Name of the ruleset. |
price_rules_attributes |
array writeonlyAllows creating and updating price rules with their ruleset. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List price rulesets
How to fetch price rulesets:
curl --get 'https://example.booqable.com/api/4/price_rulesets'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "c218f45f-5f3f-4800-8f10-4d3ad173bd93",
"type": "price_rulesets",
"attributes": {
"created_at": "2023-11-03T10:09:00.000000+00:00",
"updated_at": "2023-11-03T10:09:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Ruleset",
"description": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/price_rulesets
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rulesets]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
price_rules_attributes |
array eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a price ruleset
How to fetch a single price ruleset with related price rules:
curl --get 'https://example.booqable.com/api/4/price_rulesets/ca85320f-4ffc-496c-855e-77a3d0f4a40a'
--header 'content-type: application/json'
--data-urlencode 'include=price_rules'
A 200 status response looks like this:
{
"data": {
"id": "ca85320f-4ffc-496c-855e-77a3d0f4a40a",
"type": "price_rulesets",
"attributes": {
"created_at": "2027-04-22T08:54:05.000000+00:00",
"updated_at": "2027-04-22T08:54:05.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Ruleset",
"description": null
},
"relationships": {
"price_rules": {
"data": [
{
"type": "price_rules",
"id": "e80760ba-0d09-4a88-878f-b2f2dfd3ad73"
}
]
}
}
},
"included": [
{
"id": "e80760ba-0d09-4a88-878f-b2f2dfd3ad73",
"type": "price_rules",
"attributes": {
"created_at": "2027-04-22T08:54:05.000000+00:00",
"updated_at": "2027-04-22T08:54:05.000000+00:00",
"name": "Price rule",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 30.0,
"from": "2031-12-10T23:25:05.000000+00:00",
"till": "2032-02-09T23:25:05.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "ca85320f-4ffc-496c-855e-77a3d0f4a40a"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/price_rulesets/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rulesets]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=price_rules |
Includes
This request accepts the following includes:
price_rules
Create a price ruleset
How to create a price ruleset with price rules:
curl --request POST
--url 'https://example.booqable.com/api/4/price_rulesets'
--header 'content-type: application/json'
--data '{
"data": {
"type": "price_rulesets",
"attributes": {
"name": "Seasonal ruleset",
"price_rules_attributes": [
{
"name": "Off season",
"rule_type": "range_of_dates",
"match_strategy": "span",
"value": 25,
"from": "2014-09-24T15:02:01.000000+00:00",
"till": "2014-11-24T15:02:01.000000+00:00"
}
]
}
},
"include": "price_rules"
}'
A 201 status response looks like this:
{
"data": {
"id": "e4fe0b61-208f-4525-8281-39ceec698804",
"type": "price_rulesets",
"attributes": {
"created_at": "2014-10-25T15:02:01.000000+00:00",
"updated_at": "2014-10-25T15:02:01.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Seasonal ruleset",
"description": null
},
"relationships": {
"price_rules": {
"data": [
{
"type": "price_rules",
"id": "fe521f82-f68d-479c-843d-7420dbcf18ae"
}
]
}
}
},
"included": [
{
"id": "fe521f82-f68d-479c-843d-7420dbcf18ae",
"type": "price_rules",
"attributes": {
"created_at": "2014-10-25T15:02:01.000000+00:00",
"updated_at": "2014-10-25T15:02:01.000000+00:00",
"name": "Off season",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 25.0,
"from": "2014-09-24T15:02:01.000000+00:00",
"till": "2014-11-24T15:02:01.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "e4fe0b61-208f-4525-8281-39ceec698804"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/price_rulesets
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rulesets]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=price_rules |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][make_name_unique] |
boolean When true, a unique name will be generated when a PriceRuleset with the same name already exists. |
data[attributes][name] |
string Name of the ruleset. |
data[attributes][price_rules_attributes][] |
array Allows creating and updating price rules with their ruleset. |
Includes
This request accepts the following includes:
price_rules
Update a price ruleset
How to update a price ruleset:
curl --request PUT
--url 'https://example.booqable.com/api/4/price_rulesets/f45fa6ef-5ccc-4a37-89b6-5701c9c8f77b'
--header 'content-type: application/json'
--data '{
"data": {
"id": "f45fa6ef-5ccc-4a37-89b6-5701c9c8f77b",
"type": "price_rulesets",
"attributes": {
"name": "Seasonal ruleset (old)"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "f45fa6ef-5ccc-4a37-89b6-5701c9c8f77b",
"type": "price_rulesets",
"attributes": {
"created_at": "2016-01-18T12:44:00.000000+00:00",
"updated_at": "2016-01-18T12:44:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Seasonal ruleset (old)",
"description": null
},
"relationships": {}
},
"meta": {}
}
Updating a price ruleset's price rules:
curl --request PUT
--url 'https://example.booqable.com/api/4/price_rulesets/8fdd2e80-1ce2-4bf8-8e01-df9e6925b595'
--header 'content-type: application/json'
--data '{
"data": {
"id": "8fdd2e80-1ce2-4bf8-8e01-df9e6925b595",
"type": "price_rulesets",
"attributes": {
"price_rules_attributes": [
{
"id": "ab3f8794-7809-432e-8619-556bc2224ad3",
"name": "Off season"
}
]
}
},
"include": "price_rules"
}'
A 200 status response looks like this:
{
"data": {
"id": "8fdd2e80-1ce2-4bf8-8e01-df9e6925b595",
"type": "price_rulesets",
"attributes": {
"created_at": "2023-09-01T22:07:00.000000+00:00",
"updated_at": "2023-09-01T22:07:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Ruleset",
"description": null
},
"relationships": {
"price_rules": {
"data": [
{
"type": "price_rules",
"id": "ab3f8794-7809-432e-8619-556bc2224ad3"
}
]
}
}
},
"included": [
{
"id": "ab3f8794-7809-432e-8619-556bc2224ad3",
"type": "price_rules",
"attributes": {
"created_at": "2023-09-01T22:07:00.000000+00:00",
"updated_at": "2023-09-01T22:07:00.000000+00:00",
"name": "Off season",
"rule_type": "range_of_dates",
"match_strategy": "span",
"adjustment_strategy": "percentage",
"value": 30.0,
"from": "2028-04-21T12:38:00.000000+00:00",
"till": "2028-06-21T12:38:00.000000+00:00",
"from_day": null,
"till_day": null,
"from_time": null,
"till_time": null,
"charge": null,
"stacked": false,
"time": null,
"min_duration": null,
"max_duration": null,
"price_ruleset_id": "8fdd2e80-1ce2-4bf8-8e01-df9e6925b595"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
PUT /api/4/price_rulesets/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rulesets]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=price_rules |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][make_name_unique] |
boolean When true, a unique name will be generated when a PriceRuleset with the same name already exists. |
data[attributes][name] |
string Name of the ruleset. |
data[attributes][price_rules_attributes][] |
array Allows creating and updating price rules with their ruleset. |
Includes
This request accepts the following includes:
price_rules
Archive a price ruleset
How to archive a price ruleset:
curl --request DELETE
--url 'https://example.booqable.com/api/4/price_rulesets/dcba05ea-7016-4ed4-8034-a823d01f4d26'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "dcba05ea-7016-4ed4-8034-a823d01f4d26",
"type": "price_rulesets",
"attributes": {
"created_at": "2020-12-18T05:52:07.000000+00:00",
"updated_at": "2020-12-18T05:52:07.000000+00:00",
"archived": true,
"archived_at": "2020-12-18T05:52:07.000000+00:00",
"name": "Ruleset",
"description": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/price_rulesets/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_rulesets]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Price structures
Price structures enable you to control what is being priced for a specific period. Price structures consist of tiles that represent a period. The actual charge that is being calculated will always round up to the nearest tile it can find.
You can also set up a flat-fee structure after you've run out of tiles by setting
one of the following values: hour, day, week, month, year.
There are two kinds of price structures:
reusable: Structures that are reusable and that can be assigned to multiple product groups.private: Structure for a specific product group. These are automatically created when the price type of a product group is set toprivate_structure.
Relationships
| Name | Description |
|---|---|
price_tiles |
Price tiles hasmanyThe tiles (or tiers) within this price structure. Tiles can be created/updated through the PriceStructure resource by writing the price_tiles_attributes attribute. |
product_group |
Product group requiredThe product group for private price structures. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the price structure is archived. |
archived_at |
datetime readonly nullableWhen the price structure was archived. |
created_at |
datetime readonlyWhen the resource was created. |
day |
float Multiplier for every day outside of its tiles. |
hour |
float Multiplier for every hour outside of its tiles. |
id |
uuid readonlyPrimary key. |
month |
float Multiplier for every month outside of its tiles. |
name |
string Name of the structure. |
price_structure_type |
enum readonlyType. One of: reusable, private. |
price_tiles_attributes |
array writeonlyThe price tiles to associate. |
product_group_id |
uuid readonlyThe product group for private price structures. |
updated_at |
datetime readonlyWhen the resource was last updated. |
week |
float Multiplier for every week outside of its tiles. |
year |
float Multiplier for every year outside of its tiles. |
List price structures
How to fetch a list of price structures:
curl --get 'https://example.booqable.com/api/4/price_structures'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "ec8cd116-78dd-4aa2-8794-723225fb7f27",
"type": "price_structures",
"attributes": {
"created_at": "2027-12-25T18:39:02.000000+00:00",
"updated_at": "2027-12-25T18:39:02.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Price per hour (3 hours minimum)",
"price_structure_type": "reusable",
"hour": 1.0,
"day": 0.0,
"week": 0.0,
"month": 0.0,
"year": 0.0,
"product_group_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/price_structures
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_structures]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
price_structure_type |
enum eq, not_eq |
product_group_id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a price structure
How to fetch a price structure with it's tiles:
curl --get 'https://example.booqable.com/api/4/price_structures/1eefd0fa-08d5-4e02-8267-c2db07cb35a0'
--header 'content-type: application/json'
--data-urlencode 'include=price_tiles'
A 200 status response looks like this:
{
"data": {
"id": "1eefd0fa-08d5-4e02-8267-c2db07cb35a0",
"type": "price_structures",
"attributes": {
"created_at": "2021-07-22T04:14:00.000000+00:00",
"updated_at": "2021-07-22T04:14:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Price per hour (3 hours minimum)",
"price_structure_type": "reusable",
"hour": 1.0,
"day": 0.0,
"week": 0.0,
"month": 0.0,
"year": 0.0,
"product_group_id": null
},
"relationships": {
"price_tiles": {
"data": [
{
"type": "price_tiles",
"id": "f4b52aba-05ab-4ad3-8b2f-814b68c688cd"
}
]
}
}
},
"included": [
{
"id": "f4b52aba-05ab-4ad3-8b2f-814b68c688cd",
"type": "price_tiles",
"attributes": {
"created_at": "2021-07-22T04:14:00.000000+00:00",
"updated_at": "2021-07-22T04:14:00.000000+00:00",
"name": "3 hours",
"quantity": 3,
"length": 10800,
"multiplier": 1.0,
"period": "hours",
"price_structure_id": "1eefd0fa-08d5-4e02-8267-c2db07cb35a0"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/price_structures/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_structures]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=price_tiles |
Includes
This request accepts the following includes:
price_tiles
Create a price structure
How to create a price structure with price tiles:
curl --request POST
--url 'https://example.booqable.com/api/4/price_structures'
--header 'content-type: application/json'
--data '{
"data": {
"type": "price_structures",
"attributes": {
"name": "Price per hour (3 hours minimum)",
"hour": 1,
"price_tiles_attributes": [
{
"name": "3 hours",
"quantity": 3,
"period": "hours",
"multiplier": 1
}
]
}
},
"include": "price_tiles"
}'
A 201 status response looks like this:
{
"data": {
"id": "135630ff-fb4a-4bbb-8e04-85d256658648",
"type": "price_structures",
"attributes": {
"created_at": "2017-09-22T05:03:01.000000+00:00",
"updated_at": "2017-09-22T05:03:01.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Price per hour (3 hours minimum)",
"price_structure_type": "reusable",
"hour": 1.0,
"day": 0.0,
"week": 0.0,
"month": 0.0,
"year": 0.0,
"product_group_id": null
},
"relationships": {
"price_tiles": {
"data": [
{
"type": "price_tiles",
"id": "c49c9747-d7b5-4faf-8042-f0fc3dcd5706"
}
]
}
}
},
"included": [
{
"id": "c49c9747-d7b5-4faf-8042-f0fc3dcd5706",
"type": "price_tiles",
"attributes": {
"created_at": "2017-09-22T05:03:01.000000+00:00",
"updated_at": "2017-09-22T05:03:01.000000+00:00",
"name": "3 hours",
"quantity": 3,
"length": 10800,
"multiplier": 1.0,
"period": "hours",
"price_structure_id": "135630ff-fb4a-4bbb-8e04-85d256658648"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/price_structures
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_structures]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=price_tiles |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][day] |
float Multiplier for every day outside of its tiles. |
data[attributes][hour] |
float Multiplier for every hour outside of its tiles. |
data[attributes][month] |
float Multiplier for every month outside of its tiles. |
data[attributes][name] |
string Name of the structure. |
data[attributes][price_tiles_attributes][] |
array The price tiles to associate. |
data[attributes][week] |
float Multiplier for every week outside of its tiles. |
data[attributes][year] |
float Multiplier for every year outside of its tiles. |
Includes
This request accepts the following includes:
price_tiles
Update a price structure
How to update a price structure with price tiles:
curl --request PUT
--url 'https://example.booqable.com/api/4/price_structures/bbc6913e-a6dd-4ab4-8c78-a004643a9cad'
--header 'content-type: application/json'
--data '{
"data": {
"id": "bbc6913e-a6dd-4ab4-8c78-a004643a9cad",
"type": "price_structures",
"attributes": {
"name": "Charge per week (cut-rate > 3 weeks)",
"price_tiles_attributes": [
{
"id": "514b2a51-5961-411f-8000-e4712f4024df",
"name": "1 semana"
},
{
"id": "9d9034c8-9bcf-4c35-831c-93c082af2305",
"name": "2 semanas"
},
{
"id": "c08789b9-93ca-475f-83d1-6868f2d3602f",
"name": "3 semanas"
},
{
"id": "69e2abc5-8433-4b13-871c-1141dd30c453",
"_destroy": true
}
]
}
},
"include": "price_tiles"
}'
A 200 status response looks like this:
{
"data": {
"id": "bbc6913e-a6dd-4ab4-8c78-a004643a9cad",
"type": "price_structures",
"attributes": {
"created_at": "2026-07-21T11:43:00.000000+00:00",
"updated_at": "2026-07-21T11:43:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Charge per week (cut-rate > 3 weeks)",
"price_structure_type": "reusable",
"hour": 0.0,
"day": 0.0,
"week": 0.8,
"month": 0.0,
"year": 0.0,
"product_group_id": null
},
"relationships": {
"price_tiles": {
"data": [
{
"type": "price_tiles",
"id": "514b2a51-5961-411f-8000-e4712f4024df"
},
{
"type": "price_tiles",
"id": "9d9034c8-9bcf-4c35-831c-93c082af2305"
},
{
"type": "price_tiles",
"id": "c08789b9-93ca-475f-83d1-6868f2d3602f"
}
]
}
}
},
"included": [
{
"id": "514b2a51-5961-411f-8000-e4712f4024df",
"type": "price_tiles",
"attributes": {
"created_at": "2026-07-21T11:43:00.000000+00:00",
"updated_at": "2026-07-21T11:43:00.000000+00:00",
"name": "1 semana",
"quantity": 1,
"length": 604800,
"multiplier": 1.0,
"period": "weeks",
"price_structure_id": "bbc6913e-a6dd-4ab4-8c78-a004643a9cad"
},
"relationships": {}
},
{
"id": "9d9034c8-9bcf-4c35-831c-93c082af2305",
"type": "price_tiles",
"attributes": {
"created_at": "2026-07-21T11:43:00.000000+00:00",
"updated_at": "2026-07-21T11:43:00.000000+00:00",
"name": "2 semanas",
"quantity": 2,
"length": 1209600,
"multiplier": 2.0,
"period": "weeks",
"price_structure_id": "bbc6913e-a6dd-4ab4-8c78-a004643a9cad"
},
"relationships": {}
},
{
"id": "c08789b9-93ca-475f-83d1-6868f2d3602f",
"type": "price_tiles",
"attributes": {
"created_at": "2026-07-21T11:43:00.000000+00:00",
"updated_at": "2026-07-21T11:43:00.000000+00:00",
"name": "3 semanas",
"quantity": 3,
"length": 1814400,
"multiplier": 3.0,
"period": "weeks",
"price_structure_id": "bbc6913e-a6dd-4ab4-8c78-a004643a9cad"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
PUT /api/4/price_structures/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_structures]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=price_tiles |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][day] |
float Multiplier for every day outside of its tiles. |
data[attributes][hour] |
float Multiplier for every hour outside of its tiles. |
data[attributes][month] |
float Multiplier for every month outside of its tiles. |
data[attributes][name] |
string Name of the structure. |
data[attributes][price_tiles_attributes][] |
array The price tiles to associate. |
data[attributes][week] |
float Multiplier for every week outside of its tiles. |
data[attributes][year] |
float Multiplier for every year outside of its tiles. |
Includes
This request accepts the following includes:
price_tiles
Delete a price structure
How to delete a price structure with tax rates:
curl --request DELETE
--url 'https://example.booqable.com/api/4/price_structures/787c6191-4590-4d80-8b25-2675dd775bb1'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "787c6191-4590-4d80-8b25-2675dd775bb1",
"type": "price_structures",
"attributes": {
"created_at": "2023-08-07T17:52:01.000000+00:00",
"updated_at": "2023-08-07T17:52:01.000000+00:00",
"archived": true,
"archived_at": "2023-08-07T17:52:01.000000+00:00",
"name": "Price per hour (3 hours minimum) (Deleted)",
"price_structure_type": "reusable",
"hour": 1.0,
"day": 0.0,
"week": 0.0,
"month": 0.0,
"year": 0.0,
"product_group_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/price_structures/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_structures]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Price tiles
Price tiles hold information on how to calculate a price for a specific period.
According to the charge_length, a tile will be picked in price calculations.
Note that Booqable always rounds up to the highest tile it can find.
The base price of a product is multiplied by the multiplier.
Relationships
| Name | Description |
|---|---|
price_structure |
Price structure requiredPriceStructure this price tile is part of. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
length |
integer readonlyLength in seconds (is computed based on quantity and period). |
multiplier |
float The amount to multiply a product's base price with (e.g. 2.8 for three days). |
name |
string Name of the tile, which will be used as charge label in the store and on lines. |
period |
enum Period. One of: hours, days, weeks, months, years. |
price_structure_id |
uuid readonly-after-createPriceStructure this price tile is part of. |
quantity |
integer Used in combination with period (e.g. 3 with period days). |
updated_at |
datetime readonlyWhen the resource was last updated. |
List price tiles
How to fetch a list of price tiles:
curl --get 'https://example.booqable.com/api/4/price_tiles'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "0d6f13f8-3b9b-4c22-8b76-818cde33de51",
"type": "price_tiles",
"attributes": {
"created_at": "2024-06-11T13:44:00.000000+00:00",
"updated_at": "2024-06-11T13:44:00.000000+00:00",
"name": "3 hours",
"quantity": 3,
"length": 10800,
"multiplier": 3.0,
"period": "hours",
"price_structure_id": "206c8e98-0263-4e64-8a9a-6dee477153a3"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/price_tiles
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_tiles]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a price tile
How to fetch a price tile:
curl --get 'https://example.booqable.com/api/4/price_tiles/f87df772-a192-4033-84c5-daf41c699939'
--header 'content-type: application/json'
--data-urlencode 'include=price_tiles'
A 200 status response looks like this:
{
"data": {
"id": "f87df772-a192-4033-84c5-daf41c699939",
"type": "price_tiles",
"attributes": {
"created_at": "2024-10-25T02:33:08.000000+00:00",
"updated_at": "2024-10-25T02:33:08.000000+00:00",
"name": "3 hours",
"quantity": 3,
"length": 10800,
"multiplier": 3.0,
"period": "hours",
"price_structure_id": "a945c0c5-af5b-404b-87fd-9096543d28f9"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/price_tiles/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_tiles]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=price_structure |
Includes
This request accepts the following includes:
price_structure
Create a price tile
How to create a price tile:
curl --request POST
--url 'https://example.booqable.com/api/4/price_tiles'
--header 'content-type: application/json'
--data '{
"data": {
"type": "price_tiles",
"attributes": {
"price_structure_id": "8f39c1c4-b736-4059-8db2-de921565f8e7",
"name": "3 hours",
"quantity": 3,
"period": "hours",
"multiplier": 3
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "9adeb1b0-13d6-4add-8865-6795db1fd6f0",
"type": "price_tiles",
"attributes": {
"created_at": "2023-05-15T06:12:04.000000+00:00",
"updated_at": "2023-05-15T06:12:04.000000+00:00",
"name": "3 hours",
"quantity": 3,
"length": 10800,
"multiplier": 3.0,
"period": "hours",
"price_structure_id": "8f39c1c4-b736-4059-8db2-de921565f8e7"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/price_tiles
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_tiles]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=price_structure |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][multiplier] |
float The amount to multiply a product's base price with (e.g. 2.8 for three days). |
data[attributes][name] |
string Name of the tile, which will be used as charge label in the store and on lines. |
data[attributes][period] |
enum Period. One of: hours, days, weeks, months, years. |
data[attributes][price_structure_id] |
uuid PriceStructure this price tile is part of. |
data[attributes][quantity] |
integer Used in combination with period (e.g. 3 with period days). |
Includes
This request accepts the following includes:
price_structure
Update a price tile
How to update a price tile:
curl --request PUT
--url 'https://example.booqable.com/api/4/price_tiles/37e5319a-6e66-49a9-8d18-9d98fef25147'
--header 'content-type: application/json'
--data '{
"data": {
"id": "37e5319a-6e66-49a9-8d18-9d98fef25147",
"type": "price_tiles",
"attributes": {
"name": "4 days",
"quantity": 4,
"period": "days",
"multiplier": 4
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "37e5319a-6e66-49a9-8d18-9d98fef25147",
"type": "price_tiles",
"attributes": {
"created_at": "2027-02-09T08:16:02.000000+00:00",
"updated_at": "2027-02-09T08:16:02.000000+00:00",
"name": "4 days",
"quantity": 4,
"length": 345600,
"multiplier": 4.0,
"period": "days",
"price_structure_id": "754fab8c-2d27-4abc-8d24-c5b673ca95f6"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/price_tiles/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_tiles]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=price_structure |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][multiplier] |
float The amount to multiply a product's base price with (e.g. 2.8 for three days). |
data[attributes][name] |
string Name of the tile, which will be used as charge label in the store and on lines. |
data[attributes][period] |
enum Period. One of: hours, days, weeks, months, years. |
data[attributes][price_structure_id] |
uuid PriceStructure this price tile is part of. |
data[attributes][quantity] |
integer Used in combination with period (e.g. 3 with period days). |
Includes
This request accepts the following includes:
price_structure
Delete a price tile
How to delete a price tile:
curl --request DELETE
--url 'https://example.booqable.com/api/4/price_tiles/46af1ccd-943e-408c-8de5-d7b51faf300b'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "46af1ccd-943e-408c-8de5-d7b51faf300b",
"type": "price_tiles",
"attributes": {
"created_at": "2021-11-04T04:21:00.000000+00:00",
"updated_at": "2021-11-04T04:21:00.000000+00:00",
"name": "3 hours",
"quantity": 3,
"length": 10800,
"multiplier": 3.0,
"period": "hours",
"price_structure_id": "b51ac374-2b75-4abf-8c3c-6691345dda34"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/price_tiles/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[price_tiles]=created_at,updated_at,name |
Includes
This request does not accept any includes
Products
Products are items that can be booked on orders. They always belong to a product group and can only be created separately if the group has variations enabled.
A product inherits most of its attributes from the product group. Inherited attributes can only be changed through the product group, and will then be applied to all products that belong to the same product group.
The following attributes/relations can be configured on individual products when variations are enabled:
variation_values, to make each variation distinctsorting_weight, to control order in which variations are shownbase_price_in_cents, to give each variation its own pricephoto, to assign a different photo to each variationbarcode, to be able to scan and identify different variations
Relationships
| Name | Description |
|---|---|
barcode |
Barcode optionalThe Barcode that points to this product. |
inventory_levels |
Inventory levels hasmanyAvailability of this product. |
photo |
Photo optionalPhoto of this Product variation. This must be one of the photos associated with the ProductGroup. It is not possible to assign a Photo to a Product variation that is not part of the Photos of the ProductGroup. |
price_ruleset |
Price ruleset optionalThe PriceRuleset to use for advanced price calculations. This is inherited from the ProductGroup this product belongs to. |
price_structure |
Price structure optionalThe PriceStructure to use when this product uses tiered pricing. This is inherited from the ProductGroup this product belongs to. |
product_group |
Product group requiredThe ProductGroup this product belongs to. When a product group does not have variations, there will be exactly one product record. When variations are enabled, then there can be multiple product records. |
properties |
Properties hasmanyCustom structured data about this product, based on DefaultProperties. These are inherited from the ProductGroup this product belongs to. While it is possible to sideload properties for products, it is not possible to assign them. |
tax_category |
Tax category optionalTaxCategory for tax calculations. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the item is archived. |
archived_at |
datetime readonly nullableWhen the item was archived. |
base_price_in_cents |
integer The value that is being calculated with. This value is writable if group has variations enabled, otherwise it's inherited from the group. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
photo_id |
uuid nullablePhoto of this Product variation. This must be one of the photos associated with the ProductGroup. It is not possible to assign a Photo to a Product variation that is not part of the Photos of the ProductGroup. |
photo_url |
string readonly nullableMain photo URL. |
product_group_id |
uuid readonly-after-createThe ProductGroup this product belongs to. When a product group does not have variations, there will be exactly one product record. When variations are enabled, then there can be multiple product records. |
sorting_weight |
integer Defines sorting of variations within a product group. The lower the weight - the higher it shows up in lists. |
type |
string readonlyAlways product. |
updated_at |
datetime readonlyWhen the resource was last updated. |
variation_values |
array[string] List of values corresponding to the fields defined in product_group.variation_fields. Values should be in the same order as the fields. product_group.variation_fields are the keys, and product.variation_values are the values, and they are matched by their index in the arrays. |
Inherited Fields
| Name | Description |
|---|---|
allow_shortage |
boolean readonlyWhether shortages are allowed. |
buffer_time_after |
integer readonlyThe amount of seconds the item should be unavailable after a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lag_time in the v1 api and v1 webhooks. |
buffer_time_before |
integer readonlyThe amount of seconds the item should be unavailable before a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lead_time in the v1 api and v1 webhooks. |
deposit_in_cents |
integer readonlyThe value to use for deposit calculations. |
description |
string readonly nullableDescription used in the online store. |
discountable |
boolean readonlyWhether discounts should be applied to this item (note that price rules will still apply). |
excerpt |
string readonly nullableExcerpt used in the online store. |
extra_information |
string readonly nullableExtra information about the item, shown on orders and documents. |
group_name |
string readonlyThe name of the product group. |
has_variations |
boolean readonlyWhether variations are enabled. Not applicable for product_type service. |
name |
string readonlyName of the item (based on product group and variations_values). |
price_period |
enum readonlyThe period which is the base for price calculation when price type simple.One of: hour, day, week, month. |
price_ruleset_id |
uuid readonly nullableThe PriceRuleset to use for advanced price calculations. This is inherited from the ProductGroup this product belongs to. |
price_structure_id |
uuid readonly nullableThe PriceStructure to use when this product uses tiered pricing. This is inherited from the ProductGroup this product belongs to. |
price_type |
enum readonlyThey way prices are calculated for this product. One of: structure, private_structure, fixed, simple, none. |
product_type |
enum readonlyType of product. The sales_item type used to be called consumable. v1 apis and webhooks will return consumable.One of: rental, sales_item, service. |
properties |
hash readonlyKey value pairs of associated properties. This is the same data as provided by the properties relation, but without information about type and position. |
seo_description |
string readonly nullableSEO meta description tag. |
seo_title |
string readonly nullableSEO title tag. |
shortage_limit |
integer readonlyThe maximum allowed shortage for any date range. |
show_in_store |
boolean readonlyWhether to show this item in the online store. |
sku |
string readonlyStock keeping unit. |
slug |
string readonlySlug of the product. |
tag_list |
array readonlyList of tags. |
tax_category_id |
uuid readonly nullableTaxCategory for tax calculations. |
taxable |
boolean readonlyWhether the item is taxable. |
trackable |
boolean readonlyWhether stock items are tracked. |
tracking_type |
enum readonlyHow the product is tracked. One of: none, bulk, trackable. |
variation |
boolean readonlyWhether this Item is a variation in a product group. |
List products
How to fetch a list of products:
curl --get 'https://example.booqable.com/api/4/products'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "ed6e7fb4-7f13-4729-8dce-0f8b8c640d0b",
"type": "products",
"attributes": {
"created_at": "2017-02-21T06:58:03.000000+00:00",
"updated_at": "2017-02-21T06:58:03.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": "iPad Pro",
"slug": "ipad-pro",
"sku": null,
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": true,
"variation": true,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [
"green"
],
"product_group_id": "66a43973-a27a-4282-8f4a-c125934b1469"
},
"relationships": {}
},
{
"id": "e78aa4d3-4a0b-4904-8980-60f6cc41d84d",
"type": "products",
"attributes": {
"created_at": "2017-02-21T06:58:03.000000+00:00",
"updated_at": "2017-02-21T06:58:03.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "iPad Pro - blue",
"group_name": "iPad Pro",
"slug": "ipad-pro-blue",
"sku": "PRODUCT 1000061",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": true,
"variation": true,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 2,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [
"blue"
],
"product_group_id": "66a43973-a27a-4282-8f4a-c125934b1469"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/products
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[products]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=barcode,inventory_levels,photo |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
allow_shortage |
boolean eq |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
base_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_after |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_before |
integer eq, not_eq, gt, gte, lt, lte |
collection_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
group_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
has_variations |
boolean eq |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
price_period |
enum eq |
price_ruleset_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_type |
enum eq |
product_group_id |
uuid eq, not_eq |
product_type |
enum eq |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
shortage_limit |
integer eq, not_eq, gt, gte, lt, lte |
show_in_store |
boolean eq |
sku |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
array eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
trackable |
boolean eq |
tracking_type |
enum eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
variation |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
base_price_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
discountable |
array count |
price_period |
array count |
price_type |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
tracking_type |
array count |
Includes
This request accepts the following includes:
barcodeinventory_levelsphoto-
price_structureprice_tiles
product_grouppropertiestax_category
Search products
Use advanced search to make logical filter groups with and/or operators.
How to search for products:
curl --request POST
--url 'https://example.booqable.com/api/4/products/search'
--header 'content-type: application/json'
--data '{
"fields": {
"products": "id"
},
"filter": {
"conditions": {
"operator": "or",
"attributes": [
{
"operator": "and",
"attributes": [
{
"discountable": true
},
{
"taxable": true
}
]
},
{
"operator": "and",
"attributes": [
{
"show_in_store": true
},
{
"taxable": true
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "14ec83de-d661-4078-8309-4f5f36813f83"
},
{
"id": "72a41c5e-63c7-4472-888d-91a3231c4a27"
},
{
"id": "770bd85c-629f-42e8-8a11-2197aa83f218"
},
{
"id": "5b6bf5cc-4d27-4c95-8d55-9b672d09fc2c"
}
]
}
HTTP Request
POST /api/4/products/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[products]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=barcode,inventory_levels,photo |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
allow_shortage |
boolean eq |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
base_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_after |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_before |
integer eq, not_eq, gt, gte, lt, lte |
collection_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
group_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
has_variations |
boolean eq |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
price_period |
enum eq |
price_ruleset_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_type |
enum eq |
product_group_id |
uuid eq, not_eq |
product_type |
enum eq |
q |
string eq |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
shortage_limit |
integer eq, not_eq, gt, gte, lt, lte |
show_in_store |
boolean eq |
sku |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
array eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
trackable |
boolean eq |
tracking_type |
enum eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
variation |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
base_price_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
discountable |
array count |
price_period |
array count |
price_type |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
tracking_type |
array count |
Includes
This request accepts the following includes:
barcodeinventory_levelsphoto-
price_structureprice_tiles
product_grouppropertiestax_category
Fetch a product
How to fetch a product:
curl --get 'https://example.booqable.com/api/4/products/8f191698-6a00-445a-8b40-3f5449981539'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "8f191698-6a00-445a-8b40-3f5449981539",
"type": "products",
"attributes": {
"created_at": "2022-10-14T09:41:00.000000+00:00",
"updated_at": "2022-10-14T09:41:00.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": "iPad Pro",
"slug": "ipad-pro",
"sku": null,
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": true,
"variation": true,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [
"green"
],
"product_group_id": "c22ea0d0-9487-4cab-86f8-2859a76f32e4"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/products/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[products]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=barcode,inventory_levels,photo |
Includes
This request accepts the following includes:
barcodeinventory_levelsphoto-
price_structureprice_tiles
product_grouppropertiestax_category
Create a product
How to create a product:
curl --request POST
--url 'https://example.booqable.com/api/4/products'
--header 'content-type: application/json'
--data '{
"data": {
"type": "products",
"attributes": {
"product_group_id": "a048e1e3-6c98-4b3f-8a9b-e693eefeebac",
"variation_values": [
"red"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "ccab90b8-7b93-4828-8ec0-7de6cb6e0c4a",
"type": "products",
"attributes": {
"created_at": "2017-11-22T20:35:01.000000+00:00",
"updated_at": "2017-11-22T20:35:01.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "iPad Pro - red",
"group_name": "iPad Pro",
"slug": "ipad-pro-red",
"sku": null,
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": true,
"variation": true,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 3,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [
"red"
],
"product_group_id": "a048e1e3-6c98-4b3f-8a9b-e693eefeebac"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/products
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[products]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=barcode,inventory_levels,photo |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][base_price_in_cents] |
integer The value that is being calculated with. This value is writable if group has variations enabled, otherwise it's inherited from the group. |
data[attributes][photo_id] |
uuid Photo of this Product variation. This must be one of the photos associated with the ProductGroup. It is not possible to assign a Photo to a Product variation that is not part of the Photos of the ProductGroup. |
data[attributes][product_group_id] |
uuid The ProductGroup this product belongs to. When a product group does not have variations, there will be exactly one product record. When variations are enabled, then there can be multiple product records. |
data[attributes][sorting_weight] |
integer Defines sorting of variations within a product group. The lower the weight - the higher it shows up in lists. |
data[attributes][variation_values] |
array[string] List of values corresponding to the fields defined in product_group.variation_fields. Values should be in the same order as the fields. product_group.variation_fields are the keys, and product.variation_values are the values, and they are matched by their index in the arrays. |
Includes
This request accepts the following includes:
barcodeinventory_levelsphoto-
price_structureprice_tiles
product_grouppropertiestax_category
Update a product
How to update a product:
curl --request PUT
--url 'https://example.booqable.com/api/4/products/d2da581f-c48e-4b27-8d9d-9fc0d8b00c8f'
--header 'content-type: application/json'
--data '{
"data": {
"id": "d2da581f-c48e-4b27-8d9d-9fc0d8b00c8f",
"type": "products",
"attributes": {
"variation_values": [
"red"
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "d2da581f-c48e-4b27-8d9d-9fc0d8b00c8f",
"type": "products",
"attributes": {
"created_at": "2027-05-05T21:58:04.000000+00:00",
"updated_at": "2027-05-05T21:58:04.000000+00:00",
"type": "products",
"archived": false,
"archived_at": null,
"name": "iPad Pro - red",
"group_name": "iPad Pro",
"slug": "ipad-pro",
"sku": null,
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": true,
"variation": true,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [
"red"
],
"product_group_id": "302a3d1f-b536-467c-8597-35c1733fc1a7"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/products/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[products]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=barcode,inventory_levels,photo |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][base_price_in_cents] |
integer The value that is being calculated with. This value is writable if group has variations enabled, otherwise it's inherited from the group. |
data[attributes][photo_id] |
uuid Photo of this Product variation. This must be one of the photos associated with the ProductGroup. It is not possible to assign a Photo to a Product variation that is not part of the Photos of the ProductGroup. |
data[attributes][product_group_id] |
uuid The ProductGroup this product belongs to. When a product group does not have variations, there will be exactly one product record. When variations are enabled, then there can be multiple product records. |
data[attributes][sorting_weight] |
integer Defines sorting of variations within a product group. The lower the weight - the higher it shows up in lists. |
data[attributes][variation_values] |
array[string] List of values corresponding to the fields defined in product_group.variation_fields. Values should be in the same order as the fields. product_group.variation_fields are the keys, and product.variation_values are the values, and they are matched by their index in the arrays. |
Includes
This request accepts the following includes:
barcodeinventory_levelsphoto-
price_structureprice_tiles
product_grouppropertiestax_category
Archive a product
How to delete a product:
curl --request DELETE
--url 'https://example.booqable.com/api/4/products/5fe125ba-4a82-4fad-8a18-03ea09db75a3'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "5fe125ba-4a82-4fad-8a18-03ea09db75a3",
"type": "products",
"attributes": {
"created_at": "2021-02-18T21:58:00.000000+00:00",
"updated_at": "2021-02-18T21:58:00.000000+00:00",
"type": "products",
"archived": true,
"archived_at": "2021-02-18T21:58:00.000000+00:00",
"name": "iPad Pro",
"group_name": "iPad Pro",
"slug": "5fe125ba-4a82-4fad-8a18-03ea09db75a3",
"sku": null,
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": true,
"variation": true,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 1,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_values": [
"green"
],
"product_group_id": "a220adae-27d9-4298-8e37-e44d9f89f5db"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/products/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[products]=created_at,updated_at,type |
Includes
This request does not accept any includes
Product groups
Product groups hold general information and configuration about products. A product group always contains at least one product. When a product group is enabled to have variations, it can have multiple products.
Product groups are not plannable on orders. Products are the resource that is planned.
Product Types
- Rental: Rental products are your main products that you rent out. Even if your main product is officially a service, in Booqable you will want to add it as a rental product.
- Sales items: Sales items are products that you do not plan on getting back.
These are meant to be small items that you plan on selling along with a rental but do
not expect to be returned with the rest of the order.
The
sales_itemtype used to be calledconsumable. v1 apis and webhooks will returnconsumable. - Service: Service Item or Service Products are the optional extra services (or items) you want to offer to your products. These are not trackable, therefore they do not have an identifier.
Tracking Types
The tracking type determines how the product is tracked.
- None: Products are not tracked (only for product_type
service,sales_item) - Trackable: Trackable Products tend to be the larger ticket items; the products you want to know specifically who has what stock item of what product and when. With trackable products, every stock item has its own identifier so you can assign and track the individual products (only for product_type
rental). - Bulk: Bulk products are for those products you don't necessarily need to track each specific stock item but rather you just need to know how many you have in stock. These tend to be your smaller ticket items or items that are quicker to replace in bulk if some are lost (only for product_type
rental,sales_item).
Pricing Types
- None: Products are free (applies to all product types)
- Fixed: Charge a fixed price (applies to all product types).
- Simple: Apply simple pricing (depends on
price_period, only for product_typerental,service). - Structure: Applies associated price structure (only for product_type
rental,service). - Private structure: Applies associated private price structure (only for product_type
rental,service).
Relationships
| Name | Description |
|---|---|
inventory_levels |
Inventory levels hasmanyAvailability of this item. |
photo |
Photo optionalPrimary Photo of this product group. |
photos |
Photos hasmanyAll Photos of this product group. The primary photo must be selected from this set. |
price_ruleset |
Price ruleset optionalThe PriceRuleset used for advanced price calculations. |
price_structure |
Price structure optionalThe PriceStructure to use when this product group uses tiered pricing. |
products |
Products hasmanyWhen this product group does not have variations: there will be exactly one product. When this product group does have variations: one or more products. These products can be distinguished by their variation_values. |
properties |
Properties hasmanyCustom structured data about this product group, based on DefaultProperties. These properties apply to all products in the same product group. |
tax_category |
Tax category optionalTaxCategory for tax calculations. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the product group is archived. |
archived_at |
datetime readonly nullableWhen the product group was archived. |
base_price_in_cents |
integer readonlyThe value that is being calculated with (based on the current price_type). |
confirm_shortage |
boolean writeonlySet this to true to override certain shortage warnings. |
created_at |
datetime readonlyWhen the resource was created. |
flat_fee_price_in_cents |
integer Use this value when price type is simple. |
id |
uuid readonlyPrimary key. |
photo_base64 |
string writeonlyBase64 encoded photo, use this field to store a main photo. |
photo_id |
uuid readonly nullablePrimary Photo of this product group. |
photo_url |
string readonly nullableMain photo URL. |
properties_attributes |
array writeonlyCreate or update multiple properties associated with this product group. |
remote_photo_url |
string writeonlyURL to an image on the web. |
sorting_weight |
integer Defines sort order in the online store, the lower the weight - the higher it shows up in lists. |
stock_item_properties |
array[string] Names of custom properties for stock items of this product group. |
structure_price_in_cents |
integer Use this value when price type is structure or private_structure. |
type |
string readonlyAlways product group. |
updated_at |
datetime readonlyWhen the resource was last updated. |
variation_fields |
array Array of fields that distinguish variations (e.g. color or size). product_group.variation_fields are the keys, and product.variation_values are the values, and they are matched by their index in the arrays. |
Inherited Fields
| Name | Description |
|---|---|
allow_shortage |
boolean Whether shortages are allowed. Changing this setting affects availability, and can trigger a shortage warning. |
buffer_time_after |
integer The amount of seconds the item should be unavailable after a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lag_time in the v1 api and v1 webhooks. |
buffer_time_before |
integer The amount of seconds the item should be unavailable before a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lead_time in the v1 api and v1 webhooks. |
deposit_in_cents |
integer The value to use for deposit calculations. |
description |
string nullableDescription used in the online store. |
discountable |
boolean Whether discounts should be applied to this product groups and products in it (note that price rules will still apply). |
excerpt |
string nullableExcerpt used in the online store. |
extra_information |
string nullableExtra information about the product group, shown on orders and documents. |
group_name |
string readonlySame as name. |
has_variations |
boolean Whether variations are enabled. Variations can be enabled after a product group has been created, but variations cannot be disabled once they have been enabled. Product group of product_type service cannot have variations. |
name |
string Name of the item. |
price_period |
enum The period which is the base for price calculation when price type simple.One of: hour, day, week, month. |
price_ruleset_id |
uuid nullableThe PriceRuleset used for advanced price calculations. |
price_structure_id |
uuid nullableThe PriceStructure to use when this product group uses tiered pricing. |
price_type |
enum How prices are calculated for this product group and all products in it. One of: structure, private_structure, fixed, simple, none. |
product_type |
enum Type of product. Can only be set when creating a ProductGroup. The sales_item type used to be called consumable. v1 apis and webhooks will return consumable.One of: rental, sales_item, service. |
properties |
hash readonlyHash of properties. Sideload the properties relation when more information is needed. |
seo_description |
string nullableSEO meta description tag. |
seo_title |
string nullableSEO title tag. |
shortage_limit |
integer The maximum allowed shortage for any date range. Changing this setting affects availability, and can trigger a shortage warning. |
show_in_store |
boolean Whether to show this product group in the online store. |
sku |
string Stock keeping unit. |
slug |
string Slug of the item. |
tag_list |
array[string] List of tags. |
tax_category_id |
uuid nullableTaxCategory for tax calculations. |
taxable |
boolean Whether this product group is taxable. |
trackable |
boolean readonly-after-createWhether stock items are tracked. |
tracking_type |
enum readonly-after-createHow the product is tracked. Can only be set when creating a ProductGroup. One of: none, bulk, trackable. |
variation |
boolean readonlyWhether this Item is a variation in a ProductGroup. |
List product groups
How to fetch a list of product groups:
curl --get 'https://example.booqable.com/api/4/product_groups'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "f0f79b63-e2b9-4178-81f6-3b28593c5419",
"type": "product_groups",
"attributes": {
"created_at": "2026-12-03T23:48:01.000000+00:00",
"updated_at": "2026-12-03T23:48:01.000000+00:00",
"type": "product_groups",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": null,
"slug": "ipad-pro",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_fields": [],
"flat_fee_price_in_cents": 0,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/product_groups
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[product_groups]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=photo,properties |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
allow_shortage |
boolean eq |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
base_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_after |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_before |
integer eq, not_eq, gt, gte, lt, lte |
collection_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
flat_fee_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
group_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
has_variations |
boolean eq |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
price_period |
enum eq |
price_ruleset_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_type |
enum eq |
product_group_id |
uuid eq |
product_type |
enum eq |
q |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
shortage_limit |
integer eq, not_eq, gt, gte, lt, lte |
show_in_store |
boolean eq |
sku |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
structure_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
trackable |
boolean eq |
tracking_type |
enum eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
variation |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
base_price_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
discountable |
array count |
price_period |
array count |
price_type |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
tracking_type |
array count |
Includes
This request accepts the following includes:
photoproperties
Search product groups
Use advanced search to make logical filter groups with and/or operators.
How to search for product groups:
curl --request POST
--url 'https://example.booqable.com/api/4/product_groups/search'
--header 'content-type: application/json'
--data '{
"fields": {
"product_groups": "id"
},
"filter": {
"conditions": {
"operator": "or",
"attributes": [
{
"operator": "and",
"attributes": [
{
"discountable": true
},
{
"taxable": true
}
]
},
{
"operator": "and",
"attributes": [
{
"show_in_store": true
},
{
"taxable": true
}
]
}
]
}
}
}'
A 200 status response looks like this:
{
"data": [
{
"id": "4c211b3b-f619-45e3-8a3a-c020abe4ddf8"
},
{
"id": "b0871c21-545a-427e-87a2-34b8dd0977b6"
},
{
"id": "caa90af2-e33d-464c-836f-2e933d2bc1c8"
}
]
}
HTTP Request
POST /api/4/product_groups/search
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[product_groups]=created_at,updated_at,type |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=photo,properties |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
allow_shortage |
boolean eq |
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
base_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_after |
integer eq, not_eq, gt, gte, lt, lte |
buffer_time_before |
integer eq, not_eq, gt, gte, lt, lte |
collection_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
deposit_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
discountable |
boolean eq |
excerpt |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
extra_information |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
flat_fee_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
group_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
has_variations |
boolean eq |
id |
uuid eq, not_eq, gt |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
photo_id |
uuid eq, not_eq |
price_period |
enum eq |
price_ruleset_id |
uuid eq, not_eq |
price_structure_id |
uuid eq, not_eq |
price_type |
enum eq |
product_group_id |
uuid eq |
product_type |
enum eq |
q |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_description |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
seo_title |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
shortage_limit |
integer eq, not_eq, gt, gte, lt, lte |
show_in_store |
boolean eq |
sku |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
slug |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
sorting_weight |
integer eq, not_eq, gt, gte, lt, lte |
structure_price_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
tag_list |
string eq |
tax_category_id |
uuid eq, not_eq |
taxable |
boolean eq |
trackable |
boolean eq |
tracking_type |
enum eq |
type |
string eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
variation |
boolean eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
archived |
array count |
base_price_in_cents |
array sum, maximum, minimum, average |
deposit_in_cents |
array sum, maximum, minimum, average |
discountable |
array count |
price_period |
array count |
price_type |
array count |
product_type |
array count |
show_in_store |
array count |
tag_list |
array count |
tax_category_id |
array count |
taxable |
array count |
total |
array count |
tracking_type |
array count |
Includes
This request accepts the following includes:
photoproperties
Fetch a product group
How to fetch a product group:
curl --get 'https://example.booqable.com/api/4/product_groups/edabcdd8-89b1-46a8-8163-98ae0d275cd1'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "edabcdd8-89b1-46a8-8163-98ae0d275cd1",
"type": "product_groups",
"attributes": {
"created_at": "2025-01-22T17:59:01.000000+00:00",
"updated_at": "2025-01-22T17:59:01.000000+00:00",
"type": "product_groups",
"archived": false,
"archived_at": null,
"name": "iPad Pro",
"group_name": null,
"slug": "ipad-pro",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_fields": [],
"flat_fee_price_in_cents": 0,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/product_groups/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[product_groups]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=photo,properties,tax_category |
Includes
This request accepts the following includes:
barcodephoto-
price_structureprice_tiles
productspropertiestax_category
Create a product group
How to create a product group:
curl --request POST
--url 'https://example.booqable.com/api/4/product_groups'
--header 'content-type: application/json'
--data '{
"data": {
"type": "product_groups",
"attributes": {
"name": "iPad mini",
"tracking_type": "trackable",
"trackable": true,
"price_type": "simple",
"price_period": "day",
"tag_list": [
"tablets",
"apple"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "56ea2eb6-d09f-4f5d-8482-6eb1e7af9908",
"type": "product_groups",
"attributes": {
"created_at": "2018-12-20T06:18:00.000000+00:00",
"updated_at": "2018-12-20T06:18:00.000000+00:00",
"type": "product_groups",
"archived": false,
"archived_at": null,
"name": "iPad mini",
"group_name": null,
"slug": "ipad-mini",
"sku": "IPAD_MINI",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "trackable",
"trackable": true,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [
"tablets",
"apple"
],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_fields": [],
"flat_fee_price_in_cents": 0,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/product_groups
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[product_groups]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=photo,properties,tax_category |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][allow_shortage] |
boolean Whether shortages are allowed. Changing this setting affects availability, and can trigger a shortage warning. |
data[attributes][buffer_time_after] |
integer The amount of seconds the item should be unavailable after a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lag_time in the v1 api and v1 webhooks. |
data[attributes][buffer_time_before] |
integer The amount of seconds the item should be unavailable before a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lead_time in the v1 api and v1 webhooks. |
data[attributes][confirm_shortage] |
boolean Set this to true to override certain shortage warnings. |
data[attributes][deposit_in_cents] |
integer The value to use for deposit calculations. |
data[attributes][discountable] |
boolean Whether discounts should be applied to this product groups and products in it (note that price rules will still apply). |
data[attributes][excerpt] |
string Excerpt used in the online store. |
data[attributes][extra_information] |
string Extra information about the product group, shown on orders and documents. |
data[attributes][flat_fee_price_in_cents] |
integer Use this value when price type is simple. |
data[attributes][has_variations] |
boolean Whether variations are enabled. Variations can be enabled after a product group has been created, but variations cannot be disabled once they have been enabled. Product group of product_type service cannot have variations. |
data[attributes][name] |
string Name of the item. |
data[attributes][photo_base64] |
string Base64 encoded photo, use this field to store a main photo. |
data[attributes][price_period] |
enum The period which is the base for price calculation when price type simple.One of: hour, day, week, month. |
data[attributes][price_ruleset_id] |
uuid The PriceRuleset used for advanced price calculations. |
data[attributes][price_structure_id] |
uuid The PriceStructure to use when this product group uses tiered pricing. |
data[attributes][price_type] |
enum How prices are calculated for this product group and all products in it. One of: structure, private_structure, fixed, simple, none. |
data[attributes][product_type] |
enum Type of product. Can only be set when creating a ProductGroup. The sales_item type used to be called consumable. v1 apis and webhooks will return consumable.One of: rental, sales_item, service. |
data[attributes][properties_attributes][] |
array Create or update multiple properties associated with this product group. |
data[attributes][remote_photo_url] |
string URL to an image on the web. |
data[attributes][seo_description] |
string SEO meta description tag. |
data[attributes][seo_title] |
string SEO title tag. |
data[attributes][shortage_limit] |
integer The maximum allowed shortage for any date range. Changing this setting affects availability, and can trigger a shortage warning. |
data[attributes][show_in_store] |
boolean Whether to show this product group in the online store. |
data[attributes][sku] |
string Stock keeping unit. |
data[attributes][slug] |
string Slug of the item. |
data[attributes][sorting_weight] |
integer Defines sort order in the online store, the lower the weight - the higher it shows up in lists. |
data[attributes][stock_item_properties] |
array[string] Names of custom properties for stock items of this product group. |
data[attributes][structure_price_in_cents] |
integer Use this value when price type is structure or private_structure. |
data[attributes][tag_list] |
array[string] List of tags. |
data[attributes][tax_category_id] |
uuid TaxCategory for tax calculations. |
data[attributes][taxable] |
boolean Whether this product group is taxable. |
data[attributes][trackable] |
boolean Whether stock items are tracked. |
data[attributes][tracking_type] |
enum How the product is tracked. Can only be set when creating a ProductGroup. One of: none, bulk, trackable. |
data[attributes][variation_fields][] |
array Array of fields that distinguish variations (e.g. color or size). product_group.variation_fields are the keys, and product.variation_values are the values, and they are matched by their index in the arrays. |
Includes
This request accepts the following includes:
barcodephoto-
price_structureprice_tiles
propertiestax_category
Update a product group
How to update a product group:
curl --request PUT
--url 'https://example.booqable.com/api/4/product_groups/a32d904d-cb11-4b83-80c4-5974eff77dc8'
--header 'content-type: application/json'
--data '{
"data": {
"id": "a32d904d-cb11-4b83-80c4-5974eff77dc8",
"type": "product_groups",
"attributes": {
"name": "iPad mini"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "a32d904d-cb11-4b83-80c4-5974eff77dc8",
"type": "product_groups",
"attributes": {
"created_at": "2017-06-27T18:12:01.000000+00:00",
"updated_at": "2017-06-27T18:12:01.000000+00:00",
"type": "product_groups",
"archived": false,
"archived_at": null,
"name": "iPad mini",
"group_name": null,
"slug": "ipad-pro",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_fields": [],
"flat_fee_price_in_cents": 0,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/product_groups/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[product_groups]=created_at,updated_at,type |
include |
string List of comma seperated relationships to sideload. ?include=photo,properties,tax_category |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][allow_shortage] |
boolean Whether shortages are allowed. Changing this setting affects availability, and can trigger a shortage warning. |
data[attributes][buffer_time_after] |
integer The amount of seconds the item should be unavailable after a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lag_time in the v1 api and v1 webhooks. |
data[attributes][buffer_time_before] |
integer The amount of seconds the item should be unavailable before a reservation. Changing this setting affects availability, and can trigger a shortage warning. This attribute is called lead_time in the v1 api and v1 webhooks. |
data[attributes][confirm_shortage] |
boolean Set this to true to override certain shortage warnings. |
data[attributes][deposit_in_cents] |
integer The value to use for deposit calculations. |
data[attributes][discountable] |
boolean Whether discounts should be applied to this product groups and products in it (note that price rules will still apply). |
data[attributes][excerpt] |
string Excerpt used in the online store. |
data[attributes][extra_information] |
string Extra information about the product group, shown on orders and documents. |
data[attributes][flat_fee_price_in_cents] |
integer Use this value when price type is simple. |
data[attributes][has_variations] |
boolean Whether variations are enabled. Variations can be enabled after a product group has been created, but variations cannot be disabled once they have been enabled. Product group of product_type service cannot have variations. |
data[attributes][name] |
string Name of the item. |
data[attributes][photo_base64] |
string Base64 encoded photo, use this field to store a main photo. |
data[attributes][price_period] |
enum The period which is the base for price calculation when price type simple.One of: hour, day, week, month. |
data[attributes][price_ruleset_id] |
uuid The PriceRuleset used for advanced price calculations. |
data[attributes][price_structure_id] |
uuid The PriceStructure to use when this product group uses tiered pricing. |
data[attributes][price_type] |
enum How prices are calculated for this product group and all products in it. One of: structure, private_structure, fixed, simple, none. |
data[attributes][product_type] |
enum Type of product. Can only be set when creating a ProductGroup. The sales_item type used to be called consumable. v1 apis and webhooks will return consumable.One of: rental, sales_item, service. |
data[attributes][properties_attributes][] |
array Create or update multiple properties associated with this product group. |
data[attributes][remote_photo_url] |
string URL to an image on the web. |
data[attributes][seo_description] |
string SEO meta description tag. |
data[attributes][seo_title] |
string SEO title tag. |
data[attributes][shortage_limit] |
integer The maximum allowed shortage for any date range. Changing this setting affects availability, and can trigger a shortage warning. |
data[attributes][show_in_store] |
boolean Whether to show this product group in the online store. |
data[attributes][sku] |
string Stock keeping unit. |
data[attributes][slug] |
string Slug of the item. |
data[attributes][sorting_weight] |
integer Defines sort order in the online store, the lower the weight - the higher it shows up in lists. |
data[attributes][stock_item_properties] |
array[string] Names of custom properties for stock items of this product group. |
data[attributes][structure_price_in_cents] |
integer Use this value when price type is structure or private_structure. |
data[attributes][tag_list] |
array[string] List of tags. |
data[attributes][tax_category_id] |
uuid TaxCategory for tax calculations. |
data[attributes][taxable] |
boolean Whether this product group is taxable. |
data[attributes][trackable] |
boolean Whether stock items are tracked. |
data[attributes][tracking_type] |
enum How the product is tracked. Can only be set when creating a ProductGroup. One of: none, bulk, trackable. |
data[attributes][variation_fields][] |
array Array of fields that distinguish variations (e.g. color or size). product_group.variation_fields are the keys, and product.variation_values are the values, and they are matched by their index in the arrays. |
Includes
This request accepts the following includes:
barcodephoto-
price_structureprice_tiles
propertiestax_category
Archive a product group
How to delete a product group:
curl --request DELETE
--url 'https://example.booqable.com/api/4/product_groups/0845ee1b-c095-41c8-8179-28d5fe7fd2f3'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "0845ee1b-c095-41c8-8179-28d5fe7fd2f3",
"type": "product_groups",
"attributes": {
"created_at": "2025-02-14T15:30:00.000000+00:00",
"updated_at": "2025-02-14T15:30:00.000000+00:00",
"type": "product_groups",
"archived": true,
"archived_at": "2025-02-14T15:30:00.000000+00:00",
"name": "iPad Pro",
"group_name": null,
"slug": "0845ee1b-c095-41c8-8179-28d5fe7fd2f3",
"sku": "SKU",
"buffer_time_before": 0,
"buffer_time_after": 0,
"product_type": "rental",
"tracking_type": "bulk",
"trackable": false,
"has_variations": false,
"variation": false,
"extra_information": null,
"photo_url": null,
"description": null,
"excerpt": null,
"show_in_store": true,
"sorting_weight": 0,
"base_price_in_cents": 0,
"price_type": "simple",
"price_period": "day",
"deposit_in_cents": 0,
"discountable": true,
"taxable": true,
"seo_title": null,
"seo_description": null,
"tag_list": [],
"properties": {},
"photo_id": null,
"tax_category_id": null,
"price_ruleset_id": null,
"price_structure_id": null,
"allow_shortage": false,
"shortage_limit": 0,
"variation_fields": [],
"flat_fee_price_in_cents": 0,
"structure_price_in_cents": 0,
"stock_item_properties": []
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/product_groups/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[product_groups]=created_at,updated_at,type |
Includes
This request does not accept any includes
Properties
While Booqable comes with standard fields, like a customer's name and a product's SKU, you can add custom properties to capture additional information that's important for you or your customers.
Linking to default properties
Properties inherit their configuration from a default property. When creating properties, they are linked to a default when one of the following fields matches:
name(case insensitive)identifierdefault_property_id
Owners
- Customers
- Orders
- Product groups
Properties belong to products groups, and are the same for all products in a product group.
The
propertiesrelation and attribute of the Product resource contain the properties of the group, and you can sideload them as resource by usingproducts?include=properties. But because properties actually belong to product groups, filtering properties byproduct.iddoes not work.
Types
Properties can have different types and behave differently. These are the values you can supply for each type:
| text_field | Renders a text field |
|---|---|
value |
string |
| text_area | Renders a text area |
|---|---|
value |
string |
| phone | Renders a phone field |
|---|---|
value |
string |
| Renders an email field | |
|---|---|
value |
string |
| date_field | Renders a date picker |
|---|---|
value |
string |
| select | Renders a dropdown select |
|---|---|
value |
string |
| address | Renders multiple fields |
|---|---|
first_name |
string |
last_name |
string |
address1 |
string |
address2 |
string |
city |
string |
region |
string |
zipcode |
string |
country |
string |
country_id |
uuid |
province_id |
uuid |
Using Address Properties with Orders
Address properties are commonly used to set delivery and billing addresses on Orders.
You can provide either string values (like country: "United States") or UUIDs (like country_id: "uuid-here")
for location fields. Using UUIDs is more precise but requires looking up Country and
Province IDs first.
When creating an address property with identifier set to delivery_address or billing_address as part of
an order's properties_attributes, the order will automatically link to it. See the
Orders documentation for complete examples.
Relationships
| Name | Description |
|---|---|
default_property |
Default property optionalThe DefaultProperty this property is linked to. Properties without default property are called "one-off" properties. |
owner |
Customer, Document, Order, Product group, Stock item requiredThe resource this property is about. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
address1 |
string For type address. |
address2 |
string For type address. |
city |
string For type address. |
country |
string For type address. |
country_id |
string For type address. |
created_at |
datetime readonlyWhen the resource was created. |
default_property_id |
uuid nullableThe DefaultProperty this property is linked to. Properties without default property are called "one-off" properties. |
first_name |
string For type address. |
id |
uuid readonlyPrimary key. |
identifier |
string Key that will be used in exports, responses and custom field variables in templates. |
last_name |
string For type address. |
latitude |
string For type address. |
longitude |
string For type address. |
meets_validation_requirements |
boolean readonlyWhether this property meets the validation requirements. |
name |
string Name of the property (used as label and to compute identifier if left blank). |
owner_id |
uuid readonly-after-createThe resource this property is about. |
owner_type |
enum readonly-after-createThe resource type of the owner. One of: customers, documents, orders, product_groups, stock_items. |
position |
integer Which position the property has relative to other properties of the same owner. This determines the sorting of properties when they are displayed. |
property_type |
enum Determines how the data is rendered and the kind of input shown to the user. One of: address, date_field, email, phone, select, text_area, text_field. |
province_id |
string For type address. |
region |
string For type address. |
show_on |
array[string] Array of document types to show this custom field on. Zero or more from contract, invoice, packing, quote. For properties that are linked to a default property, always the value from the default property will be used and the show_on attribute of the individual property is ignored. |
updated_at |
datetime readonlyWhen the resource was last updated. |
validation_required |
boolean Whether this property has to be validated. |
value |
string For type text_field, text_area, phone, email, date_field, or select. |
zipcode |
string For type address. |
Manage properties through their owner
On the following resources you can manage properties
by setting the properties_attribute attribute:
- Customers
- Product groups
- Orders
The properties_attributes attribute is an array of hashes,
each representing a property.
Properties can be managed alongside other attributes when creating or updating an owner.
To delete a property, set the _destroy attribute to true.
Create a property that corresponds with an existing default property (assuming a default phone property exists):
curl --request
--url 'https://example.booqable.com/api/4/customers/78172414-b6f5-44e3-874c-3ca4eafe1a02'
--header 'content-type: application/json'
--data '{
"data": {
"id": "78172414-b6f5-44e3-874c-3ca4eafe1a02",
"type": "customers",
"attributes": {
"properties_attributes": [
{
"identifier": "phone",
"value": "+316000000"
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "78172414-b6f5-44e3-874c-3ca4eafe1a02",
"type": "customers",
"attributes": {
"created_at": "2027-08-03T07:47:02.000000+00:00",
"updated_at": "2027-08-03T07:47:02.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {
"phone": "+316000000"
},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
Create a one-off property (no corresponding default property):
curl --request
--url 'https://example.booqable.com/api/4/customers/48b9cace-e329-4be8-809a-d997d34eb388'
--header 'content-type: application/json'
--data '{
"data": {
"id": "48b9cace-e329-4be8-809a-d997d34eb388",
"type": "customers",
"attributes": {
"properties_attributes": [
{
"name": "Phone",
"value": "+316000000",
"property_type": "phone"
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "48b9cace-e329-4be8-809a-d997d34eb388",
"type": "customers",
"attributes": {
"created_at": "2026-04-01T06:11:06.000000+00:00",
"updated_at": "2026-04-01T06:11:06.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {
"phone": "+316000000"
},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
Deleting a property while updating another one:
curl --request
--url 'https://example.booqable.com/api/4/customers/273e87b8-f7db-4315-8d74-4371f489b516'
--header 'content-type: application/json'
--data '{
"data": {
"type": "customers",
"id": "273e87b8-f7db-4315-8d74-4371f489b516",
"attributes": {
"properties_attributes": [
{
"identifier": "phone",
"_destroy": true
},
{
"identifier": "birthday",
"value": "01-01-1970"
}
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "273e87b8-f7db-4315-8d74-4371f489b516",
"type": "customers",
"attributes": {
"created_at": "2022-01-05T06:05:01.000000+00:00",
"updated_at": "2022-01-05T06:05:01.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {
"birthday": "01-01-1970"
},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
},
"meta": {}
}
Includes
This request does not accept any includes
List properties
How to fetch a list of properties:
curl --get 'https://example.booqable.com/api/4/properties'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": [
{
"id": "e3140ee7-66da-44b5-827f-a62c7f18110d",
"type": "properties",
"attributes": {
"created_at": "2015-06-08T16:26:00.000000+00:00",
"updated_at": "2015-06-08T16:26:00.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 0,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"meets_validation_requirements": true,
"value": "+316000000",
"default_property_id": null,
"owner_id": "b4833bd7-fc68-444f-8965-b78a8ca805e5",
"owner_type": "customers"
},
"relationships": {
"owner": {
"data": {
"type": "customers",
"id": "b4833bd7-fc68-444f-8965-b78a8ca805e5"
}
}
}
}
],
"included": [
{
"id": "b4833bd7-fc68-444f-8965-b78a8ca805e5",
"type": "customers",
"attributes": {
"created_at": "2015-06-08T16:26:00.000000+00:00",
"updated_at": "2015-06-08T16:26:00.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {
"phone": "+316000000"
},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/properties
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[properties]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=owner |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
default_property_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
owner
Fetch a property
How to fetch a property:
curl --get 'https://example.booqable.com/api/4/properties/65f05300-83b5-4cd8-8a15-36bc907ecfe1'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": {
"id": "65f05300-83b5-4cd8-8a15-36bc907ecfe1",
"type": "properties",
"attributes": {
"created_at": "2026-04-19T17:00:00.000000+00:00",
"updated_at": "2026-04-19T17:00:00.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 0,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"meets_validation_requirements": true,
"value": "+316000000",
"default_property_id": null,
"owner_id": "bef24f9a-d753-437a-8b76-468be9985412",
"owner_type": "customers"
},
"relationships": {
"owner": {
"data": {
"type": "customers",
"id": "bef24f9a-d753-437a-8b76-468be9985412"
}
}
}
},
"included": [
{
"id": "bef24f9a-d753-437a-8b76-468be9985412",
"type": "customers",
"attributes": {
"created_at": "2026-04-19T17:00:00.000000+00:00",
"updated_at": "2026-04-19T17:00:00.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "John Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {
"phone": "+316000000"
},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/properties/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[properties]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
owner
Create a property
How to create a property and assign it to an owner:
curl --request POST
--url 'https://example.booqable.com/api/4/properties'
--header 'content-type: application/json'
--data '{
"data": {
"type": "properties",
"attributes": {
"name": "Phone",
"property_type": "phone",
"value": "+316000000",
"owner_id": "7e69a28e-0d76-4024-81cc-bf5354f84c2e",
"owner_type": "customers"
}
},
"include": "owner"
}'
A 201 status response looks like this:
{
"data": {
"id": "a0e53cf2-3711-46d7-86f4-ff9422e2c069",
"type": "properties",
"attributes": {
"created_at": "2023-03-09T00:06:01.000000+00:00",
"updated_at": "2023-03-09T00:06:01.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 0,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"meets_validation_requirements": true,
"value": "+316000000",
"default_property_id": null,
"owner_id": "7e69a28e-0d76-4024-81cc-bf5354f84c2e",
"owner_type": "customers"
},
"relationships": {
"owner": {
"data": {
"type": "customers",
"id": "7e69a28e-0d76-4024-81cc-bf5354f84c2e"
}
}
}
},
"included": [
{
"id": "7e69a28e-0d76-4024-81cc-bf5354f84c2e",
"type": "customers",
"attributes": {
"created_at": "2023-03-09T00:06:01.000000+00:00",
"updated_at": "2023-03-09T00:06:01.000000+00:00",
"archived": false,
"archived_at": null,
"number": 1,
"name": "Jane Doe",
"email": "[email protected]",
"deposit_type": "default",
"deposit_value": 0.0,
"discount_percentage": 0.0,
"legal_type": "person",
"email_marketing_consented": false,
"email_marketing_consent_updated_at": null,
"properties": {
"phone": "+316000000"
},
"tag_list": [],
"stripe_id": null,
"merge_suggestion_customer_id": null,
"tax_region_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/properties
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[properties]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address1] |
string For type address. |
data[attributes][address2] |
string For type address. |
data[attributes][city] |
string For type address. |
data[attributes][country] |
string For type address. |
data[attributes][country_id] |
string For type address. |
data[attributes][default_property_id] |
uuid The DefaultProperty this property is linked to. Properties without default property are called "one-off" properties. |
data[attributes][first_name] |
string For type address. |
data[attributes][identifier] |
string Key that will be used in exports, responses and custom field variables in templates. |
data[attributes][last_name] |
string For type address. |
data[attributes][latitude] |
string For type address. |
data[attributes][longitude] |
string For type address. |
data[attributes][name] |
string Name of the property (used as label and to compute identifier if left blank). |
data[attributes][owner_id] |
uuid The resource this property is about. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: customers, documents, orders, product_groups, stock_items. |
data[attributes][position] |
integer Which position the property has relative to other properties of the same owner. This determines the sorting of properties when they are displayed. |
data[attributes][property_type] |
enum Determines how the data is rendered and the kind of input shown to the user. One of: address, date_field, email, phone, select, text_area, text_field. |
data[attributes][province_id] |
string For type address. |
data[attributes][region] |
string For type address. |
data[attributes][show_on] |
array[string] Array of document types to show this custom field on. Zero or more from contract, invoice, packing, quote. For properties that are linked to a default property, always the value from the default property will be used and the show_on attribute of the individual property is ignored. |
data[attributes][validation_required] |
boolean Whether this property has to be validated. |
data[attributes][value] |
string For type text_field, text_area, phone, email, date_field, or select. |
data[attributes][zipcode] |
string For type address. |
Includes
This request accepts the following includes:
owner
Update a property
How to update a property:
curl --request PUT
--url 'https://example.booqable.com/api/4/properties/a08be1e9-e4aa-4b1e-8a1c-ac9d6fa79d78'
--header 'content-type: application/json'
--data '{
"data": {
"id": "a08be1e9-e4aa-4b1e-8a1c-ac9d6fa79d78",
"type": "properties",
"attributes": {
"value": "+316000001"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "a08be1e9-e4aa-4b1e-8a1c-ac9d6fa79d78",
"type": "properties",
"attributes": {
"created_at": "2028-10-19T14:18:00.000000+00:00",
"updated_at": "2028-10-19T14:18:00.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 0,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"meets_validation_requirements": true,
"value": "+316000001",
"default_property_id": null,
"owner_id": "4e6e1abc-ddfd-434a-89eb-921b87839aff",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/properties/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[properties]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][address1] |
string For type address. |
data[attributes][address2] |
string For type address. |
data[attributes][city] |
string For type address. |
data[attributes][country] |
string For type address. |
data[attributes][country_id] |
string For type address. |
data[attributes][default_property_id] |
uuid The DefaultProperty this property is linked to. Properties without default property are called "one-off" properties. |
data[attributes][first_name] |
string For type address. |
data[attributes][identifier] |
string Key that will be used in exports, responses and custom field variables in templates. |
data[attributes][last_name] |
string For type address. |
data[attributes][latitude] |
string For type address. |
data[attributes][longitude] |
string For type address. |
data[attributes][name] |
string Name of the property (used as label and to compute identifier if left blank). |
data[attributes][owner_id] |
uuid The resource this property is about. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: customers, documents, orders, product_groups, stock_items. |
data[attributes][position] |
integer Which position the property has relative to other properties of the same owner. This determines the sorting of properties when they are displayed. |
data[attributes][property_type] |
enum Determines how the data is rendered and the kind of input shown to the user. One of: address, date_field, email, phone, select, text_area, text_field. |
data[attributes][province_id] |
string For type address. |
data[attributes][region] |
string For type address. |
data[attributes][show_on] |
array[string] Array of document types to show this custom field on. Zero or more from contract, invoice, packing, quote. For properties that are linked to a default property, always the value from the default property will be used and the show_on attribute of the individual property is ignored. |
data[attributes][validation_required] |
boolean Whether this property has to be validated. |
data[attributes][value] |
string For type text_field, text_area, phone, email, date_field, or select. |
data[attributes][zipcode] |
string For type address. |
Includes
This request accepts the following includes:
owner
Delete a property
How to delete a property:
curl --request DELETE
--url 'https://example.booqable.com/api/4/properties/eab99cab-3fac-4afa-88a3-1ce18a98889e'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "eab99cab-3fac-4afa-88a3-1ce18a98889e",
"type": "properties",
"attributes": {
"created_at": "2023-03-23T09:40:01.000000+00:00",
"updated_at": "2023-03-23T09:40:01.000000+00:00",
"name": "Phone",
"identifier": "phone",
"position": 0,
"property_type": "phone",
"show_on": [],
"validation_required": false,
"meets_validation_requirements": null,
"value": "+316000000",
"default_property_id": null,
"owner_id": "229fb004-46fc-4b3f-8564-613cc13d86db",
"owner_type": "customers"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/properties/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[properties]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
owner
Provinces
The Province resource describes provinces/states etc. in a country.
Relationships
| Name | Description |
|---|---|
country |
Country requiredThe Country the province/state belongs to. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
code |
string readonlyThe code of the province/state. |
country_id |
uuid readonlyThe Country the province/state belongs to. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
name |
string readonlyThe name of the province/state. |
position |
integer readonlyThe position of the province/state in the list. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List provinces
How to fetch a list of provinces:
curl --get 'https://example.booqable.com/api/4/provinces'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "3026cccd-b110-4086-805e-a014d51387c0",
"type": "provinces",
"attributes": {
"created_at": "2027-04-07T00:26:00.000000+00:00",
"updated_at": "2027-04-07T00:26:00.000000+00:00",
"name": "Friesland",
"code": "FR",
"position": 0,
"country_id": "f5f75fb6-0967-4cc7-862d-b277d7a5bd44"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/provinces
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[provinces]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
code |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
country_id |
uuid eq, not_eq |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
position |
integer eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Settings
Settings are configured globally for a company account. They are divided in the following sections:
Currency
Information on how to display and handle the currency.
| Name | Description |
|---|---|
name |
String readonlyCurrency code |
decimal |
String readonlyDecimal separator |
thousand |
String readonlyThousand separator |
symbol |
String readonlyCurrency symbol |
precision |
String readonlyPrecision |
format |
String readonlyThe format |
Defaults
Defaults derived from other resources.
| Name | Description |
|---|---|
timezone |
String readonlyThe default timezone (managed on the company resource) |
timezone_offset |
Integer readonlyThe UTC offset of the default timezone, in minutes |
tax_category_id |
Uuid readonlyID the default tax category |
tax_region_id |
Uuid readonlyID the default tax region |
Pricing
Configuration on how to handle and display pricing
| Name | Description |
|---|---|
enabled |
Boolean Whether pricing is enabled |
tax_strategy |
Uuid How taxes should be calculated, one of exclusive, inclusive |
deposit_type |
String Default deposit type (applied to orders if customer deposit type is default, one of none, percentage_total, percentage, fixed) |
deposit_value |
Integer Default deposit value (applied to orders if customer deposit type is default) |
currency_format |
String Currency format |
currency_position |
String Where to place the currency symbol, one of left, right |
Dates
Information on how to display dates. The settings below should be used (and combined) to select the format string for the date library being used.
| Name | Description |
|---|---|
format |
String How dates should be formatted. Supported formats are DD-MM-YYYY, MM-DD-YYYY and YYYY-MM-DD. |
use_am_pm |
Boolean Whether to use 24h clock or AM/PM |
first_day_of_week |
Integer Which day to display as first day of the week ( 0 for Sunday) |
Orders
Configuration for orders (these settings also apply to the online store)
| Name | Description |
|---|---|
use_times |
Boolean Whether time selection is enabled, if not, full days are always planned and calculated |
start_type |
String Behavior of default start time, one of fixed, relative |
start_relative_offset |
Integer Offset in seconds from now, used when start_type is relative |
start_fixed_at |
String Fixed time of day, e.g. 14:00, used when start_type is fixed |
stop_type |
String Behavior of default stop time, one of fixed, relative |
stop_relative_offset |
Integer Offset in seconds from now, used when stop_type is relative |
stop_fixed_at |
String Fixed time of day, e.g. 14:00, used when stop_type is fixed |
Security
Global security settings
| Name | Description |
|---|---|
sso_forced |
Boolean Whether to force SSO |
iprestrictions_enabled |
Boolean Whether IP restrictions are enabled |
Address
Settings on how to display addresses
| Name | Description |
|---|---|
fields_order |
Array Order of how the fields are displayed, e.g. ["zipcode", "city", "region"] |
Store
Settings for the online store
| Name | Description |
|---|---|
enabled |
Boolean Whether to accept online reservations |
public |
Boolean Whether to hosted online store is public |
send_order_confirmation |
Boolean Whether to send order confirmations automatically after checkout |
brand_color |
String Brand color as HEX code |
use_availability |
Boolean Whether to show availability and block checkouts when items are unavailable |
use_prices |
Boolean Whether to show prices |
display_price |
String One of period (label will be populated with actual period), charge (label will be populated with the name of the price tile), cheapest (show "starting from" as label) |
show_powered_by |
Boolean Whether to display "Powered by" in the cart |
use_order_lag_time |
Boolean Whether to prevent last-minute reservations |
order_lag_time_interval |
String One of minutes, hours, days, weeks, months |
order_lag_time_value |
Integer The value applied for order_lag_time_interval |
payment_strategy |
String One of none (no payment required at checkout), full (full payment required at checkout), partial (partial payment required at checkout) |
payment_strategy_value |
Integer Percentage to be paid at checkout (for payment_strategy partial) |
payment_deposit |
Boolean Whether deposit should be paid during checkout |
use_toc |
Boolean Whether the agreement should be accepted during checkout |
toc_label |
String The label of the agreement checkbox |
toc_content |
String The contents of the actual agreement |
use_business_hours |
Boolean Whether to take opening hours into account while selecting a period (see operating rules for more information) |
use_away_mode |
Boolean Whether away mode is enabled (see operating rules for more information) |
period_type |
String How the period picker is setup, one of freely (free selection), timeslot_duration (select a day, time and duration), timeslot_fixed (fixed timeslots for days). See operating rules for more information |
use_times |
Boolean Whether to use time selection in the online store |
use_coupons_in_checkout |
Boolean Whether supplying coupons during checkout is enabled |
time_increment |
Integer Time increments for time selection (e.g. 15, 30, 60) |
show_product_availability |
Boolean Whether to show detailed product availability for products |
hide_product_availability_quantities |
Boolean Whether hide quantities in the product availability calendar |
show_cart_availability |
Boolean Whether to show on which dates the products in a cart are available during the period selection |
website |
String Website to use to redirect back to from the checkout |
checkout_scripts |
String Custom scripts to execute during checkout |
google_analytics_id |
String Google analytics ID to use for tracking |
facebook_pixel_id |
String Facebook pixel ID to use for tracking |
facebook_domain_verification |
String Content for the facebook-domain-verification meta tag |
User
Settings that apply to user accounts
| Name | Description |
|---|---|
auth_enabled |
Boolean Whether user accounts are enabled |
allow_signup |
Boolean Whether signup during checkout is allowed |
allow_guest_checkout |
Boolean Whether to allow guest checkouts |
require_verification |
Boolean Whether email addresses need to be verified |
Documents
Settings that apply to all document types
| Name | Description |
|---|---|
show_tax_column |
Boolean Whether to show the tax column on lines |
css |
String Custom css used for documents |
scss |
String Custom scss used for documents |
scope_numbering_to_prefix |
Boolean Whether to scope numbering to prefix, e.g. 1980-1, 1980-2, 1981-1 or 1980-1, 1980-2, 1981-3 |
page_size |
String The page size to use for pdf downloads, one of a4, letter |
Invoices
Settings that apply to invoices
| Name | Description |
|---|---|
footer |
String HTML formatted footer to display on invoices |
show_product_photos |
Boolean Whether to show product photos |
show_stock_identifiers |
Boolean Whether to show identifiers of the stock items that are booked |
show_free_lines |
Boolean Whether to display lines that don't have price |
hide_section_lines |
Boolean Whether to hide lines within a section, if enabled to total price of all lines in a section is summed and displayed next to the section |
prefix |
String Prefix to use for document numbering, e.g. {{year}} or {{customer_number}}, combinations are also possible {{year}}-{{order_number}} |
default_due_period |
Integer A period of time during which invoices can await payment, in seconds |
Quotes
Settings that apply to quotes
| Name | Description |
|---|---|
footer |
String HTML formatted footer to display on quotes |
body |
String HTML formatted body to display on quotes |
show_product_photos |
Boolean Whether to show product photos |
show_stock_identifiers |
Boolean Whether to show identifiers of the stock items that are booked |
show_free_lines |
Boolean Whether to display lines that don't have price |
hide_section_lines |
Boolean Whether to hide lines within a section, if enabled to total price of all lines in a section is summed and displayed next to the section |
prefix |
String Prefix to use for document numbering, e.g. {{year}} or {{customer_number}}, combinations are also possible {{year}}-{{order_number}} |
Contracts
Settings that apply to contracts
| Name | Description |
|---|---|
footer |
String HTML formatted footer to display on contracts |
body |
String HTML formatted body to display on contracts |
show_product_photos |
Boolean Whether to show product photos |
show_stock_identifiers |
Boolean Whether to show identifiers of the stock items that are booked |
show_free_lines |
Boolean Whether to display lines that don't have price |
hide_section_lines |
Boolean Whether to hide lines within a section, if enabled to total price of all lines in a section is summed and displayed next to the section |
prefix |
String Prefix to use for document numbering, e.g. {{year}} or {{customer_number}}, combinations are also possible {{year}}-{{order_number}} |
Labels
Customization settings for labels
| Name | Description |
|---|---|
customer |
String What to call a customer (one of customer, client, student`) |
order |
String What to call an order (one of order, booking, project`) |
quote |
String What to call a quote (one of quote, proposal) |
contract |
String What to call a contract (one of contract, waiver) |
packing_slip |
String What to call a packing slip (one of packing_slip, pull_sheet) |
Labels
Settings for emails
| Name | Description |
|---|---|
bcc |
String BCC addresses to use for all emails |
Fields
| Name | Description |
|---|---|
address |
hash Settings on how to display addresses. |
contracts |
hash Settings that apply to contracts. |
currency |
hash readonlyInformation on how to display and handle the currency (managed on Company resource). |
dashboard |
hash extraDashboard settings (Used internally by Booqable). |
dates |
hash Information on how to display dates. |
defaults |
hash readonlyDefaults derived from other resources. |
deliveries |
hash Settings for deliveries. |
documents |
hash Settings that apply to all document types. |
emails |
hash Settings for emails. |
feature_enrollments |
hash extraFeature enrollments settings (Used internally by Booqable). |
id |
uuid Primary key. |
instructions |
hash extraSettings for in app instructions (Used internally by Booqable). |
invoices |
hash Settings that apply to invoices. |
labels |
hash Customization settings for labels. |
onboarding |
hash extraOnboarding settings (Used internally by Booqable). |
orders |
hash Configuration for orders (these settings also apply to the online store). |
pricing |
hash Configuration on how to handle and display pricing. |
quotes |
hash Settings that apply to quotes. |
security |
hash Global security settings. |
setup_checklist |
hash extraSetup checklist settings (Used internally by Booqable). |
store |
hash Settings for the online store. |
tracking |
hash extraTracking settings (Used internally by Booqable). |
user |
hash Settings that apply to user accounts. |
Fetch settings
How to fetch settings:
curl --get 'https://example.booqable.com/api/4/settings/current'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "7ed00443-a502-4b1a-88ae-d8b726190682",
"type": "settings",
"attributes": {
"updated_at": "2017-11-19T10:18:02.000000+00:00",
"currency": {
"name": "USD",
"decimal": ".",
"thousand": ",",
"symbol": "$",
"precision": 2,
"format": "%s%v"
},
"defaults": {
"timezone": "UTC",
"timezone_offset": 0,
"tax_category_id": "7d25ac45-0c83-4217-8fbd-76ec66f71228",
"tax_region_id": "7ab2a037-7829-4476-8a65-17b89e83a6f5",
"shop_start_location_id": null,
"shop_stop_location_id": null
},
"pricing": {
"enabled": true,
"tax_strategy": "exclusive",
"deposit_type": "percentage",
"deposit_value": 100,
"currency_format": "symbol",
"currency_position": "left"
},
"dates": {
"format": "DD-MM-YYYY",
"use_am_pm": false,
"first_day_of_week": 0
},
"orders": {
"use_times": true,
"start_type": "fixed",
"start_relative_offset": 0,
"start_fixed_at": "09:00",
"stop_type": "fixed",
"stop_relative_offset": 48,
"stop_fixed_at": "15:00"
},
"security": {
"sso_forced": false,
"2fa_forced": false,
"iprestrictions_enabled": false
},
"address": {
"fields_order": [
"zipcode",
"city",
"region"
]
},
"store": {
"enabled": true,
"public": true,
"send_order_confirmation": true,
"brand_color": "#136DEB",
"use_availability": true,
"use_prices": true,
"display_price": "period",
"show_powered_by": true,
"default_collection_sort": "name",
"use_order_lag_time": false,
"order_lag_time_value": null,
"order_lag_time_interval": null,
"behaviors.add_button": "show_cart",
"behaviors.location_picker": "start_stop",
"payment_strategy": "none",
"payment_strategy_value": 30,
"payment_deposit": false,
"security_deposit_explanation": "",
"pay_later": false,
"pay_later_title": "Pay later",
"pay_later_terms": "",
"use_toc": false,
"toc_label": "",
"toc_content": "",
"use_business_hours": false,
"use_away_mode": false,
"period_type": "freely",
"use_times": true,
"use_coupons_in_checkout": true,
"time_increment": 60,
"show_product_availability": true,
"hide_product_availability_quantities": false,
"show_cart_availability": true,
"require_delivery_address_when_selecting_rental_period": true,
"delivery_country_names": [],
"website": null,
"checkout_scripts": "",
"google_analytics_id": null,
"google_anlaytics_options": "{}",
"facebook_pixel_id": null,
"facebook_domain_verification": null
},
"user": {
"auth_enabled": false,
"allow_signup": true,
"allow_guest_checkout": true,
"require_login_to_browse": false,
"require_verification": true
},
"documents": {
"show_tax_column": true,
"css": "",
"scss": "",
"scope_numbering_to_prefix": false,
"page_size": "a4"
},
"invoices": {
"footer": "",
"show_product_photos": true,
"show_stock_identifiers": false,
"show_free_lines": true,
"hide_section_lines": false,
"prefix": "{{year}}-{{order_number}}",
"default_due_period": null
},
"quotes": {
"footer": "",
"body": "",
"show_product_photos": true,
"show_stock_identifiers": false,
"show_free_lines": true,
"hide_section_lines": false,
"prefix": "{{year}}-{{customer_number}}"
},
"contracts": {
"footer": "",
"body": "",
"show_product_photos": true,
"show_stock_identifiers": false,
"show_free_lines": true,
"hide_section_lines": false,
"prefix": null
},
"labels": {
"customer": "customer",
"order": "order",
"quote": "quote",
"contract": "contract",
"packing_slip": "packing_slip",
"start": "pick_up",
"stop": "return"
},
"emails": {
"header_content": "{{#company.logo_url}}\n\n{{/company.logo_url}}\n{{^company.logo_url}}\n# {{company.name}}\n{{/company.logo_url}}\n",
"footer_content": "### {{company.name}}\n{{#company.email}}[{{company.email}}](mailto:{{company.email}}){{/company.email}}\n{{#company.phone}}[{{company.phone}}](tel:{{company.phone}}){{/company.phone}}\n{{#company.website}}[{{company.website}}]({{company.website}}){{/company.website}}\n{{#company.financialLine1}}{{company.financialLine1}}{{/company.financialLine1}}\n{{#company.financialLine2}}{{company.financialLine2}}{{/company.financialLine2}}\n{{company.address}}\n"
},
"deliveries": {
"distance_unit": "metric"
}
}
},
"meta": {}
}
HTTP Request
GET /api/4/settings/current
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
extra_fields[] |
array List of comma separated fields to include in addition to the default fields. ?extra_fields[settings]=dashboard,setup_checklist,onboarding |
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[settings]=currency,defaults,pricing |
Includes
This request does not accept any includes
Signatures
Signatures are used to confirm and store a signature for contracts and quotes.
This resource can also be used to update the signature of a document or add one later.
When a contract is confirmed and a signature is supplied the has_signed_contract flag will
be set accordingly on the associated order.
Relationships
| Name | Description |
|---|---|
customer |
Customer requiredThe associated Customer. |
document |
Document requiredThe associated contract or quote Document. |
order |
Order requiredThe associated Order. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
customer_id |
uuid readonlyThe associated Customer. |
document_id |
uuid readonly-after-createThe associated contract or quote Document. |
id |
uuid readonlyPrimary key. |
order_id |
uuid readonlyThe associated Order. |
signature_base64 |
string writeonlyBase64 encoded signature, use this field to store a signature. |
Sign a contract
Confirm and add a signature to a contract:
curl --request POST
--url 'https://example.booqable.com/api/4/signatures'
--header 'content-type: application/json'
--data '{
"data": {
"type": "signatures",
"attributes": {
"document_id": "6ea8048b-b423-4dfb-8076-da8361155b47",
"signature_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAFwJJREFUeF7tnX+MHsV5x5+9s7mzTXxnjO/8C2N+2wcGwgW3wY1rkahNRBJRIVCSNlEihJQgJY3SSqWNhCr1HyI1ilI1IqRKFJQmVSE/SgiYmIRE/lXXmACWsR0w4J/x+cfhc2zOd7bvtnrefed9Z+ed3Z2dndmd3X3uH8zd7uzM93k+8zzPzLz7er7v+0A/pAApIFXAI0DIM0iBaAUIEOe9AwO81+hl+1/hfxsbAv8AY42WuyECpNz2o95bVoAAsSwwNV9uBRQBodhbbjNT73UVUAREt3m6r1YKVHAezQ2QCmpXK9+3M9g0XpHmWnO9zQ0QcRXG3BCoJVLAngK5AmJvGC63rDPz6dzjsgbl7VtpASEXKo/TldlWpQVEzz3KbCpxxFUai7o18x51zQBRNwRdWTMFIsgjQGrmB2rDzXueVutV6qsMnM0hQFKrTjfEK1AiuBS6SoBU1d8VjF/VoZscFwFiUs2ktshpkxRy7u+FA0I+45xPWOlQWe1cOCBWrCE0Wlbj5KGNW8/QtZTufcmjrwUgyTLQFfoKhJ0z+D9bDmur3ejREyD6nkF35qVA/ly0RkaA5GVkek4pFSBASmk2hU4XOOsq9I67xO2OEiDprElX10wBAqRmBqfhplOg1oC4HdzTGZKutqNArQGxIym1WiUFCJAqWbNSY3EjvhMgCk7lhqkUOkqXGFeAADEuKTXoigImJjYCxBVrUj8MKmACjaA7BIhBsyQ1Zc5sSU9y9e/lU4AAcdWXqF9OKECAOGEGW50o34xtSwnddgkQXeXovlooQIDUwsw4yDJHk+L6ToCkBKQ4U7GOFt+DlJKV+vLcACGzuugnEVYhY7WMlRsgLroH9YkUSFKAAElSKOvfVWZjlWuy9sP0/WXss4YGBIiGaHRLfRQgQOpjaxqphgIEiIZoxd+Sb36T79OKV5fvAQHilj0q05vyQBXfUwKkSJdM5UWpLi5yVJV6NgFSKXPSYEwrQICYVpTaq5QCAiAUxitlXRpMZgUogmSWkBpwUgFDcz0B4qR1qVOuKFAwIIYwL0RNB/vuYJeMmKbAcRUMiBH5OhspUFBLI6JmC1KgmoDoiklg6SpX2fsIkMqalgZmYr4jQMiPSIEYBQiQWPcwMQeR/5VZAScBIbcss0tVq+9OAlItiVVGQ1OCikpFXEOA5Ko6gZBabuuS0XH31DahG0gBpkCtIoj1yYj8ypIChiyn0UytALFkPWq2wgoQIBU2Lg0tuwIESHYNrbWgkRFY60tdGyZA6mp5GreSAnJAaOpSEi/rRaMXAc5OAxyY8OGE78GJCRQ++FnQ68F1PQB9XQCXdgHMn5H1aVnur69DUATJ4jcp70UgjlwE2Hrah33jAPsnAXaN+3BxBsCMi+3G8P/xZ94sr/HfoV6A63sAVvR48L5ZAFdekvLBjl5eBuwcBqQM8ql5HoKx6R2AF0d9+Om4D11TnfdNdwe/8wMmGtCIPwyYu/sAPtALsHZu82K1btBVUQrEuJrDgJTZnoHiPBjPjLbTpynO+ae72uMUIYkChUUXBOVjcz24uVdfq+pMQ/oaxN1ZGUBcM/T2UYCnjvuw/kQbDDQED4QqKLJowoyKUeUz8wA+1e8VXKekcVDXrBXd98oAksY8Nq/FqPH0YYB/OzgNM8/LgeAhwb4wUMTfq6RdLJpgnfLxuR7c02dzdPVrmwAxaHOMGj/c78O2Uz50TbfhUAVCBopO2vU3/V5lCnmD5tFqigDRki18UyNq7AN49PA0zLgQ/I05Np9WqaRXptKuhwY8WDen6OXhcn91KNouDIix1NBYQwbc124TGDV+useHLafbtYas8Ga/i4ompusTrE2wiKdoks3+FEE09TtzDuAnBwD+4+1puGSy3cjFmdyqlGSFKgkUVYDS1CcYTWpTmxiem6sLiGGheI5Y1NjOrVCx/Qu8LgoSPvWSgRKVXkUV8vL6pHPg+UcTi+JrTmi6t2UHpDpaJGrIosaLbwK8Pj4dup45twoouvWJKihRy8Jr5nlwfx9tMCYamrsgOyBpnlbia98YAfjuPh9ePuKD16TA9/zwvgamV81SJA0oeaZd5dw3Kc5xCBAF7X/7NsCTuwHeHuMK8dbRkDAk/CyP/24dHeFqE7EgZxHFJCghQIVjKwgJ7pv83YJsu/AK0pX+EgIkxoSYUv1mD8C39/jQ3Tw/hY4nPx4SDQrvrHE1SlZQZP0KQSoBRbWAr1EmHfIIAiQCEEypfvYSwJbjsqgR3KQCCl9466Rd4nOyFvJifcIK+M9fVqajKvkFJgJEovWmPQBPvOjDkfPBH6OjhhySRprVHT6DlRUU1eVf3Y1GLOAp5ep0BgKE0wRTqh+/BPD0Xh+6m5/PEB076vStSjTh65O80i4+AvGrZ7Jj9RhNVFOu/ObwYp9EgDT1ZynVSweCmT9uxk4bUcTVrihQ+P2TNIW8ybSLUq4wkAQIALCUanQsEEfF4eIgca0+0Um7KOUKfKHWgLCU6rmdfuu4yFRz+TYOFFtpF6t32ByW9diKaoEfdWwFo8nXB2u2sSgs19UWEEypNmwH2PZmUG/wTs9DwoOSV9rFg6Kbdqn0W/b5E3H/pO51iWFAyrFavns/wE82+vDmsXC+yUMSrETJ/x4FCnOu1oYfd3/W/RPVaKIaNaIAivr8yecWelDHpWDDgBS74qDy9B2/A/jx/wKMNnfFL0jeEBIHilZ9gqd6vfauusqKl4vLwne/x4MvLqnOh7FUpvPaAIL1xgvbAH62w4eeic5VKlOglKU+Ud1XESPKTbM9eHh5fY6oOA6ICuPJcePsyQl4fGsv7HwVDxoG14vpEGtFBCVr2sWeZWP/JK/6RNw/QUg+uagenzFxHJCGewX5iebPyRGARzf4cGS/vAGxNsCrTEUTPs+XPYefnfNIu1TrE5VlYTyy8veDHnx+UN82mibN9bYSAKKvx943AL6/AeDc4faxj8lZne2pRhNx6Vcs5LXqE+6FcdGHDYVj9dyhQ53zXarpVRIoF2YGkNw7v7rnuCoLCBbj658HGD3lt9IpHg2ToEStdsXN2CZ34/mUEf+tuuKV5W0rjbF1B6nqR+d58I9XVBOSBECypTf6c7/+nawYf2FDu94QHYi1LoMkqj5Jm3bx0SZuWRgTlKmItyuqpF1iGscrpwOKShQU+8UgcXaFK4MbVyqCIBxbfwOwfqPfeGmbrJ4QDwniNSajiZh2qYAi3iMWxVlAkUHSgJLbozH1+fgb51RjhYvnqTKAND7c9AzApq3hY+ZsRhUjQN6gqMzMadOuINq5VZ+snFsNSJjflBiQNue4jLv+2V7Y/ooPMycBLvREp2g8KKqQsNZ0VrwKqU+8doSIKuLF+ijrpxn59hCSLy2uxhmuEgMSuC0u4z73pA+793ZCoQqKrEaJSrvEekKWxrGeuHS+S2W1ixXevLPrFvJVgaTUgDA49u0EOB/xpTIqkIyPH2n49MTkaIuyc+dPSsPQuXNHoWtgWftvPsDM7tmt/7+kb0nr3zP6F3a0oXJamK9botIuBrVKfaJ7bCUKlKh0Ufx9FSApLSAIx4bHfXh9X9gHo0BpzPTN1Ovddw/BWTgF3ul3YHzWNEydOhp6ly5eK+5Sy6IMe7LsWvxbT38AkndpP8yeuaDxb4Qmj7Qr6G8+9UlclJnsBfjecq+0X/ZTICD6a29RcPCo8KCcHzsIZ7vPwrnzx2H83SBahFZxhFO7fDtRzi+rX6Kuneqahu6mF4nQePPbUUZlZk5byKt+mlGcFGSRSfe1RFj3fefackJSICDSDCbxlwyOA7sAcHaK+jk73oZi8o9HOmdtCRT88qrYriooUdex9hAW/mf23OWtCDM9GE7J4vZP4l7xo5J2iWlcVDSUHd3XWRbOBxL9STfKj0oFCA+HOCAGCwPjzMjLoQ9BiVGj5bAGQEkTTRr9ECBhfWGw9C5dFRqeKih4E9vdbvxbugFpNu0SnxMXBW1CEqBRRkAM9TkJDgTjxNRbcPGdZgoV8bXJYv4fBU5cNBHTEebNOqAsW3wZXLmkHxYtmAODl89pgXFwrBfO9SyDQ6M+HD8b/Jp3ePvH6gPDJe7G466j8DI9PjqJfUZInhjqyvS9iolphsELrEYQQ2wA7nP8z3/1wKHtnSMfnT4I7xza1FjF8rkZkzeSTK+8QeGhWrK0H/701iVw4zUL4OahpfAeyQFKvB43P0dOA+z5A8DeowDbjgYnBPIAxeb+ybWXl2cz0SogJkBGJ9nxI4CXn223NjnbhzMnX4N3/VMwNnmgo75wARTZe6/W3LIMbnnvQrjz/ddHQhGl2ZkJgEMjAP93GOB3b/kwMh6+Uny7vO3Pn8QV8WK0k0UUhOTrV7v/6UTnAdn+BMDm/247w/mJE3B0ai+cGQ+DIYsIqqDI7tVJvWQFOqYUCMYH110dGy3STCb4wonN+zpBUU27rNcnCWkXe/5d8z34ynXyU8Cmso80usqubQLiSnfCXdz9PMBz327/7uT4Ljhx+lWYmhGct4pMk7jhiJDEpV6qaVfDwDFLwyydWn27WTBEA2YFJaqIT6p3WD8S65Nmyhu3T/KhJR7861XufujK2QiCn+fY/S2Ak2MAfNQQnUTVqVWjSSx4wsOjILnuhgH4sw8t10qldGY8fEvLL14LahT2ylRxIjC6f4KNN30668d+EZ4vL+2Czy7XGbn9e5wEBFesNn4NYP/BAI6DxzbAxGz5KV0mUZGgsIiCYAwPLYSPfvh6uPTymE0aC3bFWu2V/cFLt+Pqk6z7J600Dt/Swo1DNZrIohOmod8acnMj0TlAcMXq59/tgZHtHmBKdXLs1Y5PBLIUS+ZnuYPiA0zPALjtjmXw4F+vhcs7j19ZwCG6Sfa2yKRCXkx72P5JER/7Reg+MMeDr6xyr2h3DhAsyl94/AT8cfpYAw7+R1wZCoHC1R2qRbeJtOuaoQG4+54hYwW4KZpY2vXiofivYQgBwb2/S2WTUZbG6dYnCMlHFkQX7Um62KqinQLk9S0jsO17C2HHjh+2NqhUDg1GRRQb0YTVKJgWfOKvbi4knUpyFvZ39g1Zz+8KNhtd3z9BSL60zK16xBlAMLV69pHjsPn5TR0nabNAkqboVokoCN1tty2FtR+/FtYML1X11UKvY1/tgNEET7nIQIl6barsjS/t1xWpfe1cmvoEjwx9Z2UXrJ5fqGSthzsDyKYfvQ1Pfm1r6/yU8rENoVjMWp/IloVZKnHFvD4Y/siVcNc9N6fe6DNr7vQJhelowhYm4k4L4zUqH9QSP82IS79R+yNmdUxuzQlAcNXqsS88A8feGmsAgiuILHNWBSW2PuF0UK1PGsZtruNjn2653XLUSO/zydaVXKESTZhj29iNx7aTIgq+lO6rN3XB3QNaQwxuMqSnE4D8/BuvwK++/1pLDfF1n0qQNKnKAooMnkWDrkSNDM4i3CpGk0Y04M6xqe7Ih+7pbk5swoe0+EI+zfmu1fM9ePiW4t+1VTggfPQQXUALFCGsBwaK3kOJiig4y930/qXwwBfWFb50aw6NcEtx0UR07KhoIsIVVZ/ofOz3H27NGEUMCFc4IGL0kI0pb1AGFlcvakT5io1owtcnSdGJ9UuWdr1voPgoUigguHL1zQd+Daf2jMH5mFf18LMZE1SWdon5bdS1ccvCK9ZWO2pEgSJGkyTHzqM+QWi+Oay4omWo5hD1KRQQ3Pf49wd/3fp+wCRITIIiQjL/ivpEDd1oIupv9HwXd16Rjyb3X9MFn11hIFfSbKJQQDC92vhYuzjHMahAogqK6v7JXX+5Ev78/uHK1hppfSMpmpiuT+IK+TV9Hnx12CtsWb0wQDD3feqhLfDKL+Vf3GEbFDRK39VzHdnXSOvC9q+X1Sam066k9tiE+Y3VimmWBVkKAwTrj8fu+xUcO3w6tMQojtE0KDMuBF+Q8+G7VlDUUHAoFk1eOhBeCcy6LKyyG4/dQ1v9y1AXrLtKobOmLuHqGScAEWcS2ThVQFFZ7Zpzw1x44MHbYdFtC62EbUu1oinTa7WjEk3i0q6GfRO+KChuR/4zK4urQ5wBhFlOPIatE1FEUFio/ti9N8Kdn16R+2c1tLzSwZtktUlSmpRmtQvbkr0NUgcQUxNVGBBTrSoa9z//dgvsXC+vQeJACaIJfyCl84EICX66Dgv1O9Ysh9X3XQPXryn4wxqKurh8Gftg1s43ADZyX21nEhSEhLWHdnxkbQ1rEBQADyg+/c9bI/0hazQZvLof1t47BO/9i0UUNQxTF5V2mQbl2ku74JE7wUo6rCJJYSkWdg6PmTz+qV80CvW4n+RoEr4bwVi1dgnc8clbaelWxQsyXMNeHPHsruCdXSy9VX0bZNK3aX3iVq+++yBoF9wL2fxoeC8kyl5JEWXR4j5Y/sFFtDqVweF1b+U/wci/WTUtKPzm41X9Hnx5GOC6vDNjF1axmCFwufepf9oBr/72gLJtRNEZGKvWLaE6Q1lFwxf6AI2X2x0L3rDCPpzFnpJ2WRiXdx/6Ey/f5V2JJIWmWKw/mGr98uHNqSGZt5JSKcNubqQ5rE8QFPYWSPZuYdX6BOG4b7iI1KpzlcoJQFA4jCQv/GAvvPH04ciaBGchjBaDq+Y1VqUW39BvsPjOeQnPiCsmNBIzpLxGizUKe7cwvohbfCURjoDVLQjGsvke3DsEhUUOURdnAOFTrj/8fgz2bh+BC+NTcO74BMwa6IWBqy6DwStnGYYiDy+lZ6AC7EXcI6cA9o0CnBDWZVYsApg7D2B4YXErVjJLuQFIXtOZs75aTwEQGvyJert9vuaS28ANQPJVgp7mogKOzhEEiIvOQn1yRgEFQBxFW1XCkndfdZh0nR0FFACx82BqlRQogwIESBmsRH0sTIFqAkJpVWEO1X5wNYxQTUAccA/qQl4K2AWRALFmR7uG0+u2i33SG0ledxEgeSlNzymlAoYBoRnKihc4Jqtj3UkteZr+xwCSppnUfaQbSIFSKGA4gpRizNRJUkBZAQJEWaoKXEhJQWojEiCpJavLDTWmyaWP3NbF3Wic5VTAkQhierYy3V7JjFvD4dsasiOAlMwBXemuLa9wZXwO9IMAkRqBPM8B33SiC/kBUrjPFd4BJwxOnUinQH6ApOsXXa2gACGvIFLGSwiQjALS7dVWwCAgNJ9V21XqOTqDgNRTQBp1tRUgQKptXxpdRgUIkIwC0u3VVoAAqbZ9aXQZFSBAMgro8u20bJLFOoF6BEgWDeneyitAgFTexDTALAoQIFnUo3srrwABUnkTmxtgHWsaAsSc/zjRUvFOXHwPwGAXCBAn3Np+Jwz6jP3OWniC7vg7AdFtycKgqElSoGgFKIIUbQF6vr4COUzmBIi+eejOiijQ5qyTODuA5EA22ianx1TEDWgYOgrYAUSnJ3QPKeCgAu4CwoUHihQOek5NuuQuIDUxAA3TbQXqCQiFJCteWUVZPX/a98GzolfJGq2ieUtmgsTuqttI/cr4h9YzgiQagi4gBQIFCBDyBFIgRoFaAhKEX1NBuFNdey2TL+etQPkAqbL3VXlseXu2oeeVDxBDA69XM0Serr0JEF3l6L5aKECA1MLMNMhkBeRRlgBJVq74KyhDKswGdgGpkWFrNNTCnLWIB9sFpIgR0TNJAYMK5AsITbMGTUdN5aFAvoDkMaLaPINmmzxMTYDkoXLaZ5DvSxSzJUp8uzUExJbQaSmg68ugQA0BccEsFYG0IsOI8whv2vf9wj8OUgGhKzAEF2YO5/pAEcQ5k0R0iAgsxFIOA0IeUYhH0ENDCjgMCFnKLQWKm7CKezJ9ojC9DxZprfS9bd5Ryk5rj9bIjU3JKIIYUZMa0VHA9ic7dfok3kOAZFGRJuYs6pXi3v8HOZ5zbDYLrEsAAAAASUVORK5CYII=\n"
}
},
"include": "document,order",
"fields": {
"orders": "has_signed_contract"
}
}'
A 200 status response looks like this:
{
"data": {
"id": "914a141f-72ee-48a6-8d8f-75f19df8096a",
"type": "signatures",
"attributes": {
"document_id": "6ea8048b-b423-4dfb-8076-da8361155b47",
"order_id": "57b1b33c-c25e-4c82-85f1-a1fc25d65fd4",
"customer_id": "538b2f72-8ad8-419f-8f8f-f5b2c8e07381"
},
"relationships": {
"document": {
"data": {
"type": "documents",
"id": "6ea8048b-b423-4dfb-8076-da8361155b47"
}
},
"order": {
"data": {
"type": "orders",
"id": "57b1b33c-c25e-4c82-85f1-a1fc25d65fd4"
}
}
}
},
"included": [
{
"id": "6ea8048b-b423-4dfb-8076-da8361155b47",
"type": "documents",
"attributes": {
"created_at": "2025-11-01T01:57:01.000000+00:00",
"updated_at": "2025-11-01T01:57:01.000000+00:00",
"archived": false,
"archived_at": null,
"document_type": "contract",
"number": 1,
"prefix": null,
"prefix_with_number": "1",
"revision": null,
"date": "2025-10-31",
"due_date": null,
"name": "John Doe",
"address": null,
"body": null,
"footer": null,
"reference": null,
"starts_at": null,
"stops_at": null,
"start_location_id": null,
"stop_location_id": null,
"revised": false,
"finalized": true,
"sent": false,
"confirmed": true,
"status": "confirmed",
"signature_url": "/uploads/6ec35b15c20e2b83d46f922e40351a06/document/contract/signature/6ea8048b-b423-4dfb-8076-da8361155b47/fd41339f-7791-4cad-8f8f-47650ac6fbba.png",
"deposit_type": "none",
"deposit_value": 0.0,
"tag_list": [],
"price_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"total_discount_in_cents": 0,
"deposit_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_refunded_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"to_be_paid_in_cents": 0,
"paid_in_cents": 0,
"tax_in_cents": 0,
"discount_type": null,
"discount_percentage": 0.0,
"fulfillment_type": null,
"delivery_label": null,
"delivery_price_in_cents": 0,
"delivery_carrier_name": null,
"delivery_address": null,
"order_id": "57b1b33c-c25e-4c82-85f1-a1fc25d65fd4",
"customer_id": "538b2f72-8ad8-419f-8f8f-f5b2c8e07381",
"tax_region_id": null,
"coupon_id": null
},
"relationships": {}
},
{
"id": "57b1b33c-c25e-4c82-85f1-a1fc25d65fd4",
"type": "orders",
"attributes": {
"has_signed_contract": true
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/signatures
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[signatures]=document_id,order_id,customer_id |
include |
string List of comma seperated relationships to sideload. ?include=document,order,customer |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][document_id] |
uuid The associated contract or quote Document. |
data[attributes][signature_base64] |
string Base64 encoded signature, use this field to store a signature. |
Includes
This request accepts the following includes:
customerdocumentorder
Sortings
A convenient way to bulk update positions for supported resources.
Fields
| Name | Description |
|---|---|
id |
uuid readonlyPrimary key. |
ids |
array[string] writeonlyArray of ids, positions are determined by the order of the array. |
type |
enum writeonlyType of resource to update. One of: bundle_items, default_properties, lines, photos, properties, tax_rates, collection_items, products. |
Sort resources
How to update ordering of lines on an order:
curl --request POST
--url 'https://example.booqable.com/api/4/sortings'
--header 'content-type: application/json'
--data '{
"data": {
"type": "sorting",
"attributes": {
"type": "lines",
"ids": [
"dd7704d6-92af-433f-8307-1580c222b45b",
"f07a772a-99b8-42a9-80cf-ae5f022c3a88",
"0b8285b3-8cc6-4091-8484-0ae26045348e"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "c9141d6a-4138-42f9-8b9b-ec969ca14eb7",
"type": "sortings"
},
"meta": {}
}
How to update the order in which default properties are displayed:
curl --request POST
--url 'https://example.booqable.com/api/4/sortings'
--header 'content-type: application/json'
--data '{
"data": {
"type": "sorting",
"attributes": {
"type": "default_properties",
"ids": [
"b4bc1f68-037d-4910-8c66-87497dd24491",
"0bd669a0-51bf-4493-8ce1-22c9ca11fce7",
"e54e6ae1-8288-4ffd-8e7a-f3450abfc7ba",
"41c3e709-3062-4040-8862-3f5c87890671",
"2033f2d9-8300-4554-8070-08271971674b"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "09ef6bf7-74e3-4276-8064-c916d9e88fac",
"type": "sortings"
},
"meta": {}
}
HTTP Request
POST /api/4/sortings
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][ids] |
array[string] Array of ids, positions are determined by the order of the array. |
data[attributes][type] |
enum Type of resource to update. One of: bundle_items, default_properties, lines, photos, properties, tax_rates, collection_items, products. |
Includes
This request does not accept any includes
Stock adjustments
Adjusts the stock of a Product at a specific Location.
For bulk products, stock can be added (positive quantity) or removed (negative quantity).
For trackable products, StockItems are created. To remove StockItems, use the StockItemArchivation resource.
Removing stock can cause shortage. The request will fail,
and the error.code attribute will have the value shortage.
When the shortage is within the shortage limit of the product,
a warning is returned. Otherwise a blocking error is returned.
A warning can be overriden by setting confirm_shortage to true.
The orders that would be affected by the shortage can be found in
either meta.blocking[0].order_ids or meta.warning[0].order_ids.
Relationships
| Name | Description |
|---|---|
location |
Location requiredThe Location where stock is adjusted. |
product |
Product requiredThe Product whose stock needs to be adjusted. |
stock_items |
Stock items hasmanyThe StockItems that have been generated by adjusting stock. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
confirm_shortage |
boolean nullableA value of true overrides shortage warnings. Overriding shortage is only possible when the product allows shortage, and the resulting shortage is within the limit for the product. |
from |
datetime nullableThe date from which the new stock will be available. When this date is in the future, the stock will be shown as "expected". When this date is null, the stock will be available immediately. |
id |
uuid readonlyPrimary key. |
location_id |
uuid The Location where stock is adjusted. |
prefix |
string nullableThe prefix to use to generate identifiers for StockItems. When left empty, the SKU from the product will be used. When adding temporary stock, TMP- will be added automatically. |
product_id |
uuid The Product whose stock needs to be adjusted. |
quantity |
integer How much stock to add or remove. For trackable Products this means the number of StockItems that will be created. Removing stock by setting a negative quantity is only possible for bulk products. |
till |
datetime nullableThe date till which the stock will be available. When this date is set, the stock will be considered "temporary". |
Add stock (bulk)
Add stock to a bulk product:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_adjustments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_adjustments",
"attributes": {
"product_id": "70fad66c-5710-4baa-8b5c-37c053fff200",
"location_id": "6badcd2f-233c-4360-87fd-d83ee972a0ab",
"quantity": 10,
"from": "2027-09-21T19:27:03.000000+00:00",
"till": null
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "aac71372-3b85-4060-833e-c84b236fc670",
"type": "stock_adjustments",
"attributes": {
"quantity": 10,
"from": "2027-09-21T19:27:03.000000+00:00",
"till": null,
"prefix": null,
"confirm_shortage": null,
"product_id": "70fad66c-5710-4baa-8b5c-37c053fff200",
"location_id": "6badcd2f-233c-4360-87fd-d83ee972a0ab"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/stock_adjustments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_adjustments]=quantity,from,till |
include |
string List of comma seperated relationships to sideload. ?include=product,stock_items |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings. Overriding shortage is only possible when the product allows shortage, and the resulting shortage is within the limit for the product. |
data[attributes][from] |
datetime The date from which the new stock will be available. When this date is in the future, the stock will be shown as "expected". When this date is null, the stock will be available immediately. |
data[attributes][location_id] |
uuid The Location where stock is adjusted. |
data[attributes][prefix] |
string The prefix to use to generate identifiers for StockItems. When left empty, the SKU from the product will be used. When adding temporary stock, TMP- will be added automatically. |
data[attributes][product_id] |
uuid The Product whose stock needs to be adjusted. |
data[attributes][quantity] |
integer How much stock to add or remove. For trackable Products this means the number of StockItems that will be created. Removing stock by setting a negative quantity is only possible for bulk products. |
data[attributes][till] |
datetime The date till which the stock will be available. When this date is set, the stock will be considered "temporary". |
Includes
This request accepts the following includes:
productstock_items
Add stock (trackable)
Add stock items to a trackable product:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_adjustments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_adjustments",
"attributes": {
"product_id": "43137334-e017-444b-8a72-de5aae265a4c",
"location_id": "264e9817-aaea-42f0-83ac-07dc2d679915",
"quantity": 2,
"prefix": "XYZ"
}
},
"include": "stock_items"
}'
A 200 status response looks like this:
{
"data": {
"id": "dfe5dfa8-65a9-4115-888f-4bffae11171d",
"type": "stock_adjustments",
"attributes": {
"quantity": 2,
"from": null,
"till": null,
"prefix": "XYZ",
"confirm_shortage": null,
"product_id": "43137334-e017-444b-8a72-de5aae265a4c",
"location_id": "264e9817-aaea-42f0-83ac-07dc2d679915"
},
"relationships": {
"stock_items": {
"data": [
{
"type": "stock_items",
"id": "e409d5fd-b40f-4f3e-8c02-35862b0a1514"
},
{
"type": "stock_items",
"id": "05afa8b9-28ef-4f99-802e-5ac8c3184127"
}
]
}
}
},
"included": [
{
"id": "e409d5fd-b40f-4f3e-8c02-35862b0a1514",
"type": "stock_items",
"attributes": {
"created_at": "2021-11-06T07:42:00.000000+00:00",
"updated_at": "2021-11-06T07:42:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "XYZ-1",
"status": "in_stock",
"from": null,
"till": null,
"stock_item_type": "regular",
"product_group_id": "323c63ff-5037-42ee-896b-aef7717f2eac",
"properties": {},
"product_id": "43137334-e017-444b-8a72-de5aae265a4c",
"location_id": "264e9817-aaea-42f0-83ac-07dc2d679915"
},
"relationships": {}
},
{
"id": "05afa8b9-28ef-4f99-802e-5ac8c3184127",
"type": "stock_items",
"attributes": {
"created_at": "2021-11-06T07:42:00.000000+00:00",
"updated_at": "2021-11-06T07:42:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "XYZ-2",
"status": "in_stock",
"from": null,
"till": null,
"stock_item_type": "regular",
"product_group_id": "323c63ff-5037-42ee-896b-aef7717f2eac",
"properties": {},
"product_id": "43137334-e017-444b-8a72-de5aae265a4c",
"location_id": "264e9817-aaea-42f0-83ac-07dc2d679915"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/stock_adjustments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_adjustments]=quantity,from,till |
include |
string List of comma seperated relationships to sideload. ?include=product,stock_items |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings. Overriding shortage is only possible when the product allows shortage, and the resulting shortage is within the limit for the product. |
data[attributes][from] |
datetime The date from which the new stock will be available. When this date is in the future, the stock will be shown as "expected". When this date is null, the stock will be available immediately. |
data[attributes][location_id] |
uuid The Location where stock is adjusted. |
data[attributes][prefix] |
string The prefix to use to generate identifiers for StockItems. When left empty, the SKU from the product will be used. When adding temporary stock, TMP- will be added automatically. |
data[attributes][product_id] |
uuid The Product whose stock needs to be adjusted. |
data[attributes][quantity] |
integer How much stock to add or remove. For trackable Products this means the number of StockItems that will be created. Removing stock by setting a negative quantity is only possible for bulk products. |
data[attributes][till] |
datetime The date till which the stock will be available. When this date is set, the stock will be considered "temporary". |
Includes
This request accepts the following includes:
productstock_items
Remove stock (bulk)
Remove stock from bulk product:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_adjustments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_adjustments",
"attributes": {
"product_id": "54f3efb8-a875-4087-8e5f-a9d7119ec553",
"location_id": "1c9abb03-c9a9-4275-8a23-5e93b7d94e4c",
"quantity": -5
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "12134910-6f7b-4685-893e-00b89172cf2e",
"type": "stock_adjustments",
"attributes": {
"quantity": -5,
"from": null,
"till": null,
"prefix": null,
"confirm_shortage": null,
"product_id": "54f3efb8-a875-4087-8e5f-a9d7119ec553",
"location_id": "1c9abb03-c9a9-4275-8a23-5e93b7d94e4c"
},
"relationships": {}
},
"meta": {}
}
Remove stock from bulk product, causing shortage:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_adjustments'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_adjustments",
"attributes": {
"product_id": "5046c7b4-f597-4e3b-8cc2-fbdb26e612e3",
"location_id": "fba46066-c280-4b90-8c5b-665a49e893c7",
"quantity": -5
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "shortage",
"status": "422",
"title": "Shortage",
"detail": "This will create shortage for running or future orders",
"meta": {
"warning": [],
"blocking": [
{
"reason": "shortage",
"shortage": 4,
"item_id": "5046c7b4-f597-4e3b-8cc2-fbdb26e612e3",
"mutation": -5,
"order_ids": [
"27eb795b-c0c7-466c-8c90-40d5c6025995"
],
"location_id": "fba46066-c280-4b90-8c5b-665a49e893c7",
"available": 1,
"plannable": 1,
"stock_count": 5,
"planned": 4,
"needed": 4,
"cluster_available": 1,
"cluster_plannable": 1,
"cluster_stock_count": 5,
"cluster_planned": 4,
"cluster_needed": 4
}
]
}
}
]
}
HTTP Request
POST /api/4/stock_adjustments
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_adjustments]=quantity,from,till |
include |
string List of comma seperated relationships to sideload. ?include=product,stock_items |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings. Overriding shortage is only possible when the product allows shortage, and the resulting shortage is within the limit for the product. |
data[attributes][from] |
datetime The date from which the new stock will be available. When this date is in the future, the stock will be shown as "expected". When this date is null, the stock will be available immediately. |
data[attributes][location_id] |
uuid The Location where stock is adjusted. |
data[attributes][prefix] |
string The prefix to use to generate identifiers for StockItems. When left empty, the SKU from the product will be used. When adding temporary stock, TMP- will be added automatically. |
data[attributes][product_id] |
uuid The Product whose stock needs to be adjusted. |
data[attributes][quantity] |
integer How much stock to add or remove. For trackable Products this means the number of StockItems that will be created. Removing stock by setting a negative quantity is only possible for bulk products. |
data[attributes][till] |
datetime The date till which the stock will be available. When this date is set, the stock will be considered "temporary". |
Includes
This request accepts the following includes:
productstock_items
Stock items
For trackable products, each stock item is tracked and managed individually. Each stock item has a unique identifier that helps to keep track of it throughout Booqable.
To create multiple StockItems in a single request, use the StockAdjustment resource.
Statuses
- Regular: Regular stock item (
fromandtilldates are not set). - Expected: Items will become part of your regular inventory
once they surpass the available from date, used for "coming soon"
products and purchase orders (only
fromdate is set). - Temporary: Temporary items will automatically become unavailable
once they exceed the available till date, typically a sub-rental
(
fromandtillare set).
Relationships
| Name | Description |
|---|---|
barcode |
Barcode optionalBarcode to quickly identify this StockItem. |
location |
Location requiredLocation where this StockItem currently resides. This is the start location of the order if the StockItem is currently out with a customer. |
product |
Product requiredThe Product this StockItem is one instance of. |
properties |
Properties hasmanyCustom data associated with this StockItem. |
stock_item_plannings |
Stock item plannings hasmanyThe StockItemPlannings that represent the planning and reservation history of this specific StockItem. This includes both rental orders and downtime periods assigned to this StockItem. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether item is archived. |
archived_at |
datetime readonly nullableWhen the item was archived. |
confirm_shortage |
boolean writeonlyWhether to confirm a shortage when updating from, till or location of a stock item. |
created_at |
datetime readonlyWhen the resource was created. |
from |
datetime nullableWhen the stock item will be available in stock (temporary items or expected arrival date). |
id |
uuid readonlyPrimary key. |
identifier |
string Unique identifier (like serial number). |
location_id |
uuid Location where this StockItem currently resides. This is the start location of the order if the StockItem is currently out with a customer. |
product_group_id |
uuid readonlyThe ProductGroup this StockItem belongs to. |
product_id |
uuid readonly-after-createThe Product this StockItem is one instance of. |
properties |
hash readonlyA hash containing all basic property values (include properties if you need more detailed information about properties). |
properties_attributes |
array writeonlyCreate or update multiple properties associated with this stock item. |
status |
enum readonlyWhether item is out with a customer or in-store/warehouse. One of: archived, expected, in_stock, started, overdue, expired, in_downtime. |
stock_item_type |
enum readonlyBased on the values of from and till.One of: regular, temporary. |
till |
datetime nullableWhen item will be out of stock (temporary items). |
updated_at |
datetime readonlyWhen the resource was last updated. |
List stock_items
How to fetch a list of stock items:
curl --get 'https://example.booqable.com/api/4/stock_items'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "080ec72f-da7f-4569-8d12-1a6770c8f19f",
"type": "stock_items",
"attributes": {
"created_at": "2025-04-07T23:24:00.000000+00:00",
"updated_at": "2025-04-07T23:24:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "id1000189",
"status": "in_stock",
"from": null,
"till": null,
"stock_item_type": "regular",
"product_group_id": "33aa5e86-cf21-4867-8ce8-6ca8000eee14",
"properties": {},
"product_id": "ab39f2f5-e082-4520-8ba6-57e483d3686a",
"location_id": "78ae9e4b-b588-4fb0-845a-99371ba4d69c"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/stock_items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_items]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=product,barcode,location |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
from |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
identifier |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
location_id |
uuid eq, not_eq |
product_group_id |
uuid eq, not_eq |
product_id |
uuid eq, not_eq |
q |
string eq |
status |
enum eq |
stock_item_type |
enum eq |
till |
datetime eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
status |
array count |
stock_item_type |
array count |
total |
array count |
Includes
This request accepts the following includes:
barcodelocationproductproperties-
stock_item_planningsdowntime
Fetch a stock_item
How to fetch a stock item:
curl --get 'https://example.booqable.com/api/4/stock_items/218c1f4b-3124-4718-86e3-fc4646fe5562'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "218c1f4b-3124-4718-86e3-fc4646fe5562",
"type": "stock_items",
"attributes": {
"created_at": "2020-12-14T17:16:00.000000+00:00",
"updated_at": "2020-12-14T17:16:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "id1000190",
"status": "in_stock",
"from": null,
"till": null,
"stock_item_type": "regular",
"product_group_id": "20441cdb-ca45-49d3-887f-91258ef2c191",
"properties": {},
"product_id": "62127110-28f1-4b13-84de-f7287c9f9691",
"location_id": "42f6ee46-44cc-47e4-8775-d2f20612347a"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/stock_items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_items]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=barcode,location,properties |
Includes
This request accepts the following includes:
barcodelocation-
productproduct_group
properties-
stock_item_planningsdowntime
Create a stock_item
How to create a stock item:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_items'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_items",
"attributes": {
"identifier": "12345",
"product_id": "8ba34c4e-02e7-46c8-87c1-741102785936"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "63a10585-7a78-4d77-8fc0-04fefeb7b255",
"type": "stock_items",
"attributes": {
"created_at": "2025-07-23T16:54:00.000000+00:00",
"updated_at": "2025-07-23T16:54:00.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "12345",
"status": "in_stock",
"from": null,
"till": null,
"stock_item_type": "regular",
"product_group_id": "d798843c-7589-4a94-85cd-e47efc86c6ab",
"properties": {},
"product_id": "8ba34c4e-02e7-46c8-87c1-741102785936",
"location_id": "216d7c85-e3a6-4f77-809a-a5fb404ea9a4"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/stock_items
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_items]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=barcode,location,properties |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean Whether to confirm a shortage when updating from, till or location of a stock item. |
data[attributes][from] |
datetime When the stock item will be available in stock (temporary items or expected arrival date). |
data[attributes][identifier] |
string Unique identifier (like serial number). |
data[attributes][location_id] |
uuid Location where this StockItem currently resides. This is the start location of the order if the StockItem is currently out with a customer. |
data[attributes][product_id] |
uuid The Product this StockItem is one instance of. |
data[attributes][properties_attributes][] |
array Create or update multiple properties associated with this stock item. |
data[attributes][till] |
datetime When item will be out of stock (temporary items). |
Includes
This request accepts the following includes:
barcodelocation-
productproduct_group
properties
Update a stock_item
How to update a stock item:
curl --request PUT
--url 'https://example.booqable.com/api/4/stock_items/96e16eb3-614f-4a6a-8444-531244376f3a'
--header 'content-type: application/json'
--data '{
"data": {
"id": "96e16eb3-614f-4a6a-8444-531244376f3a",
"type": "stock_items",
"attributes": {
"identifier": "12346"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "96e16eb3-614f-4a6a-8444-531244376f3a",
"type": "stock_items",
"attributes": {
"created_at": "2019-01-10T06:59:11.000000+00:00",
"updated_at": "2019-01-10T06:59:11.000000+00:00",
"archived": false,
"archived_at": null,
"identifier": "12346",
"status": "in_stock",
"from": null,
"till": null,
"stock_item_type": "regular",
"product_group_id": "4fd29b75-0981-44f0-893f-c9e5885ec5f6",
"properties": {},
"product_id": "797648e2-ccc4-4117-832c-6b0a19709ee5",
"location_id": "b10fb7f2-9f8e-4e91-8a52-93585748b5a3"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/stock_items/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_items]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=barcode,location,properties |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean Whether to confirm a shortage when updating from, till or location of a stock item. |
data[attributes][from] |
datetime When the stock item will be available in stock (temporary items or expected arrival date). |
data[attributes][identifier] |
string Unique identifier (like serial number). |
data[attributes][location_id] |
uuid Location where this StockItem currently resides. This is the start location of the order if the StockItem is currently out with a customer. |
data[attributes][product_id] |
uuid The Product this StockItem is one instance of. |
data[attributes][properties_attributes][] |
array Create or update multiple properties associated with this stock item. |
data[attributes][till] |
datetime When item will be out of stock (temporary items). |
Includes
This request accepts the following includes:
barcodelocation-
productproduct_group
properties
Stock item archivations
Archives a stock item.
Archiving is final and cannot be undone.
Errors
When the request fails, the error.code attribute can have the
following values:
stock_item_archivedThe stock item was already archived before.stock_item_specifiedThe stock item has not been archived because this specific stock item has been planned for current or future orders. The orders to which this stock item has been planned are specified in themeta.blocking[0].order_idsfield.shortageThe stock item has not been archived because this would lead to an (un)acceptable shortage of the product for current or future orders. When the shortage is within the shortage limit of the product, a warning is returned. Otherwise a blocking error is returned. A warning can be overridden by settingconfirm_shortagetotrue. The orders that would be affected by the shortage can be found in eithermeta.blocking[0].order_idsormeta.warning[0].order_ids.
Relationships
| Name | Description |
|---|---|
stock_item |
Stock item requiredThe StockItem that needs to be archived. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
confirm_shortage |
boolean A value of true overrides shortage warnings. |
id |
uuid readonlyPrimary key. |
stock_item_id |
uuid The StockItem that needs to be archived. |
Archive
When the StockItem is not used, it can be archived:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_item_archivations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_item_archivations",
"attributes": {
"stock_item_id": "37f0c3fc-b2bf-4966-8eb5-d78dd973ed78"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "16f1d062-5ca2-4e3d-86ef-07d906b31fcf",
"type": "stock_item_archivations",
"attributes": {
"confirm_shortage": null,
"stock_item_id": "37f0c3fc-b2bf-4966-8eb5-d78dd973ed78"
},
"relationships": {}
},
"meta": {}
}
When the StockItem was already archived:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_item_archivations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_item_archivations",
"attributes": {
"stock_item_id": "3ff5774c-b38f-47e3-87b2-c514df491708"
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "stock_item_archived",
"status": "422",
"title": "Stock item archived",
"detail": "Stock item is already archived",
"meta": null
}
]
}
When the StockItem is specified on a reserved Order:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_item_archivations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_item_archivations",
"attributes": {
"stock_item_id": "00fb3418-f6cc-403c-8a08-25489ba726a0"
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "stock_item_specified",
"status": "422",
"title": "Stock item specified",
"detail": "This stock item is specified on a current or future order",
"meta": {
"blocking": [
{
"order_ids": [
"809e9c77-25f8-4f0e-8a50-7c1e884681d5"
]
}
]
}
}
]
}
When archival would create unallowed shortage:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_item_archivations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_item_archivations",
"attributes": {
"stock_item_id": "b4e06e4a-63ed-4e5d-8e4e-f6594bac9ab9"
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "shortage",
"status": "422",
"title": "Shortage",
"detail": "This will create shortage for running or future orders",
"meta": {
"warning": [],
"blocking": [
{
"reason": "shortage",
"shortage": 1,
"item_id": "f5273ac1-25df-4451-82dd-a11908f80b33",
"mutation": -1,
"order_ids": [
"48e3654d-1bd3-4805-8dc4-28a9702fd4be"
],
"location_id": "a850b1a1-8829-4508-8ce1-2fa8e886fce6",
"available": 0,
"plannable": 0,
"stock_count": 1,
"planned": 1,
"needed": 1,
"cluster_available": 0,
"cluster_plannable": 0,
"cluster_stock_count": 1,
"cluster_planned": 1,
"cluster_needed": 1
}
]
}
}
]
}
When archival would create allowed shortage, but confirm_shortage is unspecified:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_item_archivations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_item_archivations",
"attributes": {
"stock_item_id": "d4f5dbfe-e53b-4fae-8d91-56dbd8ec1f0a"
}
}
}'
A 422 status response looks like this:
{
"errors": [
{
"code": "shortage",
"status": "422",
"title": "Shortage",
"detail": "This will create shortage for running or future orders",
"meta": {
"warning": [
{
"reason": "shortage",
"shortage": 1,
"item_id": "56a2701d-0c44-442b-881b-2332c08e358c",
"mutation": -1,
"order_ids": [
"9ab41c24-253e-4ca3-8714-4e2ae2dbcaeb"
],
"location_id": "bffaaa23-5b23-494f-8775-986f7429fbae",
"available": 0,
"plannable": 1,
"stock_count": 1,
"planned": 1,
"needed": 1,
"cluster_available": 0,
"cluster_plannable": 1,
"cluster_stock_count": 1,
"cluster_planned": 1,
"cluster_needed": 1
}
],
"blocking": []
}
}
]
}
When archival would create allowed shortage, and confirm_shortage is true:
curl --request POST
--url 'https://example.booqable.com/api/4/stock_item_archivations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "stock_item_archivations",
"attributes": {
"stock_item_id": "b899b3e7-5c23-4e22-8859-325956852bea",
"confirm_shortage": true
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "2adbd074-8788-4a4c-85e1-3043bd4d878a",
"type": "stock_item_archivations",
"attributes": {
"confirm_shortage": true,
"stock_item_id": "b899b3e7-5c23-4e22-8859-325956852bea"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/stock_item_archivations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_item_archivations]=confirm_shortage,stock_item_id |
include |
string List of comma seperated relationships to sideload. ?include=stock_item |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][confirm_shortage] |
boolean A value of true overrides shortage warnings. |
data[attributes][stock_item_id] |
uuid The StockItem that needs to be archived. |
Includes
This request accepts the following includes:
stock_item
Stock item plannings
StockItemPlannings hold information about the planning of individual StockItems (for trackable products). They make it possible to know precisely which StockItems have been where and define when an item is available during a given period.
StockItemPlannings are never directly created or updated through their resource; instead they are created by booking or specifying StockItems; they are updated by starting or stopping them. See the OrderFulfillments resource for examples.
Purpose and Relationship to Plannings
While a Planning represents the quantitative planning of items (how many), a StockItemPlanning represents the specific trackable StockItem assigned to fulfill that Planning. The relationship is:
- A Planning may have multiple StockItemPlannings (one for each trackable StockItem)
- The number of StockItemPlannings may be less than
Planning.quantitywhen not all StockItems have been specified yet.
Lifecycle Management
StockItemPlannings follow a specific lifecycle:
- Creation: They are created when StockItems are booked or specified on a Planning via OrderFulfillments
- Reservation: When reserved, the specific StockItem becomes unavailable for other orders
- Start: When the StockItem is marked as started (picked up or delivered)
- Stop: When the StockItem is marked as stopped (returned)
The status of each StockItem is tracked independently, allowing partial pickups and returns.
Tracking Benefits
StockItemPlannings provide several key benefits:
- Precise inventory tracking for each individual StockItem
- Ability to track StockItem history (which customers used which specific items)
- Support for partial pickups and returns
- Detailed audit trail of StockItem movements
Relationships
| Name | Description |
|---|---|
downtime |
Downtime optionalThe Downtime this StockItemPlanning is associated with when the planning is for downtime rather than an order. Either order or downtime will be present, but not both. |
order |
Order optionalThe Order this StockItemPlanning is part of. |
planning |
Planning requiredThe Planning for which this StockItemPlanning specifies a StockItem. |
stock_item |
Stock item requiredThe StockItem being specified, and whose status through the fulfillment process is tracked by this StockItemPlanning. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether this StockItemPlanning has been archived. There are two distinct archiving mechanisms: 1. Unspecifying (Unassigning) a StockItem: When a StockItem is "unspecified" from an Order through the OrderFulfillment API, the archived attribute is set to true. This indicates that the StockItem is no longer assigned to this Planning. The archived_at timestamp is updated to record when this occurred. This mechanism allows users to change the StockItems assigned to a Planning without losing the historical record of which StockItems were assigned.2. Archive an Order: When an Order is archived, the status of its StockItemPlannings is set to archived, but the archived attribute remains false. This preserves the historical record of which StockItems were assigned to the Order while marking the entire Order as archived. This mechanism allows users to archive Orders to have a clear overview of current and future Orders without cluttering the UI with historical Orders. |
archived_at |
datetime readonly nullableWhen the StockItemPlanning was archived through StockItem unspecified archiving. This timestamp records when the StockItem was unassigned from the Planning. This field is only updated when the archived attribute is set to true through the StockItem unspecified archiving mechanism. |
created_at |
datetime readonlyWhen the resource was created. |
downtime_id |
uuid readonly nullableThe Downtime this StockItemPlanning is associated with when the planning is for downtime rather than an order. Either order or downtime will be present, but not both. |
id |
uuid readonlyPrimary key. |
order_id |
uuid readonly nullableThe Order this StockItemPlanning is part of. |
planning_id |
uuid readonlyThe Planning for which this StockItemPlanning specifies a StockItem. |
reserved |
boolean Whether StockItem is reserved, meaning it's unavailable for other orders. This is set to true when the order status is changed to "reserved" or when the StockItem is specifically assigned to the planning. When reserved, the item cannot be booked for other orders during the same period. |
started |
boolean Whether the StockItem is started, meaning it has been picked up by the customer or delivered. This is set to true when staff performs a "Start" action through the OrderFulfillments resource. Once started, the item is physically out with the customer and its status can be tracked independently of other items on the same order. |
starts_at |
datetime When the StockItem is scheduled to be picked up or delivered. This date/time indicates when the specific StockItem will begin its rental period, aligning with the planning's start date. This date/time is not updated when a StockItem is picked up earlier or later than originally scheduled. |
status |
enum readonlyStatus of this StockItemPlanning. A StockItemPlanning becomes "stopped" when the StockItem is returned. The Order it belongs to might not be completely stopped (partial return). Otherwise, the status mostly follows the status of the Order. Note that there are two concepts of "archiving". The archived attribute is set to true when a StockItem is "unspecified" from an Order through the OrderFulfillment API. When an Order is archived, status of StockItemPlannings is set to archived, but the archived attribute remains false.Possible status values: - new: When the order is in new state. - draft: When the order is in draft state. - reserved: When the StockItem is reserved for this order. The parent Order can already be started due to partial pickups. - started: When the StockItem has been picked up or delivered. - stopped: When the StockItem has been returned. The parent Order can still be started due to partial returns. - archived: When the parent Order has been archived. - canceled: When the parent Order has been canceled.One of: new, draft, reserved, started, stopped, archived, canceled. |
stock_item_id |
uuid readonlyThe StockItem being specified, and whose status through the fulfillment process is tracked by this StockItemPlanning. |
stock_item_planning_type |
enum readonlyThe type of planning this StockItemPlanning belongs to. This field indicates whether the StockItem is allocated for a regular order or for downtime. One of: order, downtime.order - The StockItem is allocated for a regular rental order.downtime - The StockItem is allocated for downtime.This attribute helps distinguish between order-related and downtime-related StockItem allocations, which may have different business logic and display requirements. |
stopped |
boolean Whether the StockItem is stopped, meaning it has been returned by the customer and is available again for other rentals. This is set to true when staff performs a "Stop" action through the OrderFulfillments resource. A StockItem must be started before it can be stopped. Once stopped, the item becomes available for other bookings. |
stops_at |
datetime When the StockItem is scheduled to be returned. This date/time indicates when the specific StockItem will end its rental period, aligning with the planning's stop date. This date/time is not updated when a StockItem is returned earlier or later than originally scheduled. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List stock item plannings
How to fetch a list of stock item plannings:
curl --get 'https://example.booqable.com/api/4/stock_item_plannings'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "76e3b6a9-a2ef-48f7-813b-a183307e38ce",
"type": "stock_item_plannings",
"attributes": {
"created_at": "2021-11-26T13:55:00.000000+00:00",
"updated_at": "2021-11-26T13:55:00.000000+00:00",
"archived": false,
"archived_at": null,
"starts_at": null,
"stops_at": null,
"reserved": false,
"started": false,
"stopped": false,
"status": "draft",
"stock_item_planning_type": "order",
"stock_item_id": "cb6d24a2-3cdf-47ad-8b45-e484a3447f07",
"planning_id": "a0d6b272-7ad6-4a19-8c78-7a77546685b6",
"order_id": "a7840ea8-9a1c-473b-8218-df29c7e23ae3",
"downtime_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/stock_item_plannings
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_item_plannings]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=stock_item,planning,order |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
downtime_id |
uuid eq, not_eq |
id |
uuid eq, not_eq |
order_id |
uuid eq, not_eq |
planning_id |
uuid eq, not_eq |
reserved |
boolean eq |
started |
boolean eq |
starts_at |
datetime eq, not_eq, gt, gte, lt, lte |
status |
enum eq |
stock_item_id |
uuid eq, not_eq |
stock_item_planning_type |
enum eq |
stopped |
boolean eq |
stops_at |
datetime eq, not_eq, gt, gte, lt, lte |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
status |
array count |
total |
array count |
Includes
This request accepts the following includes:
downtime-
ordercustomer
planning-
stock_item-
productphoto
-
Archive a stock item planning (DEPRECATED)
(DEPRECATED) How to archive a stock item planning:
curl --request DELETE
--url 'https://example.booqable.com/api/4/stock_item_plannings/de7107aa-a6f6-4267-8d25-0900853fa86e'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "de7107aa-a6f6-4267-8d25-0900853fa86e",
"type": "stock_item_plannings",
"attributes": {
"created_at": "2017-02-23T21:35:01.000000+00:00",
"updated_at": "2017-02-23T21:35:01.000000+00:00",
"archived": false,
"archived_at": null,
"starts_at": null,
"stops_at": null,
"reserved": false,
"started": false,
"stopped": false,
"status": "draft",
"stock_item_planning_type": "order",
"stock_item_id": "43333d08-17a4-4fba-8d4e-d72ca065b58e",
"planning_id": "1d924e5e-e519-4099-8a55-2bb0ad9b1658",
"order_id": "a14b0c0b-28ec-40a9-8731-70f3e67ba44e",
"downtime_id": null
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/stock_item_plannings/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_item_plannings]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Stock item suggestions
Use stock item suggestions to figure out which stock item can be booked, started, or stopped.
The suggestions are sorted: 1. Temporary stock items are sorted before permanent stock items. 2. Available stock items are sorted before overdue, unavailable and already_booked stock items. 3. Equally relevant stock items are sorted by the identifier.
Relationships
| Name | Description |
|---|---|
item |
Item requiredThe Product the suggested stock item belongs to. |
stock_item |
Stock item requiredThe suggested stock item. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
id |
uuid readonlyPrimary key. |
item_id |
uuid readonlyThe Product the suggested stock item belongs to. |
status |
enum readonlyStatus of the suggested stock item. One of: available_in_location, available_in_cluster, overdue, unavailable, already_booked. |
stock_item_id |
uuid readonlyThe suggested stock item. |
List stock item suggestions
Retrieve stock item suggestions for booking:
curl --get 'https://example.booqable.com/api/4/stock_item_suggestions'
--header 'content-type: application/json'
--data-urlencode 'filter[action]=book'
--data-urlencode 'filter[item_id]=402fa5d1-ec05-46ad-85ee-c56564c66946'
--data-urlencode 'filter[order_id]=38c7808b-99c9-4b0e-8dbe-dcf731d54ca9'
A 200 status response looks like this:
{
"data": [
{
"id": "8ce54731-3e9e-48fd-898a-42985159c79a",
"type": "stock_item_suggestions",
"attributes": {
"status": "available_in_location",
"item_id": "402fa5d1-ec05-46ad-85ee-c56564c66946",
"stock_item_id": "e1ceaec8-5cd6-4097-87ec-77e8e1fe5381"
},
"relationships": {}
},
{
"id": "484c2445-4864-4e9d-87f6-d37086fbae96",
"type": "stock_item_suggestions",
"attributes": {
"status": "already_booked",
"item_id": "402fa5d1-ec05-46ad-85ee-c56564c66946",
"stock_item_id": "8d913ead-29f6-4cde-8a88-001222806991"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/stock_item_suggestions
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[stock_item_suggestions]=status,item_id,stock_item_id |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=stock_item |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
action |
enum requiredeq |
from |
datetime eq |
item_id |
uuid requiredeq |
location_id |
uuid eq |
order_id |
uuid requiredeq |
q |
string eq |
status |
enum eq |
till |
datetime eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
stock_item
Tags
Tags allow users to label and quickly identify customers, orders and products.
Tags are assigned by writing the tag_list attribute on resources that support tags.
The Tag resource allows to gather names and usage counts of tags that are being used.
Fields
| Name | Description |
|---|---|
count |
integer How often this tag is used. |
for |
enum writeonlyThe resource to show the tag counts for. One of: Order, Customer, ProductGroup, Bundle, Document. |
id |
uuid readonlyPrimary key. |
name |
string Name of the tag. |
List tags
How to fetch a list of tags with their counts:
curl --get 'https://example.booqable.com/api/4/tags'
--header 'content-type: application/json'
--data-urlencode 'filter[for]=Order'
A 200 status response looks like this:
{
"data": [
{
"id": "9ab5867e-6bcc-497d-800a-17a81435dca3",
"type": "tags",
"attributes": {
"name": "vip",
"count": 1
}
},
{
"id": "e15b75d1-c447-4d47-87a5-24e44dfac6a4",
"type": "tags",
"attributes": {
"name": "webshop",
"count": 3
}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tags
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tags]=name,count |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
for |
enum requiredeq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Tax categories
You can create different tax categories and assign them according to the tax requirements of a product. The tax rates in the category are charged over a product when it's added to an order. An order's total tax rate is the sum of all product taxes on that order.
Relationships
| Name | Description |
|---|---|
tax_rates |
Tax rates hasmanyThe different rates that need to be charged. Rates can be created/updated through the TaxRate resource by writing the tax_rates_attributes attribute. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the tax category is archived. |
archived_at |
datetime readonly nullableWhen the tax category was archived. |
created_at |
datetime readonlyWhen the resource was created. |
default |
boolean Whether this is the default tax category. Setting this value to true will set other tax categories to false. |
id |
uuid readonlyPrimary key. |
name |
string Name of the tax category. |
tax_rates_attributes |
array writeonlyThe tax rates to associate. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List tax categories
How to fetch a list of tax categories:
curl --get 'https://example.booqable.com/api/4/tax_categories'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "eb6ca64a-1783-4ca7-8e92-8ec7ab3ff4eb",
"type": "tax_categories",
"attributes": {
"created_at": "2021-09-13T19:57:01.000000+00:00",
"updated_at": "2021-09-13T19:57:01.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Sales Tax",
"default": false
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tax_categories
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_categories]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=tax_rates |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
default |
boolean eq |
id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
tax_rates
Fetch a tax category
How to fetch a tax categories with it's tax rates:
curl --get 'https://example.booqable.com/api/4/tax_categories/471739b4-dc9f-404d-8324-c61a3de5e2da'
--header 'content-type: application/json'
--data-urlencode 'include=tax_rates'
A 200 status response looks like this:
{
"data": {
"id": "471739b4-dc9f-404d-8324-c61a3de5e2da",
"type": "tax_categories",
"attributes": {
"created_at": "2021-02-06T21:30:00.000000+00:00",
"updated_at": "2021-02-06T21:30:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Sales Tax",
"default": false
},
"relationships": {
"tax_rates": {
"data": [
{
"type": "tax_rates",
"id": "2de2a095-6e4a-4ebd-8b21-6bb8dabfd593"
}
]
}
}
},
"included": [
{
"id": "2de2a095-6e4a-4ebd-8b21-6bb8dabfd593",
"type": "tax_rates",
"attributes": {
"created_at": "2021-02-06T21:30:00.000000+00:00",
"updated_at": "2021-02-06T21:30:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "VAT",
"value": 21.0,
"position": 1,
"owner_id": "471739b4-dc9f-404d-8324-c61a3de5e2da",
"owner_type": "tax_categories"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tax_categories/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_categories]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=tax_rates |
Includes
This request accepts the following includes:
tax_rates
Create a tax category
How to create a tax category with tax rates:
curl --request POST
--url 'https://example.booqable.com/api/4/tax_categories'
--header 'content-type: application/json'
--data '{
"data": {
"type": "tax_categories",
"attributes": {
"name": "Sales Tax",
"tax_rates_attributes": [
{
"name": "VAT",
"value": 21
}
]
}
},
"include": "tax_rates"
}'
A 201 status response looks like this:
{
"data": {
"id": "a2acf665-e4f1-4f21-8dbc-bc971ddc0930",
"type": "tax_categories",
"attributes": {
"created_at": "2022-01-08T11:51:00.000000+00:00",
"updated_at": "2022-01-08T11:51:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Sales Tax",
"default": false
},
"relationships": {
"tax_rates": {
"data": [
{
"type": "tax_rates",
"id": "823436f2-33a3-40d1-8841-d71705ec33f5"
}
]
}
}
},
"included": [
{
"id": "823436f2-33a3-40d1-8841-d71705ec33f5",
"type": "tax_rates",
"attributes": {
"created_at": "2022-01-08T11:51:00.000000+00:00",
"updated_at": "2022-01-08T11:51:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "VAT",
"value": 21.0,
"position": 1,
"owner_id": "a2acf665-e4f1-4f21-8dbc-bc971ddc0930",
"owner_type": "tax_categories"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/tax_categories
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_categories]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=tax_rates |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][default] |
boolean Whether this is the default tax category. Setting this value to true will set other tax categories to false. |
data[attributes][name] |
string Name of the tax category. |
data[attributes][tax_rates_attributes][] |
array The tax rates to associate. |
Includes
This request accepts the following includes:
tax_rates
Update a tax category
How to update a tax category with tax rates:
curl --request PUT
--url 'https://example.booqable.com/api/4/tax_categories/e3d7ddaf-e57a-47bb-8eef-839b7f1a4bfd'
--header 'content-type: application/json'
--data '{
"data": {
"id": "e3d7ddaf-e57a-47bb-8eef-839b7f1a4bfd",
"type": "tax_categories",
"attributes": {
"name": "State Tax",
"tax_rates_attributes": [
{
"name": "VAT",
"value": 9
},
{
"id": "3341f09b-efc4-4586-8c73-2125fbb05896",
"_destroy": true
}
]
}
},
"include": "tax_rates"
}'
A 200 status response looks like this:
{
"data": {
"id": "e3d7ddaf-e57a-47bb-8eef-839b7f1a4bfd",
"type": "tax_categories",
"attributes": {
"created_at": "2021-11-08T05:22:00.000000+00:00",
"updated_at": "2021-11-08T05:22:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "State Tax",
"default": false
},
"relationships": {
"tax_rates": {
"data": [
{
"type": "tax_rates",
"id": "a9588059-d21e-4093-8059-b130c575b763"
},
{
"type": "tax_rates",
"id": "3341f09b-efc4-4586-8c73-2125fbb05896"
}
]
}
}
},
"included": [
{
"id": "a9588059-d21e-4093-8059-b130c575b763",
"type": "tax_rates",
"attributes": {
"created_at": "2021-11-08T05:22:00.000000+00:00",
"updated_at": "2021-11-08T05:22:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "VAT",
"value": 9.0,
"position": 2,
"owner_id": "e3d7ddaf-e57a-47bb-8eef-839b7f1a4bfd",
"owner_type": "tax_categories"
},
"relationships": {}
},
{
"id": "3341f09b-efc4-4586-8c73-2125fbb05896",
"type": "tax_rates",
"attributes": {
"created_at": "2021-11-08T05:22:00.000000+00:00",
"updated_at": "2021-11-08T05:22:00.000000+00:00",
"archived": true,
"archived_at": "2021-11-08T05:22:00.000000+00:00",
"name": "Vat",
"value": 21.0,
"position": 1,
"owner_id": "e3d7ddaf-e57a-47bb-8eef-839b7f1a4bfd",
"owner_type": "tax_categories"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
PUT /api/4/tax_categories/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_categories]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=tax_rates |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][default] |
boolean Whether this is the default tax category. Setting this value to true will set other tax categories to false. |
data[attributes][name] |
string Name of the tax category. |
data[attributes][tax_rates_attributes][] |
array The tax rates to associate. |
Includes
This request accepts the following includes:
tax_rates
Delete a tax category
How to delete a tax category with tax rates:
curl --request DELETE
--url 'https://example.booqable.com/api/4/tax_categories/c7095ef4-6e5b-42f7-8675-6fd1e233106f'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "c7095ef4-6e5b-42f7-8675-6fd1e233106f",
"type": "tax_categories",
"attributes": {
"created_at": "2027-06-16T04:31:07.000000+00:00",
"updated_at": "2027-06-16T04:31:07.000000+00:00",
"archived": true,
"archived_at": "2027-06-16T04:31:07.000000+00:00",
"name": "Sales Tax (Archived)",
"default": false
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/tax_categories/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_categories]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Tax rates
Tax rates are always assigned to either a TaxRegion or TaxCategory. Tax rates define the individual rates that will be taxed.
Relationships
| Name | Description |
|---|---|
owner |
Tax category, Tax region requiredThe TaxRegion or TaxCategory this TaxRate is part of. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
archived |
boolean readonlyWhether the tax rate is archived. |
archived_at |
datetime readonly nullableWhen the tax rate was archived. |
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
name |
string The name of the tax rate. |
owner_id |
uuid readonly-after-createThe TaxRegion or TaxCategory this TaxRate is part of. |
owner_type |
enum readonly-after-createThe resource type of the owner. One of: tax_categories, tax_regions. |
position |
integer readonlyPosition of the tax rate. |
updated_at |
datetime readonlyWhen the resource was last updated. |
value |
float The percentage value of the rate. |
List tax rates
How to fetch a list of tax rates:
curl --get 'https://example.booqable.com/api/4/tax_rates'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "d39e7448-db31-4b79-82da-4e0c59539ac4",
"type": "tax_rates",
"attributes": {
"created_at": "2016-01-22T07:05:01.000000+00:00",
"updated_at": "2016-01-22T07:05:01.000000+00:00",
"archived": false,
"archived_at": null,
"name": "VAT",
"value": 21.0,
"position": 1,
"owner_id": "c0ac16c6-1011-4d0d-8a6d-20b0b13763cd",
"owner_type": "tax_regions"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tax_rates
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_rates]=created_at,updated_at,archived |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=owner |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
archived |
boolean eq |
archived_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
owner
Fetch a tax rate
How to fetch a tax rate:
curl --get 'https://example.booqable.com/api/4/tax_rates/4315e7db-350a-4786-848a-27333157f531'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": {
"id": "4315e7db-350a-4786-848a-27333157f531",
"type": "tax_rates",
"attributes": {
"created_at": "2028-12-26T07:19:00.000000+00:00",
"updated_at": "2028-12-26T07:19:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "VAT",
"value": 21.0,
"position": 1,
"owner_id": "bed7a8b1-0fc6-401d-818a-374b416dbbd5",
"owner_type": "tax_regions"
},
"relationships": {
"owner": {
"data": {
"type": "tax_regions",
"id": "bed7a8b1-0fc6-401d-818a-374b416dbbd5"
}
}
}
},
"included": [
{
"id": "bed7a8b1-0fc6-401d-818a-374b416dbbd5",
"type": "tax_regions",
"attributes": {
"created_at": "2028-12-26T07:19:00.000000+00:00",
"updated_at": "2028-12-26T07:19:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Sales Tax",
"strategy": "add_to",
"default": false
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tax_rates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_rates]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
owner
Create a tax rate
How to create a tax rate and associate it with an owner:
curl --request POST
--url 'https://example.booqable.com/api/4/tax_rates'
--header 'content-type: application/json'
--data '{
"data": {
"type": "tax_rates",
"attributes": {
"name": "VAT",
"value": 21,
"owner_id": "12188347-ab4b-416c-8b2d-44bf5802abbc",
"owner_type": "tax_regions"
}
},
"include": "owner"
}'
A 201 status response looks like this:
{
"data": {
"id": "87122383-0cc0-4126-8013-a213d1fbb19d",
"type": "tax_rates",
"attributes": {
"created_at": "2021-02-16T04:50:00.000000+00:00",
"updated_at": "2021-02-16T04:50:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "VAT",
"value": 21.0,
"position": 1,
"owner_id": "12188347-ab4b-416c-8b2d-44bf5802abbc",
"owner_type": "tax_regions"
},
"relationships": {
"owner": {
"data": {
"type": "tax_regions",
"id": "12188347-ab4b-416c-8b2d-44bf5802abbc"
}
}
}
},
"included": [
{
"id": "12188347-ab4b-416c-8b2d-44bf5802abbc",
"type": "tax_regions",
"attributes": {
"created_at": "2021-02-16T04:50:00.000000+00:00",
"updated_at": "2021-02-16T04:50:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Sales Tax",
"strategy": "add_to",
"default": false
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
POST /api/4/tax_rates
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_rates]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][name] |
string The name of the tax rate. |
data[attributes][owner_id] |
uuid The TaxRegion or TaxCategory this TaxRate is part of. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: tax_categories, tax_regions. |
data[attributes][value] |
float The percentage value of the rate. |
Includes
This request accepts the following includes:
owner
Update a tax rate
How to update a tax rate:
curl --request PUT
--url 'https://example.booqable.com/api/4/tax_rates/85ba8a31-4370-484d-86f2-4da1726975ff'
--header 'content-type: application/json'
--data '{
"data": {
"id": "85ba8a31-4370-484d-86f2-4da1726975ff",
"type": "tax_rates",
"attributes": {
"value": 9
}
},
"include": "owner"
}'
A 200 status response looks like this:
{
"data": {
"id": "85ba8a31-4370-484d-86f2-4da1726975ff",
"type": "tax_rates",
"attributes": {
"created_at": "2020-08-24T18:48:00.000000+00:00",
"updated_at": "2020-08-24T18:48:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Vat",
"value": 9.0,
"position": 1,
"owner_id": "309c4936-b8c0-4af3-80c5-1659745b4375",
"owner_type": "tax_categories"
},
"relationships": {
"owner": {
"data": {
"type": "tax_categories",
"id": "309c4936-b8c0-4af3-80c5-1659745b4375"
}
}
}
},
"included": [
{
"id": "309c4936-b8c0-4af3-80c5-1659745b4375",
"type": "tax_categories",
"attributes": {
"created_at": "2020-08-24T18:48:00.000000+00:00",
"updated_at": "2020-08-24T18:48:00.000000+00:00",
"archived": false,
"archived_at": null,
"name": "Sales Tax",
"default": false
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
PUT /api/4/tax_rates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_rates]=created_at,updated_at,archived |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][name] |
string The name of the tax rate. |
data[attributes][owner_id] |
uuid The TaxRegion or TaxCategory this TaxRate is part of. |
data[attributes][owner_type] |
enum The resource type of the owner. One of: tax_categories, tax_regions. |
data[attributes][value] |
float The percentage value of the rate. |
Includes
This request accepts the following includes:
owner
Delete a tax rate
How to delete a tax rate:
curl --request DELETE
--url 'https://example.booqable.com/api/4/tax_rates/b018f5dc-4f78-414a-8728-22d47be42893'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "b018f5dc-4f78-414a-8728-22d47be42893",
"type": "tax_rates",
"attributes": {
"created_at": "2026-11-02T15:14:02.000000+00:00",
"updated_at": "2026-11-02T15:14:02.000000+00:00",
"archived": true,
"archived_at": "2026-11-02T15:14:02.000000+00:00",
"name": "VAT",
"value": 21.0,
"position": 1,
"owner_id": "6af038f1-d8e7-4001-8ce9-f365ecd2b6e1",
"owner_type": "tax_regions"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
DELETE /api/4/tax_rates/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_rates]=created_at,updated_at,archived |
Includes
This request does not accept any includes
Tax values
Tax values are generated automatically by price calculations for Orders and Carts. They hold information about the amount taxed for a specific rate.
Relationships
| Name | Description |
|---|---|
owner |
Order, Document requiredThe order or cart. |
tax_rate |
Tax rate requiredThe rate used to calculated this tax. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen the resource was created. |
id |
uuid readonlyPrimary key. |
name |
string readonlyName of the tax rate. |
owner_id |
uuid readonlyThe order or cart. |
owner_type |
enum readonlyThe resource type of the owner. One of: orders, documents. |
percentage |
float readonlyThe percentage taxed. |
tax_rate_id |
uuid readonlyThe rate used to calculated this tax. |
updated_at |
datetime readonlyWhen the resource was last updated. |
value_in_cents |
integer readonlyAmount of tax in cents. |
List tax values
How to fetch a list of tax values:
curl --get 'https://example.booqable.com/api/4/tax_values'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "806d7c35-3f4c-4c1b-8766-11c9f012e6f2",
"type": "tax_values",
"attributes": {
"created_at": "2018-04-23T02:36:00.000000+00:00",
"updated_at": "2018-04-23T02:36:00.000000+00:00",
"name": "VAT 19%",
"percentage": 19.0,
"value_in_cents": 13800,
"tax_rate_id": "67d4d696-b147-4a30-8f26-413641077ca6",
"owner_id": "bc39e751-ea2e-4f5c-879d-4bc23d403698",
"owner_type": "orders"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tax_values
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_values]=created_at,updated_at,name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
owner_id |
uuid eq, not_eq |
owner_type |
enum eq, not_eq |
percentage |
float eq, not_eq, gt, gte, lt, lte |
tax_rate_id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
value_in_cents |
integer eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
value_in_cents |
array sum, maximum, minimum, average |
Includes
This request does not accept any includes
Fetch a tax value
How to fetch a tax value:
curl --get 'https://example.booqable.com/api/4/tax_values/af3a48e5-050f-4556-89e6-e863b75c268a'
--header 'content-type: application/json'
--data-urlencode 'include=owner'
A 200 status response looks like this:
{
"data": {
"id": "af3a48e5-050f-4556-89e6-e863b75c268a",
"type": "tax_values",
"attributes": {
"created_at": "2018-02-01T17:33:00.000000+00:00",
"updated_at": "2018-02-01T17:33:00.000000+00:00",
"name": "VAT 19%",
"percentage": 19.0,
"value_in_cents": 13800,
"tax_rate_id": "badc9624-dce0-4222-87c1-62dd12ef84f4",
"owner_id": "fb0af3c4-01e8-4dce-8fa4-b5e184c08a33",
"owner_type": "orders"
},
"relationships": {
"owner": {
"data": {
"type": "orders",
"id": "fb0af3c4-01e8-4dce-8fa4-b5e184c08a33"
}
}
}
},
"included": [
{
"id": "fb0af3c4-01e8-4dce-8fa4-b5e184c08a33",
"type": "orders",
"attributes": {
"created_at": "2018-02-01T17:33:00.000000+00:00",
"updated_at": "2018-02-01T17:33:00.000000+00:00",
"number": null,
"status": "new",
"statuses": [
"new"
],
"status_counts": {
"new": 0,
"draft": 0,
"reserved": 0,
"started": 0,
"stopped": 0
},
"starts_at": "2018-01-30T17:32:00.000000+00:00",
"stops_at": "2018-02-03T17:32:00.000000+00:00",
"deposit_type": "percentage",
"deposit_value": 100.0,
"entirely_started": true,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "paid",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 0,
"tag_list": [],
"properties": {
"delivery_address": null,
"billing_address": null
},
"amount_in_cents": 0,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": null,
"deposit_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": null,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 0,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 0,
"total_discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"discount_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"paid_in_cents": 0,
"price_in_cents": 0,
"tax_in_cents": 0,
"to_be_paid_in_cents": 0,
"discount_type": "percentage",
"discount_percentage": 0.0,
"billing_address_property_id": null,
"delivery_address_property_id": null,
"fulfillment_type": "pickup",
"delivery_address": null,
"customer_id": null,
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "85f56930-46f4-40f6-8df3-e14cb405b347",
"stop_location_id": "85f56930-46f4-40f6-8df3-e14cb405b347",
"order_delivery_rate_id": null
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/tax_values/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[tax_values]=created_at,updated_at,name |
include |
string List of comma seperated relationships to sideload. ?include=owner |
Includes
This request accepts the following includes:
owner
Transfers
When an order causes a shortage for a location and that shortage can be solved by the inventory in the cluster, one or multiple transfers are created.
Relationships
| Name | Description |
|---|---|
destination_location |
Location requiredLocation to which the product needs to be transferred to. |
item |
Item requiredThe Product that needs to be transferred. |
order |
Order requiredThe Order for which the product is required. |
source_location |
Location requiredLocation from which the product needs to be transferred. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
available_at |
datetime Date when item should be available at destination location. |
created_at |
datetime readonlyWhen the resource was created. |
destination_location_id |
uuid readonlyLocation to which the product needs to be transferred to. |
finalized |
boolean Whether or not the transfer has completed. |
id |
uuid readonlyPrimary key. |
item_id |
uuid readonlyThe Product that needs to be transferred. |
order_id |
uuid readonlyThe Order for which the product is required. |
quantity |
integer Quantity of items being transferred. |
source_location_id |
uuid readonlyLocation from which the product needs to be transferred. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List transfers
How to fetch a list of transfers:
curl --get 'https://example.booqable.com/api/4/transfers'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "6f5d421b-37d1-4f12-8170-d8bb4b8ce0b8",
"type": "transfers",
"attributes": {
"created_at": "2028-08-08T18:28:00.000000+00:00",
"updated_at": "2028-08-08T18:28:00.000000+00:00",
"quantity": 1,
"available_at": "2028-08-06T18:27:00.000000+00:00",
"finalized": false,
"item_id": "672d6735-92fa-4198-8145-116e1191847d",
"order_id": "058a8f0f-d1ac-4363-8778-a6c4476ee292",
"source_location_id": "1773d662-6eb3-4dae-8736-31948f79df75",
"destination_location_id": "1773d662-6eb3-4dae-8736-31948f79df75"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/transfers
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[transfers]=created_at,updated_at,quantity |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
include |
string List of comma seperated relationships to sideload. ?include=order,item,source_location |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
available_at |
datetime eq, not_eq, gt, gte, lt, lte |
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
destination_location_id |
uuid eq, not_eq |
finalized |
boolean eq |
id |
uuid eq, not_eq |
item_id |
uuid eq, not_eq |
order_id |
uuid eq, not_eq |
q |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
quantity |
integer eq, not_eq, gt, gte, lt, lte |
source_location_id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request accepts the following includes:
destination_location-
itemphoto
ordersource_location
User invitations
Creating a user will send an invitation to the user. If that email message is lost or deleted, use this to resend the invitation email so the user can confirm their email before the account is active.
Relationships
| Name | Description |
|---|---|
user |
User requiredThe user to send the invitation to. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
id |
uuid readonlyPrimary key. |
user_id |
uuid The user to send the invitation to. |
Re-invite a user
How to re-invite a user:
curl --request POST
--url 'https://example.booqable.com/api/4/user_invitations'
--header 'content-type: application/json'
--data '{
"data": {
"type": "user_invitations",
"attributes": {
"user_id": "c8075239-a5b3-4523-8ca2-84e0023813d1"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "32dbf20f-66cb-4977-88ec-8ec42fbddc6a",
"type": "user_invitations",
"attributes": {
"user_id": "c8075239-a5b3-4523-8ca2-84e0023813d1"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/user_invitations
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[user_invitations]=user_id |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][user_id] |
uuid The user to send the invitation to. |
Includes
This request does not accept any includes
Users
Users can be used to log into the web shop. They are useful for exposing your shop to a limited audience or verifiying that a customers can actually be reached via an email.
A user always belongs to a Customer. A customer can have multiple users. This is relevant for companies where multiple people are allowed to book orders in the name of that company. Because of this, a user should always be an actual person, not a legal person.
Depending on the setting in your Booqable account, creating a user can actually mean that you're inviting the user. In that case, the user still needs to confirm their email and set a password before the account is active. (See status)
Relationships
| Name | Description |
|---|---|
customer |
Customer requiredCustomer who owns this account. |
notes |
Notes hasmanyNotes about this user. |
Check matching attributes under Fields to see which relations can be written.
Check each individual operation to see which relations can be included as a sideload.
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen the resource was created. |
customer_id |
uuid readonly-after-createCustomer who owns this account. |
disabled |
boolean writeonlyWhen a user is disabled they cannot log into their account or create orders. |
email |
string readonly-after-createThe email of the user. |
first_name |
string The first name of the user. |
id |
uuid readonlyPrimary key. |
last_name |
string The last name of the user. |
name |
string The full name of the user (first_name + last_name). |
status |
enum readonlyStatus. One of: disabled, active, invited, unconfirmed. |
updated_at |
datetime readonlyWhen the resource was last updated. |
List users
How to fetch a list of users:
curl --get 'https://example.booqable.com/api/4/users'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "ca08d52a-c5d9-433f-8774-bd964a456f31",
"type": "users",
"attributes": {
"created_at": "2028-10-16T13:17:01.000000+00:00",
"updated_at": "2028-10-16T13:17:01.000000+00:00",
"first_name": "John",
"last_name": "Doe",
"name": "John Doe",
"email": "[email protected]",
"status": "active",
"customer_id": "7e745c70-f3c2-47be-8ac6-3f11e3ce374b"
},
"relationships": {}
}
],
"meta": {}
}
How to find users belonging to a customer:
curl --get 'https://example.booqable.com/api/4/users'
--header 'content-type: application/json'
--data-urlencode 'filter[customer_id]=fe7b81ca-a0ac-425d-8618-2e1929b46bc8'
--data-urlencode 'include=customer'
A 200 status response looks like this:
{
"data": [
{
"id": "dbbce813-8d54-47d6-8b4d-eec5b28c878c",
"type": "users",
"attributes": {
"created_at": "2023-08-23T07:33:01.000000+00:00",
"updated_at": "2023-08-23T07:33:01.000000+00:00",
"first_name": "John",
"last_name": "Doe",
"name": "John Doe",
"email": "[email protected]",
"status": "active",
"customer_id": "fe7b81ca-a0ac-425d-8618-2e1929b46bc8"
},
"relationships": {}
}
],
"meta": {}
}
HTTP Request
GET /api/4/users
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[users]=created_at,updated_at,first_name |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
customer_id |
uuid eq, not_eq |
email |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
first_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
id |
uuid eq, not_eq |
last_name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
name |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
status |
enum eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Fetch a user
How to fetch a user:
curl --get 'https://example.booqable.com/api/4/users/c92780ab-5df7-4cbd-8435-a2c09cee05e8'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "c92780ab-5df7-4cbd-8435-a2c09cee05e8",
"type": "users",
"attributes": {
"created_at": "2023-09-28T12:54:04.000000+00:00",
"updated_at": "2023-09-28T12:54:04.000000+00:00",
"first_name": "John",
"last_name": "Doe",
"name": "John Doe",
"email": "[email protected]",
"status": "active",
"customer_id": "d51b343c-b9f4-4080-8923-80d182b6de87"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
GET /api/4/users/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[users]=created_at,updated_at,first_name |
include |
string List of comma seperated relationships to sideload. ?include=customer,disabled_by,notes |
Includes
This request accepts the following includes:
customerdisabled_bynotes
Invite a user
How to invite a user:
curl --request POST
--url 'https://example.booqable.com/api/4/users'
--header 'content-type: application/json'
--data '{
"data": {
"type": "users",
"attributes": {
"first_name": "Bob",
"last_name": "Bobsen",
"email": "[email protected]",
"customer_id": "dbc90081-f163-4c62-8cb3-5b1ecbb19235"
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "75e1d103-6838-433a-8f0d-62737c7a8761",
"type": "users",
"attributes": {
"created_at": "2017-06-05T11:04:00.000000+00:00",
"updated_at": "2017-06-05T11:04:00.000000+00:00",
"first_name": "Bob",
"last_name": "Bobsen",
"name": "Bob Bobsen",
"email": "[email protected]",
"status": "invited",
"customer_id": "dbc90081-f163-4c62-8cb3-5b1ecbb19235"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
POST /api/4/users
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[users]=created_at,updated_at,first_name |
include |
string List of comma seperated relationships to sideload. ?include=customer,disabled_by,notes |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][customer_id] |
uuid Customer who owns this account. |
data[attributes][disabled] |
boolean When a user is disabled they cannot log into their account or create orders. |
data[attributes][email] |
string The email of the user. |
data[attributes][first_name] |
string The first name of the user. |
data[attributes][last_name] |
string The last name of the user. |
data[attributes][name] |
string The full name of the user (first_name + last_name). |
Includes
This request accepts the following includes:
customerdisabled_bynotes
Update a user
How to update a user:
curl --request PUT
--url 'https://example.booqable.com/api/4/users/c7e240ef-31fa-4e38-8cb7-cafd7719304c'
--header 'content-type: application/json'
--data '{
"data": {
"id": "c7e240ef-31fa-4e38-8cb7-cafd7719304c",
"type": "users",
"attributes": {
"first_name": "Bobba"
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "c7e240ef-31fa-4e38-8cb7-cafd7719304c",
"type": "users",
"attributes": {
"created_at": "2021-01-03T08:52:01.000000+00:00",
"updated_at": "2021-01-03T08:52:01.000000+00:00",
"first_name": "Bobba",
"last_name": "Doe",
"name": "Bobba Doe",
"email": "[email protected]",
"status": "active",
"customer_id": "947c2a92-d6bf-4637-860d-17e82c6dbf1b"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/users/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[users]=created_at,updated_at,first_name |
include |
string List of comma seperated relationships to sideload. ?include=customer,disabled_by,notes |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][customer_id] |
uuid Customer who owns this account. |
data[attributes][disabled] |
boolean When a user is disabled they cannot log into their account or create orders. |
data[attributes][email] |
string The email of the user. |
data[attributes][first_name] |
string The first name of the user. |
data[attributes][last_name] |
string The last name of the user. |
data[attributes][name] |
string The full name of the user (first_name + last_name). |
Includes
This request accepts the following includes:
customerdisabled_bynotes
Enable a user
How to enable a user:
curl --request PUT
--url 'https://example.booqable.com/api/4/users/b20174a8-b59e-4d8b-8ae1-af97052ceaae'
--header 'content-type: application/json'
--data '{
"data": {
"id": "b20174a8-b59e-4d8b-8ae1-af97052ceaae",
"type": "users",
"attributes": {
"disabled": false
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "b20174a8-b59e-4d8b-8ae1-af97052ceaae",
"type": "users",
"attributes": {
"created_at": "2025-07-19T12:22:01.000000+00:00",
"updated_at": "2025-07-19T12:22:01.000000+00:00",
"first_name": "John",
"last_name": "Doe",
"name": "John Doe",
"email": "[email protected]",
"status": "active",
"customer_id": "a6d008aa-b06a-4337-84f0-23b4ce2148a9"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/users/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[users]=created_at,updated_at,first_name |
include |
string List of comma seperated relationships to sideload. ?include=customer,disabled_by,notes |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][customer_id] |
uuid Customer who owns this account. |
data[attributes][disabled] |
boolean When a user is disabled they cannot log into their account or create orders. |
data[attributes][email] |
string The email of the user. |
data[attributes][first_name] |
string The first name of the user. |
data[attributes][last_name] |
string The last name of the user. |
data[attributes][name] |
string The full name of the user (first_name + last_name). |
Includes
This request accepts the following includes:
customerdisabled_bynotes
Disable a user
How to disable a user:
curl --request PUT
--url 'https://example.booqable.com/api/4/users/bf3a537d-192a-4df8-8a92-594008521fef'
--header 'content-type: application/json'
--data '{
"data": {
"id": "bf3a537d-192a-4df8-8a92-594008521fef",
"type": "users",
"attributes": {
"disabled": true
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "bf3a537d-192a-4df8-8a92-594008521fef",
"type": "users",
"attributes": {
"created_at": "2022-03-25T21:54:00.000000+00:00",
"updated_at": "2022-03-25T21:54:00.000000+00:00",
"first_name": "John",
"last_name": "Doe",
"name": "John Doe",
"email": "[email protected]",
"status": "disabled",
"customer_id": "79211c5b-e26c-49e8-8199-74af44f213df"
},
"relationships": {}
},
"meta": {}
}
HTTP Request
PUT /api/4/users/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[users]=created_at,updated_at,first_name |
include |
string List of comma seperated relationships to sideload. ?include=customer,disabled_by,notes |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][customer_id] |
uuid Customer who owns this account. |
data[attributes][disabled] |
boolean When a user is disabled they cannot log into their account or create orders. |
data[attributes][email] |
string The email of the user. |
data[attributes][first_name] |
string The first name of the user. |
data[attributes][last_name] |
string The last name of the user. |
data[attributes][name] |
string The full name of the user (first_name + last_name). |
Includes
This request accepts the following includes:
customerdisabled_bynotes
Webhook endpoints
Webhook endpoints are used to notify your application when certain events occur in your Booqable account. You can use these events to trigger actions in your application, such as sending an email, updating a record, or creating a new record.
Version 1 (default)
// v1 payload
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2021-01-01T00:00:00Z",
"event": "customer.created",
"object": "Customer",
"data": {
// same attributes and relations as returned by /api/1/customers/:id
}
}
Resources included in the payload are delivered in the same format as the resource's v1 JSON format. Documentation for this format can be found at https://boomerang.booqable.com/v1.html.
The content-type of the payload for v1 webhooks is application/x-www-form-urlencoded.
Version 4 (opt-in)
// v4 payload
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2021-01-01T00:00:00Z",
"event": "customer.created",
"resource_type": "customers",
"data": {
// same attributes as returned by /api/4/customers/:id,
// plus a subset of the relations as nested JSON objects
}
}
The content-type of the payload for v4 webhooks is application/json.
Included Resources
Resources included in the payload are delivered in the same format as the resource's v4 (aka Boomerang) JSON format. This is the documentation you are looking at.
Note that the payload is in JSON format, not JSON API format. Relations of the resource are delivered as nested JSON objects, not as JSON API relationships.
The table below shows which relations are included in the payload for each resource.
The included relations are always the same for a resource and do not depend on the
event. Includes are not recursive (ie. bundle.updated will NOT include bundle_item.product.barcode).
| Resource | Relations included in webhook payload |
|---|---|
bundles |
bundle_items, bundle_items.product, bundle_items.product_group |
bundle_items |
bundle, product, product_group |
cart |
customer, lines, lines.item, order |
contract/invoice/quote |
coupon, customer, lines, order, tax_values |
customer |
barcode, tax_region |
order |
barcode, coupon, customer, lines, notes, plannings, properties, start_location, stop_location, tax_values |
product_group |
photo, price_ruleset, price_structure, tax_category |
product |
barcode |
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen the webhook endpoint was first registered. |
events |
array[string] The events that will trigger the webhook. One or more from: app.configured, app.installed, app.plan_changed, app.uninstalled, bundle.archived, bundle.created, bundle.updated, bundle_item.archived, bundle_item.created, bundle_item.updated, cart.completed_checkout, contract.archived, contract.confirmed, contract.created, contract.signed, contract.updated, customer.archived, customer.created, customer.updated, invoice.archived, invoice.created, invoice.finalized, invoice.revised, invoice.updated, order.archived, order.canceled, order.reserved, order.saved_as_concept, order.saved_as_draft, order.started, order.stopped, order.updated, payment.completed, product.created, product_group.archived, product_group.created, product_group.updated, quote.archived, quote.confirmed, quote.created, quote.signed, quote.updated. |
id |
uuid readonlyPrimary key. |
updated_at |
datetime readonlyWhen the webhook endpoint was last updated. |
url |
string The URL that will receive the webhook payload. |
version |
enum The version of the webhook payload. One of: 1, 4. |
List webhook endpoints
How to fetch a list of webhook endpoints:
curl --get 'https://example.booqable.com/api/4/webhook_endpoints'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": [
{
"id": "cb0a7fbd-01d5-485d-82a4-11c5eae2e486",
"created_at": "2020-05-19T04:30:06.000000+00:00",
"updated_at": "2020-05-19T04:30:06.000000+00:00",
"url": "https://example.com/hooks",
"events": [
"invoice.finalized"
],
"version": 1
}
]
}
HTTP Request
GET /api/4/webhook_endpoints
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[webhook_endpoints]=created_at,updated_at,url |
filter |
hash The filters to apply ?filter[attribute][eq]=value |
meta |
hash Metadata to send along. ?meta[total][]=count |
page[number] |
string The page to request. |
page[size] |
string The amount of items per page. |
sort |
string How to sort the data. ?sort=attribute1,-attribute2 |
Filters
This request can be filtered on:
| Name | Description |
|---|---|
created_at |
datetime eq, not_eq, gt, gte, lt, lte |
id |
uuid eq, not_eq |
updated_at |
datetime eq, not_eq, gt, gte, lt, lte |
url |
string eq, not_eq, eql, not_eql, prefix, not_prefix, suffix, not_suffix, match, not_match |
version |
enum eq |
Meta
Results can be aggregated on:
| Name | Description |
|---|---|
total |
array count |
Includes
This request does not accept any includes
Subscribe to webhook events
How to subscribe to webhook events and receive v1 payloads:
curl --request POST
--url 'https://example.booqable.com/api/4/webhook_endpoints'
--header 'content-type: application/json'
--data '{
"data": {
"type": "webhook_endpoints",
"attributes": {
"url": "https://example.com/hooks",
"version": 1,
"events": [
"customer.created",
"customer.updated"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "bd50478f-3de1-4432-847f-f7da90859fde",
"type": "webhook_endpoints",
"attributes": {
"created_at": "2019-07-24T05:22:00.000000+00:00",
"updated_at": "2019-07-24T05:22:00.000000+00:00",
"url": "https://example.com/hooks",
"events": [
"customer.created",
"customer.updated"
],
"version": 1
}
},
"meta": {}
}
How to subscribe to webhook events and receive v4 payloads:
curl --request POST
--url 'https://example.booqable.com/api/4/webhook_endpoints'
--header 'content-type: application/json'
--data '{
"data": {
"type": "webhook_endpoints",
"attributes": {
"url": "https://example.com/hooks",
"version": 4,
"events": [
"customer.created",
"customer.updated"
]
}
}
}'
A 201 status response looks like this:
{
"data": {
"id": "be43f04f-01e8-44d9-86ae-1fc1376bdea0",
"type": "webhook_endpoints",
"attributes": {
"created_at": "2021-11-16T09:32:00.000000+00:00",
"updated_at": "2021-11-16T09:32:00.000000+00:00",
"url": "https://example.com/hooks",
"events": [
"customer.created",
"customer.updated"
],
"version": 4
}
},
"meta": {}
}
HTTP Request
POST /api/4/webhook_endpoints
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[webhook_endpoints]=created_at,updated_at,url |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][events] |
array[string] The events that will trigger the webhook. One or more from: app.configured, app.installed, app.plan_changed, app.uninstalled, bundle.archived, bundle.created, bundle.updated, bundle_item.archived, bundle_item.created, bundle_item.updated, cart.completed_checkout, contract.archived, contract.confirmed, contract.created, contract.signed, contract.updated, customer.archived, customer.created, customer.updated, invoice.archived, invoice.created, invoice.finalized, invoice.revised, invoice.updated, order.archived, order.canceled, order.reserved, order.saved_as_concept, order.saved_as_draft, order.started, order.stopped, order.updated, payment.completed, product.created, product_group.archived, product_group.created, product_group.updated, quote.archived, quote.confirmed, quote.created, quote.signed, quote.updated. |
data[attributes][url] |
string The URL that will receive the webhook payload. |
data[attributes][version] |
enum The version of the webhook payload. One of: 1, 4. |
Includes
This request does not accept any includes
Update webhook events
How to update webhook events:
curl --request PUT
--url 'https://example.booqable.com/api/4/webhook_endpoints/a2f71717-53b5-45ba-85c6-3eadcf6cb09f'
--header 'content-type: application/json'
--data '{
"data": {
"type": "webhook_endpoints",
"id": "a2f71717-53b5-45ba-85c6-3eadcf6cb09f",
"attributes": {
"url": "https://example.com/hooks",
"version": 4,
"events": [
"customer.created"
]
}
}
}'
A 200 status response looks like this:
{
"data": {
"id": "a2f71717-53b5-45ba-85c6-3eadcf6cb09f",
"type": "webhook_endpoints",
"attributes": {
"created_at": "2019-07-11T19:29:00.000000+00:00",
"updated_at": "2019-07-11T19:29:00.000000+00:00",
"url": "https://example.com/hooks",
"events": [
"customer.created"
],
"version": 4
}
},
"meta": {}
}
HTTP Request
PUT /api/4/webhook_endpoints/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[webhook_endpoints]=created_at,updated_at,url |
Request body
This request accepts the following body:
| Name | Description |
|---|---|
data[attributes][events] |
array[string] The events that will trigger the webhook. One or more from: app.configured, app.installed, app.plan_changed, app.uninstalled, bundle.archived, bundle.created, bundle.updated, bundle_item.archived, bundle_item.created, bundle_item.updated, cart.completed_checkout, contract.archived, contract.confirmed, contract.created, contract.signed, contract.updated, customer.archived, customer.created, customer.updated, invoice.archived, invoice.created, invoice.finalized, invoice.revised, invoice.updated, order.archived, order.canceled, order.reserved, order.saved_as_concept, order.saved_as_draft, order.started, order.stopped, order.updated, payment.completed, product.created, product_group.archived, product_group.created, product_group.updated, quote.archived, quote.confirmed, quote.created, quote.signed, quote.updated. |
data[attributes][url] |
string The URL that will receive the webhook payload. |
data[attributes][version] |
enum The version of the webhook payload. One of: 1, 4. |
Includes
This request does not accept any includes
Unsubscribe from webhook events
How to unsubscribe from webhook events:
curl --request DELETE
--url 'https://example.booqable.com/api/4/webhook_endpoints/fd2f4709-67d8-441e-8206-213a900ef683'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "fd2f4709-67d8-441e-8206-213a900ef683",
"type": "webhook_endpoints",
"attributes": {
"created_at": "2020-12-01T19:32:01.000000+00:00",
"updated_at": "2020-12-01T19:32:01.000000+00:00",
"url": "https://example.com/hooks",
"events": [],
"version": 1
}
},
"meta": {}
}
HTTP Request
DELETE /api/4/webhook_endpoints/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[webhook_endpoints]=created_at,updated_at,url |
Includes
This request does not accept any includes
Webhooks
Webhooks represent individual notifications that have been sent to your WebhookEndpoints. They contain information about the event that occurred, the version of the webhook, and the data payload that was sent.
Webhooks are only available for a limited time after the event occurred.
Fields
| Name | Description |
|---|---|
created_at |
datetime readonlyWhen this webhook notification was created. This is the timestamp of the original event. |
data |
hash readonlyThe payload data that was sent with this webhook notification. The format and included attributes depend on the version subscribed to. |
event |
enum readonlyThe type of event that triggered this webhook. One of: app.configured, app.installed, app.plan_changed, app.uninstalled, bundle_item.archived, bundle_item.created, bundle_item.updated, bundle.archived, bundle.created, bundle.updated, cart.completed_checkout, contract.archived, contract.confirmed, contract.created, contract.signed, contract.updated, customer.archived, customer.created, customer.updated, invoice.archived, invoice.created, invoice.finalized, invoice.revised, invoice.updated, order.archived, order.canceled, order.reserved, order.saved_as_draft, order.started, order.stopped, order.updated, payment.completed, product_group.archived, product_group.created, product_group.updated, product.created, quote.archived, quote.confirmed, quote.created, quote.signed, quote.updated. |
id |
uuid readonlyThe unique identifier for this webhook notification. |
resource_type |
string readonlyThe JSON API resource type of the resource this webhook notification is about. Examples: orders, products, customers, bundles, invoices, etc. |
updated_at |
datetime readonlyWhen this webhook notification was last updated. This is the timestamp of the last attempt to send the webhook. |
version |
integer readonlyThe version number of the webhook payload format. This only applies to the data attribute. |
Fetch a webhook
How to fetch a webhook (v1 format):
curl --get 'https://example.booqable.com/api/4/webhooks/aba57882-3c35-4134-8743-d98b5e34cd29'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "aba57882-3c35-4134-8743-d98b5e34cd29",
"type": "webhooks",
"attributes": {
"created_at": "2014-03-27T18:03:01.000000+00:00",
"updated_at": "2014-03-27T18:03:01.000000+00:00",
"event": "order.created",
"version": 1,
"resource_type": "orders",
"data": {
"id": "304069d1-983a-4e60-8ae5-c9edfac7e1a1",
"updated_at": "2014-03-27T18:03:01.000000+00:00",
"created_at": "2014-03-27T18:03:01.000000+00:00",
"properties_attributes": {},
"amount_in_cents": 0,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": null,
"deposit_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": null,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 0,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 0,
"total_discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"discount_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"paid_in_cents": 0,
"price_in_cents": 0,
"tax_in_cents": 0,
"to_be_paid_in_cents": 0,
"number": null,
"status": "new",
"statuses": [
"new"
],
"status_counts": {
"new": 0,
"concept": 0,
"reserved": 0,
"started": 0,
"stopped": 0
},
"starts_at": "2014-03-25T18:01:01.000000+00:00",
"stops_at": "2014-03-29T18:01:01.000000+00:00",
"customer_id": null,
"discount_type": "percentage",
"discount_percentage": 0.0,
"deposit_type": "percentage",
"deposit_value": 100.0,
"tags": [],
"tax_region_id": null,
"item_count": 0,
"coupon_id": null,
"tax_strategy": "exclusive",
"currency": "usd",
"shortage": false,
"location_shortage": false,
"payment_status": "Paid",
"start_location_id": "843df6b3-61fc-4f12-8b0b-62ab93d41e6e",
"stop_location_id": "843df6b3-61fc-4f12-8b0b-62ab93d41e6e",
"entirely_started": true,
"entirely_stopped": false,
"coupon_code": null,
"coupon_percentage": null,
"item_ids": [],
"stock_item_ids": [],
"invoice_count": 0,
"total_tax_in_cents": 0,
"price_with_tax_in_cents": 0,
"amount_as_decimal": "0.0",
"amount": "0.0",
"amount_paid_as_decimal": "0.0",
"amount_paid": "0.0",
"amount_to_be_paid_as_decimal": "0.0",
"amount_to_be_paid": "0.0",
"deposit_as_decimal": "0.0",
"deposit": "0.0",
"deposit_held_as_decimal": "0.0",
"deposit_held": "0.0",
"deposit_paid_as_decimal": "0.0",
"deposit_paid": "0.0",
"deposit_to_be_paid_as_decimal": "0.0",
"deposit_to_be_paid": "0.0",
"deposit_refunded_as_decimal": "0.0",
"deposit_refunded": "0.0",
"deposit_to_refund_as_decimal": "0.0",
"deposit_to_refund": "0.0",
"total_as_decimal": "0.0",
"total": "0.0",
"total_paid_as_decimal": "0.0",
"total_paid": "0.0",
"total_to_be_paid_as_decimal": "0.0",
"total_to_be_paid": "0.0",
"total_discount_as_decimal": "0.0",
"total_discount": "0.0",
"coupon_discount_as_decimal": "0.0",
"coupon_discount": "0.0",
"discount_as_decimal": "0.0",
"discount": "0.0",
"grand_total_as_decimal": "0.0",
"grand_total": "0.0",
"grand_total_with_tax_as_decimal": "0.0",
"grand_total_with_tax": "0.0",
"paid_as_decimal": "0.0",
"paid": "0.0",
"price_as_decimal": "0.0",
"price": "0.0",
"tax_as_decimal": "0.0",
"tax": "0.0",
"to_be_paid_as_decimal": "0.0",
"to_be_paid": "0.0",
"total_tax_as_decimal": "0.0",
"total_tax": "0.0",
"price_with_tax_as_decimal": "0.0",
"price_with_tax": "0.0",
"start_location": {
"id": "843df6b3-61fc-4f12-8b0b-62ab93d41e6e",
"updated_at": "2014-03-27T18:03:01.000000+00:00",
"created_at": "2014-03-27T18:03:01.000000+00:00",
"name": "Location 1000089",
"code": "LOC1000124",
"location_type": "rental",
"address": "",
"address_line_1": null,
"address_line_2": null,
"zipcode": null,
"city": null,
"region": null,
"country": null,
"archived_at": null
},
"stop_location": {
"id": "843df6b3-61fc-4f12-8b0b-62ab93d41e6e",
"updated_at": "2014-03-27T18:03:01.000000+00:00",
"created_at": "2014-03-27T18:03:01.000000+00:00",
"name": "Location 1000089",
"code": "LOC1000124",
"location_type": "rental",
"address": "",
"address_line_1": null,
"address_line_2": null,
"zipcode": null,
"city": null,
"region": null,
"country": null,
"archived_at": null
},
"plannings": [],
"notes": [],
"tax_values": [],
"lines": [],
"properties": []
}
}
},
"meta": {}
}
How to fetch a webhook (v4 format):
curl --get 'https://example.booqable.com/api/4/webhooks/eaa10d09-1e59-4ba6-8dfb-528b5574fcd6'
--header 'content-type: application/json'
A 200 status response looks like this:
{
"data": {
"id": "eaa10d09-1e59-4ba6-8dfb-528b5574fcd6",
"type": "webhooks",
"attributes": {
"created_at": "2018-06-25T17:38:00.000000+00:00",
"updated_at": "2018-06-25T17:38:00.000000+00:00",
"event": "order.created",
"version": 4,
"resource_type": "orders",
"data": {
"id": "8b32f593-809b-4c05-8607-487da64f4265",
"created_at": "2018-06-25T17:38:00.000000+00:00",
"updated_at": "2018-06-25T17:38:00.000000+00:00",
"number": null,
"status": "new",
"statuses": [
"new"
],
"status_counts": {
"new": 0,
"draft": 0,
"reserved": 0,
"started": 0,
"stopped": 0
},
"starts_at": "2018-06-23T17:36:00.000000+00:00",
"stops_at": "2018-06-27T17:36:00.000000+00:00",
"deposit_type": "percentage",
"deposit_value": 100.0,
"entirely_started": true,
"entirely_stopped": false,
"location_shortage": false,
"shortage": false,
"payment_status": "paid",
"override_period_restrictions": false,
"has_signed_contract": false,
"item_count": 0,
"tag_list": [],
"properties": {
"delivery_address": null,
"billing_address": null
},
"amount_in_cents": 0,
"amount_paid_in_cents": 0,
"amount_to_be_paid_in_cents": null,
"deposit_in_cents": 0,
"deposit_held_in_cents": 0,
"deposit_paid_in_cents": 0,
"deposit_to_be_paid_in_cents": null,
"deposit_refunded_in_cents": 0,
"deposit_to_refund_in_cents": 0,
"total_in_cents": 0,
"total_paid_in_cents": 0,
"total_to_be_paid_in_cents": 0,
"total_discount_in_cents": 0,
"coupon_discount_in_cents": 0,
"discount_in_cents": 0,
"grand_total_in_cents": 0,
"grand_total_with_tax_in_cents": 0,
"paid_in_cents": 0,
"price_in_cents": 0,
"tax_in_cents": 0,
"to_be_paid_in_cents": 0,
"discount_type": "percentage",
"discount_percentage": 0.0,
"billing_address_property_id": null,
"delivery_address_property_id": null,
"fulfillment_type": "pickup",
"delivery_address": null,
"customer_id": null,
"tax_region_id": null,
"coupon_id": null,
"start_location_id": "754c12e4-45d9-420e-8f44-22f3498076f3",
"stop_location_id": "754c12e4-45d9-420e-8f44-22f3498076f3",
"order_delivery_rate_id": null
}
}
},
"meta": {}
}
HTTP Request
GET /api/4/webhooks/{id}
Request params
This request accepts the following parameters:
| Name | Description |
|---|---|
fields[] |
array List of comma separated fields to include instead of the default fields. ?fields[webhooks]=created_at,updated_at,event |
Includes
This request does not accept any includes