For developers

Calendar API

How to read a studio's appointments from another system —a reminder service, an automation— and how to subscribe to its calendar.

What this is

A studio that uses Hive can let another system read its calendar. That's what you need, for example, to send a member a reminder of their appointment from an outside service.

Everything is read-only. There's no way to book, move, cancel or confirm an appointment from here. And no health data about the member is sent: what's left out.

The studio decides whether to open its calendar, and can close it whenever it wants. If you stop getting responses, the first thing to ask them is whether they revoked the key.

How to get the key

The studio generates it, not us. An administrator goes to Settings → Integrations, creates a key for "an external service" and copies it with a button.

It's best to use one key per provider: that way the studio can cut one off without leaving the others without service. And treat it like a password — whoever has it can see that calendar.

Querying appointments

curl -H "Authorization: Bearer YOUR_KEY" \
  "https://hivegyms.com/api/v1/appointments?desde=2026-08-26&hasta=2026-09-02"

Without the header, or with an invalid or revoked key, it responds 401.

Parameters

Parameter What it does
desde
hasta
Date range (YYYY-MM-DD). Maximum 62 days per query. Without them: today and the next seven days. For a single day, use the same date in both.
sucursal_id Only that branch's appointments. The IDs are listed in the response's sucursales.
actualizadas_desde ISO 8601 timestamp. Returns only what changed since then — the cheap way to ask "what changed?" instead of sweeping the whole calendar every time.
cursor Next page. It comes in siguiente_cursor.
limite Appointments per page. Maximum 500, default 200.

The response

{
  "ok": true,
  "desde": "2026-08-26",
  "hasta": "2026-09-02",
  "zona": "America/Bogota",
  "sucursales": [
    { "id": 3, "nombre": "Sede Norte" },
    { "id": 4, "nombre": "Sede Sur" }
  ],
  "siguiente_cursor": null,
  "citas": [
    {
      "id": 4821,
      "fecha": "2026-08-27",
      "hora": "10:00",
      "duracion_minutos": 30,
      "inicio": "2026-08-27T10:00:00-05:00",
      "zona": "America/Bogota",
      "estado": "confirmada",
      "recordatorio": "ninguno",
      "sucursal": { "id": 3, "nombre": "Sede Norte" },
      "coach": { "id": 12, "nombre": "Coach Forero" },
      "socio": {
        "id": 990,
        "nombre": "Juan Pérez",
        "telefono": "+57 3001112233",
        "email": "[email protected]",
        "acepta_whatsapp": true
      },
      "actualizada_en": "2026-08-26T09:12:44Z"
    }
  ]
}

The time: use inicio

This is the easiest mistake to make here. fecha and hora are the studio's wall-clock time: "10:00" means ten o'clock at the studio, with no time zone. inicio is that same moment with the branch's real offset, and it's the only field you should calculate "24 hours before" against. If you subtract from the bare time, reminders go out at the wrong time.

That's why zona comes per appointment and not per studio: a chain can have branches in different time zones, and Tijuana and Mexico City are two hours apart.

Studios with multiple branches

Every response includes sucursales with the branches that key can reach, and each appointment says which one it belongs to. There are two ways to work, depending on how the studio created it:

One key for the whole studio

The usual case. Appointments from all branches come together, each with its sucursal. If you only care about one, filter with sucursal_id.

One key per branch

The studio restricts it when creating it, and that key can't see the others no matter how you ask.

Asking for a sucursal_id the key can't reach responds 422 with the reason, not an empty list — so "there are no appointments" isn't confused with "I don't have access".

Fields that may be empty

coach is null for appointments booked without an assigned professional (it happens at the front desk, it's normal). telefono and email are null when the studio doesn't have them on file.

It's worth counting them before promising coverage: the number of appointments isn't the number of reminders that can be sent.

acepta_whatsapp

Says whether someone explicitly marked on the member profile that they accept WhatsApp messages. It's informational, not an instruction. Today most have it set to false simply because nobody has gone and marked it, not because they refused: the real consent is held by the studio in its privacy notice, signed when the record was opened.

The studio decides who gets messaged, and it's an agreement between the studio and its provider. If the rule is "only those who opted in", this field is useful for filtering; if it's "everyone who left a phone number" —which is what Hive's own WhatsApp does— the field is ignored.

Appointment statuses

programada · confirmada · llego · en_silla · en_procedimiento · checkout · completada · cancelada · no_asistio · reagendar

Cancelled ones do appear: knowing an appointment fell through is often half the reason to query. What never appears are schedule blocks (lunches, meetings) or appointments deleted by mistake.

recordatorio is the status of the reminder Hive sends over WhatsApp (ninguno, enviado, entregado, fallido). If a third party sends the reminders, that field stays at ninguno.

Limits and errors

60 requests per minute per key.

Code When
401Missing, invalid or revoked key.
422Malformed dates, a range longer than 62 days, or a branch the key can't reach.
429More than 60 requests in a minute.

All of them respond { "ok": false, "error": "…" } with the reason as text.

Calendar feed

To see the calendar in Google Calendar, on an iPhone or in Outlook you don't need to code anything: in Settings → Integrations the studio generates an address that you paste into the calendar as "subscribe by URL".

Google Calendar decides on its own how often to check again, and it usually takes between 8 and 24 hours. There's no way to speed it up. It's good for seeing the week; to react to a last-minute change you need to use the API.

It covers from 30 days back to 180 days ahead, without cancelled appointments (so the slot clears from the calendar by itself), and each event carries only the member's name, the coach and the branch.

What it does NOT return, and it's not an oversight

No progress notes, no reason for the visit written on the appointment, no services, plans, quotes, balances, allergies or health history. That's health data, the studio answers for it, and none of it is needed to remind a member of their appointment.

There's also no way to write: no booking, moving, cancelling or confirming. If a workflow needs it, let's talk — it's left out on purpose, not for lack of time.