API de horario de apertura
Obtén el horario de apertura resuelto y los próximos festivos para un sitio web
Última actualización el
Usa la API de horario de apertura resuelto si muestras en un sitio público horarios de temporada (por ejemplo Zomer / Winter) o los próximos festivos. Tillor ya aplica las excepciones, los periodos de temporada y el horario semanal normal, y añade los festivos legales dentro del rango solicitado. No necesitas volver a implementarlo.
Permiso: organization:settings:read u organization:settings:write
La clave de API se queda en el servidor
Llama a Tillor solo desde un servidor (Route Handler de Next.js, Server Component o backend). Guarda la clave en variables de entorno. No la envíes nunca al navegador.
Autenticación: consulta la API HTTP. Prueba el endpoint en la referencia de la API o mediante OpenAPI (etiqueta organization-settings).
Endpoint
GET https://tillor.eu/api/orgs/org_abc123/organization-settings/opening-hoursEncabezados:
x-api-key: tkn_xxxSustituye org_abc123 por el ID de tu organización.
Parámetros de consulta
Usa date o from/to. No los combines.
| Parámetro | Significado |
|---|---|
| (ninguno) | Hoy, en la zona horaria de la organización |
date | Un solo día natural (YYYY-MM-DD) |
from | Día de inicio (incluido). Sin to: solo ese día |
to | Día final (incluido). Requiere from. Máximo 366 días |
languageIsoCode | Idioma de los nombres de los festivos (NL, FR, …). Por defecto: el idioma de la organización |
Respuesta
Cada elemento es un día natural, ya resuelto:
| Campo | Significado |
|---|---|
timeZone | Zona horaria IANA de la organización |
from / to | Rango solicitado |
holidays | Festivos legales que se solapan con from–to |
items[].date | Día natural YYYY-MM-DD |
items[].weekday | monday … sunday |
items[].source | exception, period o regular |
items[].periodLabel | Solo con source: "period": la etiqueta de Tillor, por ejemplo "Zomer" o "Winter" |
items[].holiday | Solo si ese día es un festivo legal: { id, name, startDate, endDate } |
items[].blocks | Franjas horarias en minutos desde la medianoche |
items[].closed | true si blocks está vacío |
Prioridad: excepción (festivo o rango personalizado) → último periodo de temporada que coincida → horario semanal normal.
Las etiquetas de temporada provienen de Configuración > Horario de apertura. Los periodos pueden cruzar el cambio de año (por ejemplo del 1 de noviembre al 31 de marzo). Los días fuera de todo periodo recurren al horario semanal normal (source: "regular", sin periodLabel).
De minutos a hora del reloj
startMinutes / endMinutes son minutos desde las 00:00.
| Minutos | Hora |
|---|---|
| 540 | 09:00 |
| 600 | 10:00 |
| 720 | 12:00 |
| 780 | 13:00 |
| 1020 | 17:00 |
| 1140 | 19:00 |
function formatMinutes(minutes: number): string {
const hour = Math.floor(minutes / 60);
const minute = minutes % 60;
return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
}Ejemplos
Día dentro de un periodo de temporada
curl -X GET "https://tillor.eu/api/orgs/org_abc123/organization-settings/opening-hours?date=2026-07-15" \
-H "x-api-key: tkn_xxx"{
"timeZone": "Europe/Brussels",
"from": "2026-07-15",
"to": "2026-07-15",
"holidays": [],
"items": [
{
"date": "2026-07-15",
"weekday": "wednesday",
"source": "period",
"periodLabel": "Zomer",
"blocks": [{ "startMinutes": 540, "endMinutes": 720 }],
"closed": false
}
]
}09:00–12:00, horario de verano.
Día fuera de los periodos de temporada
curl -X GET "https://tillor.eu/api/orgs/org_abc123/organization-settings/opening-hours?date=2026-01-15" \
-H "x-api-key: tkn_xxx"{
"timeZone": "Europe/Brussels",
"from": "2026-01-15",
"to": "2026-01-15",
"holidays": [],
"items": [
{
"date": "2026-01-15",
"weekday": "thursday",
"source": "regular",
"blocks": [
{ "startMinutes": 540, "endMinutes": 720 },
{ "startMinutes": 780, "endMinutes": 1020 }
],
"closed": false
}
]
}09:00–12:00 y 13:00–17:00.
Rango que cruza el límite de un periodo
curl -X GET "https://tillor.eu/api/orgs/org_abc123/organization-settings/opening-hours?from=2026-03-30&to=2026-04-02" \
-H "x-api-key: tkn_xxx"| Fecha | source | periodLabel |
|---|---|---|
| 2026-03-30 | regular | - |
| 2026-03-31 | regular | - |
| 2026-04-01 | period | Zomer |
| 2026-04-02 | period | Zomer |
Próximos festivos
Los festivos legales vienen en la misma respuesta: holidays para una lista (nombre + fechas), items[].holiday si ese día natural es festivo. Las horas siguen siendo el horario resuelto; un festivo sin excepción rellenada en Tillor sigue el horario de temporada o el semanal (source no es entonces "exception").
curl -X GET "https://tillor.eu/api/orgs/org_abc123/organization-settings/opening-hours?from=2026-08-27&to=2026-12-31&languageIsoCode=NL" \
-H "x-api-key: tkn_xxx"{
"timeZone": "Europe/Brussels",
"from": "2026-08-27",
"to": "2026-12-31",
"holidays": [
{
"id": "0fad0035-6b77-404a-953d-c66dac014483",
"name": "Allerheiligen",
"startDate": "2026-11-01",
"endDate": "2026-11-01"
},
{
"id": "d90e5f53-bc92-4860-bdae-f7e75935848d",
"name": "Kerstmis",
"startDate": "2026-12-25",
"endDate": "2026-12-25"
}
],
"items": [
{
"date": "2026-11-01",
"weekday": "sunday",
"source": "regular",
"holiday": {
"id": "0fad0035-6b77-404a-953d-c66dac014483",
"name": "Allerheiligen",
"startDate": "2026-11-01",
"endDate": "2026-11-01"
},
"blocks": [],
"closed": true
}
]
}El ejemplo de items anterior está abreviado; la respuesta real contiene cada día del rango. Las vacaciones escolares no están en este endpoint; siguen siendo GET /holidays?kind=school.
Next.js (servidor)
Para un widget semanal o un “abierto ahora” en un sitio público:
const TILLOR_API_URL = "https://tillor.eu";
const ORGANIZATION_ID = process.env.TILLOR_ORG_ID ?? "";
type OpeningHoursBlock = {
startMinutes: number;
endMinutes: number;
};
type OpeningHoursHoliday = {
id: string;
name: string;
startDate: string;
endDate: string;
};
type OpeningHoursItem = {
date: string;
weekday: string;
source: "exception" | "period" | "regular";
periodLabel?: string;
holiday?: OpeningHoursHoliday;
blocks: OpeningHoursBlock[];
closed: boolean;
};
type OpeningHoursResponse = {
timeZone: string;
from: string;
to: string;
holidays: OpeningHoursHoliday[];
items: OpeningHoursItem[];
};
export async function getOpeningHours(
from: string,
to: string,
): Promise<OpeningHoursResponse> {
const url = new URL(
`${TILLOR_API_URL}/api/orgs/${ORGANIZATION_ID}/organization-settings/opening-hours`,
);
url.searchParams.set("from", from);
url.searchParams.set("to", to);
url.searchParams.set("languageIsoCode", "NL");
const response = await fetch(url, {
headers: {
"x-api-key": process.env.TILLOR_API_KEY ?? "",
},
next: { tags: ["opening-hours"], revalidate: 3600 },
});
if (!response.ok) {
throw new Error(`Tillor opening hours ${response.status}`);
}
return response.json() as Promise<OpeningHoursResponse>;
}holidays es la lista para un bloque de “próximos festivos”. items[].holiday es útil en un calendario semanal. items[].periodLabel es el texto de temporada (por ejemplo "Zomer" o "Winter"). Una caché de 1 hora suele bastar.
Invalidar la caché (webhook)
En cada cambio de los ajustes de la organización, Tillor envía organizationSettings:updated (webhook y SSE). Suscríbete a él y vuelve a obtener el horario de apertura. El payload es pequeño a propósito (sin IP de impresoras ni el horario completo):
{
"event": "organizationSettings:updated",
"data": {
"openingHoursChanged": true
},
"timestamp": 1787829600000
}openingHoursChanged es true si cambia el horario de apertura, la zona horaria o el país por defecto, que es lo que afecta a GET .../opening-hours. Con false puedes dejar la caché del horario de apertura como está.
Ejemplo de Route Handler de Next.js:
import { revalidateTag } from "next/cache";
export async function POST(request: Request) {
const body = (await request.json()) as {
event?: string;
data?: { openingHoursChanged?: boolean };
};
if (body.event === "organizationSettings:updated" && body.data?.openingHoursChanged) {
await revalidateTag("opening-hours");
}
return new Response(null, { status: 204 });
}Crear un webhook: consulta Webhooks. Clave de evento: organizationSettings:updated (permiso organization:settings:read u organization:settings:write).
Horario completo (opcional)
Solo es necesario si quieres mostrar tú mismo el calendario de temporadas (etiquetas + fromMonth/untilDay), sin resolverlo por día:
GET https://tillor.eu/api/orgs/org_abc123/organization-settingsLee openingHoursSchedule.periods (etiquetas como "Zomer") y openingHoursSchedule.weekdays (horario normal). Para el propio sitio web, GET .../opening-hours sigue siendo la fuente más sencilla.
MCP
En Cursor o Claude: endpoint organizationSettings_listOpeningHours (categoría organizationSettings), argumentos organizationId, opcionalmente date o from/to, opcionalmente languageIsoCode.
Relacionado
- API HTTP - autenticación y encabezados
- Ejemplos HTTP - ejemplos generales de cURL
- Webhooks -
organizationSettings:updatedpara revalidar la caché - Ajustes de la organización - configurar el horario de apertura en Tillor