Building on the Miru API: What Developers Need to Know
Authentication, endpoints, rate limits, and real code examples. Everything you need to build on top of Miru's REST API.
Miru has a REST API. Not a “REST API” in scare quotes where half the endpoints are undocumented and the other half return HTML error pages. An actual, consistent, JSON-in-JSON-out API that covers every resource in the system.
Here’s what you need to know to start building on it.
Authentication
Bearer token. Generate one from Settings > Profile > API Token in the Miru web app. Include it in every request:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://app.miru.so/api/v1/time_entries
Tokens don’t expire on their own. Revoke them from the same settings page. If you’re building a multi-user integration, each user generates their own token. There’s no OAuth flow — by design. OAuth is the right choice for third-party apps with millions of users. For internal tools and integrations, a bearer token is simpler, faster, and harder to get wrong.
Base URL
https://app.miru.so/api/v1
Self-hosted instances use your own domain: https://miru.yourcompany.com/api/v1. Everything else works the same.
Endpoints
The API is organized around resources. Each resource supports the standard CRUD operations you’d expect:
| Resource | Methods | What It Does |
|---|---|---|
/time_entries | GET, POST, PUT, DELETE | Track and manage time |
/invoices | GET, POST, PUT | Create and manage invoices |
/clients | GET, POST, PUT, DELETE | Manage clients |
/projects | GET, POST, PUT, DELETE | Manage projects |
/expenses | GET, POST | Track expenses |
/payments | GET | View payment history |
/users | GET | List team members |
GET requests support pagination and filtering. POST and PUT expect JSON bodies. DELETE does what you’d expect. Every response includes standard HTTP status codes — 200 for success, 201 for created, 422 for validation errors, 404 for not found.
Real Examples
Create a time entry:
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"project_id": 42, "duration": 120, "note": "API integration work"}' \
https://app.miru.so/api/v1/time_entries
List invoices for a specific client:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.miru.so/api/v1/invoices?client_id=7"
Create a new project:
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Q2 Website Redesign", "client_id": 7, "billable": true}' \
https://app.miru.so/api/v1/projects
Export time entries for a date range:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://app.miru.so/api/v1/time_entries?from=2026-01-01&to=2026-01-31" \
| jq '.[] | {date: .work_date, hours: .duration, project: .project_name}'
Pipe it to jq, csvkit, or whatever you like. The output is JSON. Do what you want with it.
Rate Limits
100 requests per minute per token. If you exceed it, you’ll get a 429 response with a Retry-After header. Back off and retry.
For most integrations, this is more than enough. If you’re syncing thousands of records, batch your reads and space your writes. If you’re polling for changes, consider caching the last result and only fetching new records. The API returns records in chronological order, so you can use timestamps to pick up where you left off.
What People Build
In the months since the API launched, we’ve seen people build:
- Slack bots that let team members log time without leaving the chat
- Dashboard integrations that pull Miru data into Grafana and Metabase
- Billing automation scripts that generate invoices on the first of every month
- Calendar sync tools that create time entries from Google Calendar events
- CI/CD hooks that log deployment time to the associated project
- Mobile shortcuts using iOS Shortcuts and the API to log time with one tap
The API is the same one the Miru web app uses. If you can do it in the browser, you can do it with curl.
Error Handling
Errors return JSON with a message field and a standard HTTP status code. No HTML error pages. No stack traces in production. No guessing.
{
"error": "Validation failed",
"messages": ["Duration must be greater than 0", "Project is required"]
}
Handle 422s (validation), 401s (bad token), 404s (resource not found), and 429s (rate limited). That covers 99% of error scenarios.
Getting Started
- Sign up at app.miru.so or self-host
- Generate an API token from Settings > Profile
- Make your first request:
curl -H "Authorization: Bearer TOKEN" https://app.miru.so/api/v1/users - Build something
The full API reference with request/response schemas is at docs.miru.so. But honestly, the best way to learn any API is to open a terminal and start making requests. The endpoints are predictable. The responses are consistent. You’ll figure it out in ten minutes.
Your tools should talk to each other. The API makes that possible. Get your token and start building.
Vipul A M
Co-founder at Saeloun. Building Miru. Rails contributor. Shipping from Pune, India.
Read next
How We Track Time with AI Agents and the Miru CLI
A practical guide to automated time tracking for teams using Claude Code, Codex, and other AI coding tools. Real workflows, real scripts, zero browser tabs.
Dark Mode Done Right: Why Most Apps Get It Wrong
CSS invert() is not dark mode. Here's what it actually takes to build a dark theme that doesn't hurt your eyes.
Why We Built the Miru CLI (And Why Every SaaS Should Have One)
Most SaaS tools treat the terminal as an afterthought. We built a full CLI because developers deserve better than a browser tab.