Partner API
Reservation API for third-party integrations — check availability, book, cancel, change and look up reservations, regardless of the reservation system the restaurant runs.
Base URL
https://apointa.org/api/partner/v1All requests must use HTTPS.
Authentication
Every endpoint (except /health) requires a bearer token:
Authorization: Bearer apt_live_...You get exactly one API key per partner account. It covers every restaurant you added in your dashboard. Accessing a restaurant that is not enabled returns 403 FORBIDDEN.
Rate limits
60 requests per minute per API key across all endpoints. Exceeding the limit returns 429 Too Many Requests.
Tip: for voice AI, cache availability checks for the same (restaurantId, date, time, partySize) tuple.
Error handling
All errors are returned as JSON:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable description"
}
}| Code | Status | When |
|---|---|---|
| UNAUTHORIZED | 401 | API key missing or invalid |
| FORBIDDEN | 403 | Restaurant not enabled for this API key |
| VALIDATION_ERROR | 400 | Request body fails validation |
| NOT_FOUND | 404 | Restaurant or reservation not found |
| PROVIDER_ERROR | 502 | Upstream reservation system failed |
| RATE_LIMITED | 429 | Rate limit exceeded |
Endpoints
/healthLiveness probe. No authentication required.
Response
{ "status": "ok", "version": "1.0.0" }/check-availabilityChecks whether a given slot is available. No reservation is created.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
| restaurantId | string | yes | Restaurant ID — you find this in your dashboard |
| date | string | yes | YYYY-MM-DD (local date) |
| time | string | yes | HH:MM in 24-hour format (local time) |
| partySize | integer | yes | Number of guests (1-50) |
Request
{
"restaurantId": "35YDWSFbm7I",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4
}Response
{
"success": true,
"data": {
"available": true,
"closed": false,
"alternatives": ["19:00", "19:45", "20:00"]
}
}/bookCreates a real reservation. Every successful call is a binding booking — do not use it for testing. Only first name and phone number are required.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
| restaurantId | string | yes | Restaurant ID — you find this in your dashboard |
| date | string | yes | YYYY-MM-DD |
| time | string | yes | HH:MM |
| partySize | integer | yes | Number of guests (1-50) |
| customer.firstName | string | yes | Guest's first name |
| customer.lastName | string | no | Guest's last name. If omitted we book with a neutral placeholder. |
| customer.phone | string[] | yes | Guest's phone numbers as an array, primary number first |
| customer.email | string | no | Guest's email |
| specialRequests | string | no | Free-text note |
Request
{
"restaurantId": "35YDWSFbm7I",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4,
"customer": {
"firstName": "Max",
"lastName": "Mustermann",
"phone": ["+491701234567", "+4989123456"],
"email": "max@example.com"
},
"specialRequests": "Table by the window"
}Response
{
"success": true,
"data": {
"reservationId": "gn-a1b2c3d4",
"status": "confirmed",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4
}
}/cancelCancels a reservation. Either by reservationId or — if your system does not know it — by phone number, optionally narrowed down with date and time.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
| restaurantId | string | yes | Restaurant ID — you find this in your dashboard |
| reservationId | string | no | Id from the /book response. Alternatively look up by phone number. |
| phone | string[] | no | Guest's phone numbers as an array — alternative numbers are searched too. |
| date | string | no | Date of the reservation, narrows down multiple matches |
| time | string | no | Time of the reservation, narrows down multiple matches |
Request
{
"restaurantId": "35YDWSFbm7I",
"reservationId": "gn-a1b2c3d4"
}Response
{
"success": true,
"data": {
"reservationId": "gn-a1b2c3d4",
"status": "cancelled",
"date": "2026-08-15",
"time": "19:30"
}
}/updateRequests a change. The reservation is located the same way as in /cancel. The restaurant is notified and applies the change.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
| restaurantId | string | yes | Restaurant ID — you find this in your dashboard |
| reservationId | string | no | Id from the /book response. Alternatively look up by phone number. |
| phone | string[] | no | Guest's phone numbers as an array — alternative numbers are searched too. |
| date | string | no | Date of the reservation, narrows down multiple matches |
| time | string | no | Time of the reservation, narrows down multiple matches |
| updates.date | string | no | New date YYYY-MM-DD |
| updates.time | string | no | New time HH:MM |
| updates.partySize | integer | no | New party size |
| updates.specialRequests | string | no | New note |
Request
{
"restaurantId": "35YDWSFbm7I",
"phone": ["+491701234567"],
"date": "2026-08-15",
"time": "19:30",
"updates": {
"partySize": 6,
"specialRequests": "Guest with allergies"
}
}Response
{
"success": true,
"data": {
"reservationId": "gn-a1b2c3d4",
"status": "pending",
"message": "Update request forwarded to restaurant."
}
}/reservationsLooks up existing reservations by phone number. Only future reservations are returned.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
| restaurantId | string | yes | Restaurant ID — you find this in your dashboard |
| phone | string[] | yes | Guest's phone numbers as an array — alternative numbers are searched too. |
Request
{
"restaurantId": "35YDWSFbm7I",
"phone": ["+491701234567", "+4989123456"]
}Response
{
"success": true,
"data": {
"reservations": [
{
"reservationId": "gn-a1b2c3d4",
"date": "2026-08-15",
"time": "19:30",
"partySize": 4,
"specialRequests": "Table by the window"
}
]
}
}Important: only reservations from this system
The API only sees reservations that were created through this system. If the guest booked by phone, on the restaurant's website or through any other channel, it is invisible to /reservations, /update and /cancel.
In that case /cancel and /update respond with 404 NOT_FOUND. At the same time we automatically notify the restaurant by email with everything you sent us.
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "No reservation found that was created through this API. The restaurant staff has been notified and will handle the cancellation."
}
}Catch this case in your system and tell the caller that a staff member has been notified and will take care of it — that is exactly what happens in the background.
Phone number format
Always send the country code in E.164 format:
+491701234567(Germany)+436641234567(Austria)+41791234567(Switzerland)
Phone numbers are always passed as an array. If your system knows a second number of the guest, send it along — we search all of them.
Support
Contact the Apointa team with: request timestamp (UTC), restaurantId, full request body (redact personal data), HTTP status and response body.
