(Revised 2024-11-23)
Parkingsadmin.com is a SaaS for parkings that manages parking bookings and integrates all the booking channels of a parking in one place. It helps to manage the availability, checkin, reporting and invoicing.
This API is ready for the distribution channels that sell bookings in the name of the parking. Every parking activates a channel in our system to distribute the product and then the Channel is authorized to make reservations through this system. Parkings can also connect to this API to access and manage their bookings.
This API is a REST API that speaks JSON. It will always return JSON (unless otherwise stated) and it assumes that information is sent as JSON BODY when possible, besides the query string parameters, of course.
You should include an Accept
header including the content type and the version like this:
Accept: application/json; version=1
Fields that finish in _at
are in UTC time. Fields that finish in _date
or _time
are in the timezone of the parking. The timezone of the parking is provided in the /parkings
endpoint.
All request must include a User-Agent information including the platform and (separated by a space) the client version (not the OS version) that is making the request, for instance:
User-Agent: "channels/ChannelCode 1.0.1"
User-Agent: "parkings/ParkingCode 1.0.1"
You will be provided with the left part of the user agent by us.
Most entry points require authentication. To authenticate your request you must use the "Authorization" HTTP header using as value the token provided by us to every channel or parking operator and prefixing it with the string "Bearer "
Authorization: "Bearer 1234567890abcdef1234567890abcdef"
The API returns errors using the standard HTTP response codes (see http://www.restapitutorial.com/httpstatuscodes.html). The error also has a JSON response including the code and a message.
You can use our test server as sandbox with another token that will be provided to you.
The following table shows the location of each endpoint:
Server | URL |
---|---|
Sandbox | https://api-sandbox.parkingsadmin.com |
Production | https://api.parkingsadmin.com |
Entity | Verb | Auth | Action |
---|---|---|---|
/parkings | GET | Channel,Parking,User | Get the list of parkings |
/bookings | GET | Channel,Parking,User | List of bookings |
/bookings | POST | Channel,Parking,User | Create a new Booking |
/bookings/{id} | GET | Channel,Parking,User | View a Booking |
/bookings/{id} | PUT | Channel,Parking,User | Modify a Booking |
/bookings/{id} | DELETE | Channel,Parking,User | Cancel a Booking |
/bookings-available | GET | Channel,Parking,User | Check availability and price |
BEFORE creating a booking, the channel SHOULD check the availability for that parking and dates.
If you try to create a booking and there is no availability you will get a 409
error anyways.
1) GET /parkings
to know our parking ID for the parking that you have permissions.
2) GET /bookings-available
to check availability (and price) for specific dates.
3) POST /bookings
to create the booking.
4) PUT /bookings/{id}
to modify a booking.
5) DELETE /bookings/{id}
to cancel a booking.
This collection only accepts GET verb to request the list of authorized parkings for the token and their IDs which you will need in the POST /bookings
phase.
per_page
(integer) - Number of results per page. Default is 20
max is 1000
.Possible HTTP status codes:
Code | Description |
---|---|
200 | OK |
400 | Bad request |
401 | Unauthorized, f.i. No token was provided |
403 | Forbidden, f.i. This token has no permission at this parking |
{
"data":
[
{
"id": 1,
"name": "Example Parking in Madrid",
"city": "Madrid",
"country": {
"code": "ES",
"name": "Italia"
},
"timezone": "Europe/Madrid",
"currency": "EUR",
"vat_percentage": 21,
"required_fields": []
},
{
"id": 2,
"parkingName": "Example Parking in Rome",
"city": "Rome",
"country": {
"code": "IT",
"name": "Italia"
},
"timezone": "Europe/Rome",
"currency": "EUR",
"vat_percentage": 22,
"required_fields": [
"vehicle_plate"
]
}
]
}
Be careful with timezones and DTS changing dates because sometimes a booking from 8AM today to 8AM tomorrow can be a 23, 24 or 25 hours booking and most parkings calculate their rates using 24-hour schemas. The dates and times must be in the timezone of the parking.
The response will be an array including a json object for each requested parking (given that the parking id exists and the channel has permissions to access it). If the places_available
attribute is >= 1, then there is availability for a booking.
parking_id
(integer) - REQUIRED ID of the Parking. You can pass up to 10
IDs separated by comma.arrival_date
(ISO 8601 date YYYY-MM-DD
) - REQUIRED Date of arrival (at parking timezone), f.i. 2025-06-28
. Parkings normally don't admit bookings more than 365 days in advance. But some parkings can have different policies.arrival_time
(ISO 8601 time hh:mm
) - REQUIRED Hour of arrival in 24 hours format (at parking timezone), f.i. 07:00
for 7AM.departure_date
(ISO 8601 date YYYY-MM-DD
) - REQUIRED Date of departure (at parking timezone), f.i. 2025-06-31
. Parkings normally don't admit bookings of more than 31 days.departure_time
(ISO 8601 time hh:mm
) - REQUIRED Hour of departure in 24 hours format (at parking timezone), f.i. 18:00
for 6PM.price
attribute. If price is null
you should ignore it and use the rates provided by the parking.available
is a boolean: you MUST NOT try to book in a parking that has "available": false
.available_places
can be an integer, displaying the number of available places left for reservations for that period, but can also be null
if the parking does not provide this information. This is only informative, and you should not rely on it to make a booking, but it can be interesting to display to your customers in order to rush them to make a reservation if few places are left.
available_reason
is a string that explains why the parking is not available. If available
is true
, this field will always be null
, but in many cases, even if available
is true
, this field can be null
too: not all unavailable responses have an explanation: if the value is null it means that the parking does not have more available spaces. For instance, if the parking only accepts reservations for 31 days or less, it will show a message here.product_code
and product_name
are the code and name of the product that the parking is offering. If product_code
is null
, you can ignore it, but if it is not null, you MUST use this code to make the booking in the POST
request. Same with product_name
: you MUST ignore if null
, but if not, you must send them on the POST
request. You can display product_name
to the user if you wish. These fields are only used when the parking has dynamic pricing, or it uses a third party integration that we interact with and requires them.Possible HTTP status codes:
Code | Description |
---|---|
200 | OK |
400 | Bad request, f.i. too many parking ids, etc |
401 | Unauthorized, f.i. No token was provided |
403 | Forbidden, f.i. This token has no permission at this parking |
404 | Not found, f.i. Parking not found |
{
"availability": [
{
"parking_id": 1,
"available": true,
"available_places": null,
"available_reason": null,
"price": null,
"product_code": null,
"product_name": null
},
{
"parking_id": 3,
"available": false,
"available_places": null,
"available_reason": "This parking only accepts reservations for 31 days or less.",
"price": null,
"product_code": null,
"product_name": null
}
]
}
In this case, parking #2 has dynamic pricing:
{
"availability": [
{
"parking_id": 2,
"available": true,
"available_places": 30,
"available_reason": null,
"price": 10.50,
"product_code": "ONEDAY",
"product_name": "One day multipass"
},
{
"parking_id": 1,
"available": true,
"available_places": null,
"available_reason": null,
"price": null,
"product_code": null,
"product_name": null
}
]
}
If no parameters added, it will display all the future bookings that the user has access to. If you want to filter by arrival date, you can use the arrival_date_from
and arrival_date_to
parameters. If you want to filter by booking code, you can use the booking_code
parameter. You can also filter by parking_id
, specifying up to 10 parking IDs separated by comma.
OPTIONAL Parameters
arrival_date_from
(string) - Default: today
. Minimum date of arrival (format yyyy-mm-dd
) of the bookings to display.arrival_date_to
(string) - Maximum date of arrival (format yyyy-mm-dd
) of the bookings to display.booking_code
(string) - Booking code to search. Will compare the exact string.parking_id
(integer) - Parking ID. You can pass up to 10
IDs separated by comma.per_page
(integer) - Number of results per page. Default is 20
max is 1000
.Possible HTTP status codes:
Code | Description |
---|---|
200 | OK |
400 | Bad request |
401 | Unauthorized, f.i. No token was provided |
403 | Forbidden, f.i. This token has not permissions for this call |
{
"data": [
{
"id": 123456,
"parking_id": 1,
"created_at": "2021-06-15T18:46:06Z",
"arrival_at": "2022-05-30T07:30:00Z",
"departure_at": "2022-05-30T10:30:00Z",
"checkin_at": null,
"checkout_at": null,
"canceled_at": null,
"rejected_at": null,
"prepaid": true,
"price": 8.9,
"source": "api",
"qr_code": null,
"channel_id": 13,
"channel_booking_code": "ID12345",
"channel_margin": 50,
"product_name": "Basic pass",
"customer_name": "John Doe",
"customer_email": null,
"customer_phone": "+16549879651",
"customer_language_code": null,
"customer_country_code": null,
"room": null,
"vehicle_type": "car",
"vehicle_plate": "6655ABC",
"vehicle_model": "Ford Focus",
"vehicle_color": "Pink",
"transportation_passengers": null,
"transportation_type": null,
"transportation_departure_time": null,
"transportation_departure_terminal": null,
"transportation_departure_number": null,
"transportation_arrival_time": null,
"transportation_arrival_terminal": null,
"transportation_arrival_number": null,
"special_requests": null,
"canceled": false,
"arrival_date": "2022-05-30",
"arrival_time": "09:30",
"departure_date": "2022-05-30",
"departure_time": "12:30"
}
],
"links": {
"first": "https://api.parkingsadmin.com/bookings?page=1",
"last": "https://api.parkingsadmin.com/bookings?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "https://api.parkingsadmin.com/bookings",
"per_page": 20,
"to": 15,
"total": 15
}
}
Possible HTTP status codes:
Code | Description |
---|---|
201 | Created (OK!) |
400 | Bad request, f.i. wrong phone number, missing field, etc |
401 | Unauthorized, f.i. No token was provided |
403 | Forbidden, f.i. This token has no permission at this parking |
404 | Not found, f.i. Parking not found |
409 | Conflict, f.i. No places available |
All strings are 255 characters max unless the contrary is specified. Floats must use dot (.
) as decimals separator, not comma (,
). Please never use thousands separator.
Although some fields are not required, please provide them if you have them. For instance, if you know the vehicle color or the product name, please provide them. Everything that you would send a parking via e-mail, please send it via API. It helps the parking.
REQUIRED Parameters
parking_id
(integer) - ID of the Parking (check /parkings
if you don't know it).booking_code
(string, 128) - REQUIRED The channel's booking ID. Can be letters and numbers up to 128 characters. It is STRONGLY recommended being less than 16 characters. Otherwise, the parking will see this field reduced to the last 16 characters in the listings. This field is UNIQUE for the channel. If you send the same booking code twice, the API will return a 409 Conflict
error.vehicle_type
(string) - REQUIRED possible values: car
, motorcycle
, van
, caravan
, bus
, truck
(other types can be added in the future).price
(float) - REQUIRED Total price including taxes. This price is the parking price. It is the one that was charged to the customer and the one that will be used for the settlements. In case that the channel adds Management fees or similar over the price amounts that are not settled with the Parking Operator, these fees SHOULD NOT be included in this price. Maximum 2 decimals.arrival_date
(string, ISO 8601 date YYYY-MM-DD) - Date of arrival (at parking timezone), f.i. 2025-06-28
.arrival_time
(string, ISO 8601 time hh:mm ) - Hour of arrival in 24 hours format (at parking timezone), f.i. 07:00
for 7AM. It is MANDATORY to match this regexp ^(:?[0-1][0-9]|2[0-3]):[0-5][0-9]$
.departure_date
(string, ISO 8601 date YYYY-MM-DD) - Date of departure (at parking timezone), f.i. 2025-06-31
.departure_time
(string, ISO 8601 time hh:mm) - Hour of departure in 24 hours format (at parking timezone), f.i. 18:00
for 6PM. It is MANDATORY to match this regexp ^(:?[0-1][0-9]|2[0-3]):[0-5][0-9]$
.customer_name
(string, 255) - Name and surname of the driver as he/she wants to be addressed. Max. 255 chars.customer_phone
(string, 14) - Driver phone. With international prefix and no spaces (f.i. +34999888777
, regex: ^\+?[0-9]{1,14}$
)MAYBE REQUIRED by some parkings (check /parkings
to know the required fields) Max 14 characters.
vehicle_plate
(string, 255) the license plate of the vehicle, no spaces (f.i. 8744FFH
). Max 255 characters.vehicle_model
(string, 255) the brand and model of vehicle (f.i. BMW x5
). Max 255 characters.vehicle_color
(string, 255) the main color of the vehicle, in the parking language or English (f.i. Blue
). Max 255 characters.passengers
(integer, between 1 and 8) must be a dropdown with options from 1 to 8, numbers.transportation_departure_time
and transportation_arrival_time
(string, ISO 8601 time hh:mm) must be a hour in this format: 23:59
. It is MANDATORY to match this regexp ^(:?[0-1][0-9]|2[0-3]):[0-5][0-9]$
. To avoid problems, just show the user a dropdown with all hours in the day with 15 minutes intervals.transportation_departure_terminal
and transportation_arrival_terminal
(string, 255) is MANDATORY to match with this regexp: ^[a-zA-Z0-9._%\+-]{1,255}$
. Max 255 characters.transportation_departure_number
and transportation_arrival_number
(string, 8) are the flight numbers or vessel names. For flights, it is MANDATORY to match with this regexp: ^[A-Z0-9]{1,8}$
.product_code
(string, 255) - Code of the product specified by the parking. It is mandatory if the parking uses availability and price and the availability response includes a product_code
field. It can also be mandatory if specified by the parking manually.OPTIONAL fields
prepaid
(boolean) - true if the booking has already been paid, note that most parkings only allow prepaid reservations. OPTIONAL: True by default.margin
(float, two decimal positions max) - Margin percentage for the channel. Maximum 2 decimals. OPTIONAL: the default margin defined by the parking will be used if none is set. For instance 10,25% is represented like the decimal 10.25
room
(string, 10) - For hotels, room of the customer that is booking (max 10 characters).product_name
(string, 255) - Name of the product that corresponds to the booking.customer_email
(string, 255) - Driver email, please check the syntax before sending. Max 255 characters.customer_language_code
(string, 2) - specify the language, use the ISO 639-1 two-letter code that applies in the standard (lowercase). f.i. es
for Spanishcustomer_country_code
(string, 2) - Two-letter (uppercase) country code defined in ISO 3166-1. f.i. ES
for Spainspecial_requests
(string) Max 255 characters.Minimum Request (application/json)
{
"parking_id": "2",
"booking_code": "123456",
"price": 19.55,
"arrival_date": "2025-06-29",
"arrival_time": "10:00",
"departure_date": "2025-06-30",
"departure_time": "10:00",
"customer_name": "John Doe",
"customer_phone": "+34999888777",
"vehicle_type": "car"
}
{
"parking_id": "2",
"booking_code": "A23EF61234",
"margin": 15,
"price": 19.55,
"product_name": "1 day multipass",
"prepaid": true,
"arrival_date": "2025-06-29",
"arrival_time": "10:00",
"departure_date": "2025-06-30",
"departure_time": "10:00",
"customer_name": "John Doe",
"customer_phone": "+34999888777",
"customer_email": "[email protected]",
"customer_language_code": "es",
"customer_country_code": "ES",
"passengers": 4,
"vehicle_type": "car",
"vehicle_plate": "0000EEE",
"vehicle_model": "Audi Q3",
"vehicle_color": "White",
"transportation_departure_time": "13:00",
"transportation_departure_terminal": "2",
"transportation_departure_number": "IB8876",
"transportation_arrival_time": "16:00",
"transportation_arrival_terminal": "2",
"transportation_arrival_number": "IB8867",
"special_requests": "One of the passengers is a RMP."
}
{
"id": "6542",
"parking_id": "2",
"created_at": "2020-12-28 19:00:00",
"arrival_at": "2020-12-29 19:00:00",
"departure_at": "2020-12-23 19:00:00",
"canceled_at": null,
"rejected_at": null,
"prepaid": true,
"price": 19.55,
"source": "email",
"qr_code": null,
"channel_id": 13,
"channel_booking_code": "A23EF61234",
"channel_margin": 15,
"product_name": "1 day multipass",
"customer_name": "John Doe",
"customer_phone": "+34999888777",
"customer_email": "[email protected]",
"customer_language_code": "es",
"customer_country_code": "ES",
"room": "404",
"vehicle_type": "car",
"vehicle_plate": "0000EEE",
"vehicle_model": "Audi Q3",
"vehicle_color": "White",
"transportation_passengers": 4,
"transportation_type": null,
"transportation_departure_time": "13:00:00",
"transportation_departure_terminal": "2",
"transportation_departure_number": "IB8876",
"transportation_arrival_time": "16:00_00",
"transportation_arrival_terminal": "2",
"transportation_arrival_number": "IB8867",
"special_requests": "One of the passengers is a RMP."
}
Works the same way as the POST, please don't include the fields: id
, created_at
, canceled_at
and canceled
.
Possible HTTP status codes:
Code | Description |
---|---|
200 | OK. Will return the object with the canceled_at not null |
400 | Bad request, f.i. wrong phone number, missing field, etc |
401 | Unauthorized, f.i. No token was provided |
403 | Forbidden, f.i. This token has no permission for the booking |
404 | Not found, f.i. Booking not found |
409 | Conflict, f.i. Time restricted |
No parameters are needed, just DELETE /bookings/{id}
and if the time constraint check (some parkings won't allow cancelling when the booking arrival is past), the API will return the booking object with a 200 OK
HTTP status code (meaning everything went all right). You will be able to check that canceled_at
attribute will be set to the time of the cancellation.
If a 409 Conflict
status code is returned it means that the booking is not in a correct status (it might have been already canceled, or it cannot be canceled) or the time limits are not being respected and that booking is not allowed to be canceled. Check the message for details.
If the status is 403 Not allowed
means that the client is not correctly authenticated or is trying to cancel a booking that does not belong to him.
The api can return other errors (50x when is a problem in the server). But, as always when the API returns an error it also returns a message
field with a message that specifies the details of the problem.
For parameters defined as string
, empty strings or strings containing only whitespaces are not accepted. If the parameter is not required, simply omit it in these cases.