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

# Integrate Take Time Data into Your Tools and Workflows

> Use the Take Time REST API to sync your study schedule with external tools, automate block creation, and pull progress data into your own dashboards.

The Take Time REST API gives you programmatic access to your entire study schedule. You can automate block creation from calendar imports, pull heatmap data into personal dashboards, or build custom reminders — all through a simple HTTP API.

## Common integration patterns

Every integration starts with an API key. Generate one in **Settings → Developer → Generate API Key**, then use it as a Bearer token on every request. The four most common patterns are:

1. **Daily sync** — Query today's blocks each morning and push them to a Notion or Obsidian task list to keep your notes in sync with your study plan.
2. **Progress dashboard** — Call `GET /v1/stats` weekly to pull streak counts and completion rates into Grafana, Notion charts, or any BI tool you already use.
3. **Schedule automation** — Create blocks programmatically from a course syllabus CSV or calendar `.ics` file so you never have to enter sessions by hand.
4. **AI assistant** — Connect the Take Time MCP Server to Claude or Cursor so your AI assistant can read and update your schedule via natural language.

<Info>
  All API requests require the `Authorization: Bearer <key>` header. Requests without a valid key return `401 UNAUTHORIZED`.
</Info>

## Listing today's blocks

The `GET /v1/blocks` endpoint accepts a `date` query parameter in `YYYY-MM-DD` format. Fetch today's blocks and filter for incomplete sessions to build a quick daily briefing.

<CodeGroup>
  ```javascript Node.js theme={null}
  const today = new Date().toISOString().split('T')[0];

  const res = await fetch(`https://api.taketime.app/v1/blocks?date=${today}`, {
    headers: { 'Authorization': 'Bearer tt_live_your_key_here' }
  });

  const { data, error } = await res.json();

  if (error) {
    console.error('API error:', error.code, error.message);
    process.exit(1);
  }

  const pending = data.filter(b => !b.done);
  console.log(`${pending.length} blocks remaining today`);
  ```

  ```bash cURL theme={null}
  curl -G https://api.taketime.app/v1/blocks \
    --data-urlencode "date=$(date +%F)" \
    -H "Authorization: Bearer tt_live_your_key_here"
  ```
</CodeGroup>

<Tip>
  For multi-day queries, use the `date_from` and `date_to` parameters instead of calling the endpoint once per day. A single ranged request is faster and counts as one API call against your rate limit.
</Tip>

## Marking a block complete

Send a `PATCH` request to `/v1/blocks/:id` with `done: true` to mark a block complete. You can also update the `topic`, `start`, `end`, or `subject_id` fields in the same request.

<CodeGroup>
  ```javascript Node.js theme={null}
  const blockId = 'blk_abc123';

  const res = await fetch(`https://api.taketime.app/v1/blocks/${blockId}`, {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer tt_live_your_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ done: true })
  });

  const { data, error } = await res.json();

  if (error) {
    console.error('Failed to mark block done:', error.code, error.message);
  } else {
    console.log('Block marked complete:', data.id);
  }
  ```

  ```bash cURL theme={null}
  curl -X PATCH https://api.taketime.app/v1/blocks/blk_abc123 \
    -H "Authorization: Bearer tt_live_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{"done": true}'
  ```
</CodeGroup>

<Warning>
  Marking a block `done: true` is reversible — you can `PATCH` it back to `done: false` — but doing so may affect your streak calculation if the day has already rolled over.
</Warning>

## Pulling progress stats

`GET /v1/stats` returns aggregated progress data for a given time period. Use the `period` parameter — `today`, `week`, `month`, or `all` — to control how far back the data goes.

<CodeGroup>
  ```javascript Node.js theme={null}
  const res = await fetch('https://api.taketime.app/v1/stats?period=week', {
    headers: { 'Authorization': 'Bearer tt_live_your_key_here' }
  });

  const { data, error } = await res.json();

  if (error) {
    console.error('Stats error:', error.code, error.message);
    process.exit(1);
  }

  const { completion_rate, streak_days, heatmap } = data;

  console.log(`Completion rate this week: ${(completion_rate * 100).toFixed(1)}%`);
  console.log(`Current streak: ${streak_days} days`);
  // heatmap is an object keyed by date with a session count value
  Object.entries(heatmap).forEach(([date, count]) => {
    console.log(`  ${date}: ${count} session(s) completed`);
  });
  ```

  ```bash cURL theme={null}
  curl "https://api.taketime.app/v1/stats?period=week" \
    -H "Authorization: Bearer tt_live_your_key_here"
  ```
</CodeGroup>

The response `data` object includes:

| Field              | Type      | Description                                                  |
| ------------------ | --------- | ------------------------------------------------------------ |
| `total_blocks`     | `integer` | Total blocks in the period.                                  |
| `completed_blocks` | `integer` | Number of blocks marked done.                                |
| `completion_rate`  | `number`  | Fraction of scheduled blocks completed (0–1).                |
| `streak_days`      | `integer` | Current consecutive-day streak.                              |
| `total_minutes`    | `integer` | Total study minutes in the period.                           |
| `heatmap`          | `object`  | Map of `{ "YYYY-MM-DD": count }` for each day in the period. |

Valid values for `period`: `today`, `week`, `month`, `all`.

## Error handling

Every Take Time API response uses a consistent `{ data, error, meta }` envelope. The `data` field is `null` when an error occurs, and the `error` object contains a machine-readable `code` and a human-readable `message`.

```javascript Node.js theme={null}
async function apiRequest(url, options = {}) {
  const res = await fetch(url, {
    ...options,
    headers: {
      'Authorization': `Bearer ${process.env.TAKETIME_API_KEY}`,
      'Content-Type': 'application/json',
      ...options.headers
    }
  });

  const body = await res.json();

  if (body.error) {
    const { code, message } = body.error;

    switch (code) {
      case 'VALIDATION_ERROR':
        throw new Error(`Bad request — check your input fields: ${message}`);
      case 'NOT_FOUND':
        throw new Error(`Resource not found: ${message}`);
      case 'RATE_LIMITED': {
        const retryAfter = res.headers.get('Retry-After') ?? 'unknown';
        throw new Error(`Rate limited. Retry after ${retryAfter} seconds.`);
      }
      case 'UNAUTHORIZED':
        throw new Error('Invalid or missing API key.');
      default:
        throw new Error(`API error [${code}]: ${message}`);
    }
  }

  return body.data;
}
```

Key error codes you'll encounter:

| Code               | Meaning                                                                                  |
| ------------------ | ---------------------------------------------------------------------------------------- |
| `VALIDATION_ERROR` | One or more input fields failed validation. Check the `message` for field-level details. |
| `NOT_FOUND`        | The block or activity ID you referenced does not exist.                                  |
| `RATE_LIMITED`     | You've exceeded your plan's request quota. Respect the `Retry-After` response header.    |
| `UNAUTHORIZED`     | The API key is missing, malformed, or revoked.                                           |

<Warning>
  Never log or expose your full API key in error output or client-side code. If a key is compromised, revoke it immediately in **Settings → Developer** and generate a replacement.
</Warning>

## Best practices

<Tip>
  Use `tt_test_` prefixed keys during development. Test keys give you full API access in an isolated sandbox so your experiments never touch real study data.
</Tip>

* **Use date range filters.** Pass `date_from` and `date_to` to `GET /v1/blocks` instead of making one request per day. Range queries reduce round-trips and are counted as a single API call.
* **Always check `error` before reading `data`.** Even a `200 OK` response can carry an `error` object in edge cases. Treat `error !== null` as a failure regardless of HTTP status.
* **Handle `RATE_LIMITED` gracefully.** Read the `Retry-After` header and implement exponential backoff rather than hammering the API on failure.
* **Validate block IDs before patching.** Call `GET /v1/blocks` with a date filter to confirm a block exists before sending a `PATCH`. This avoids `NOT_FOUND` errors in automation scripts.
* **Store your API key in environment variables.** Never hardcode keys in source files. Use `process.env.TAKETIME_API_KEY` in Node.js or your platform's secrets manager.
