> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ontime.hosai.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Developer overview

> The three programmatic surfaces OnTime exposes — REST API, webhooks and MCP — and a first request in under five minutes.

OnTime exposes three ways to work with it programmatically.

<CardGroup cols={3}>
  <Card title="Public REST API" icon="code">
    Key-authenticated, read-only. Pull employees and attendance into your own systems.
  </Card>

  <Card title="Webhooks" icon="webhook">
    Outbound, HMAC-signed. OnTime posts to you when something happens.
  </Card>

  <Card title="MCP server" icon="bot">
    Lets an AI agent operate OnTime as a specific employee. See the **AI & MCP** tab.
  </Card>
</CardGroup>

## Base URL

```text theme={null}
https://app.ontime.hosai.app
```

## Two API surfaces, one host

<Warning>
  **Only `/api/public/v1/*` is a supported integration surface.**

  The rest of `/api/*` is what the OnTime web and mobile apps call. It is documented in the API Reference for completeness, it authenticates with a **session cookie** rather than an API key, and it may change without notice. Build against `/api/public/v1/*`.
</Warning>

| Surface                        | Auth           | Stability                                     |
| ------------------------------ | -------------- | --------------------------------------------- |
| `/api/public/v1/*`             | API key        | Versioned. Additive changes only within `v1`. |
| Everything else under `/api/*` | Session cookie | Internal. Subject to change without notice.   |

## Your first request

<Steps>
  <Step title="Issue a key">
    In the admin console, **API & webhooks → Issue key**. You need the `api:manage` permission.

    <Warning>
      The key is displayed **once**. OnTime stores only a hash — there is no way to retrieve it later.
    </Warning>
  </Step>

  <Step title="Call the API">
    <CodeGroup>
      ```bash curl theme={null}
      curl https://app.ontime.hosai.app/api/public/v1/employees \
        -H "Authorization: Bearer ont_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8"
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch(
        "https://app.ontime.hosai.app/api/public/v1/employees",
        { headers: { Authorization: `Bearer ${process.env.ONTIME_API_KEY}` } },
      );
      if (!res.ok) throw new Error(`OnTime ${res.status}: ${await res.text()}`);
      const { meta, data } = await res.json();
      console.log(`${meta.count} employees`);
      ```

      ```python Python theme={null}
      import os, requests

      res = requests.get(
          "https://app.ontime.hosai.app/api/public/v1/employees",
          headers={"Authorization": f"Bearer {os.environ['ONTIME_API_KEY']}"},
          timeout=30,
      )
      res.raise_for_status()
      body = res.json()
      print(body["meta"]["count"], "employees")
      ```
    </CodeGroup>
  </Step>

  <Step title="Read the response">
    Every public endpoint returns the same envelope: a `meta` object and a `data` array.

    ```json theme={null}
    {
      "meta": { "count": 2 },
      "data": [
        {
          "id": "3f1c9b2a-5d84-4e7a-9c11-2b6f8d0a4e73",
          "code": "EMP-0421",
          "name": "Rhea Varma",
          "email": "rhea.varma@example.com",
          "department": "Operations",
          "status": "Active"
        },
        {
          "id": "8a2e4d61-7c93-4b05-8f2d-1e5c9a3b7d40",
          "code": "EMP-0518",
          "name": "Arjun Nair",
          "email": "arjun.nair@example.com",
          "department": "Sales",
          "status": "Probation"
        }
      ]
    }
    ```
  </Step>

  <Step title="Register a webhook">
    So you find out when something happens rather than polling for it. **API & webhooks → Register webhook**, then verify the signature — see [Webhooks](/developers/webhooks/overview).
  </Step>
</Steps>

## What the public API covers

Two endpoints:

| Endpoint                                        | Returns                                   |
| ----------------------------------------------- | ----------------------------------------- |
| `GET /api/public/v1/employees`                  | The organization's employee directory.    |
| `GET /api/public/v1/attendance?date=YYYY-MM-DD` | Every employee's day record for one date. |

<Warning>
  **The public API is read-only.** There are no write endpoints. A key issued with the `ReadWrite` scope currently grants exactly the same access as `ReadOnly` — see [Authentication](/developers/authentication).

  If you need to write, use the MCP server (which does support writes, under the bound employee's permissions) or the admin console.
</Warning>

## Rate limit

600 requests per minute, per key. Exceeding it returns `429` with `{"error": "too_many_requests"}`.

<Note>
  Counters are held in process memory, so a backend restart resets them. Treat 600 as the intended budget rather than a hard guarantee, and back off on `429` regardless.
</Note>

## Where to go next

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/developers/authentication">
    Keys, scopes, headers and secret handling.
  </Card>

  <Card title="Errors" icon="triangle-alert" href="/developers/errors">
    The error envelope and what each status means.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/developers/webhooks/overview">
    Registering, verifying signatures, retries and replay.
  </Card>

  <Card title="Guides" icon="book" href="/developers/guides/export-attendance-to-payroll">
    Worked end-to-end integrations.
  </Card>
</CardGroup>
