# Developer quickstart and API reference The REPSLog API lets you log and read REPS work hours programmatically. Use it to build your own integrations, automate time logging from another tool, or pull hours summaries into a report. This article is a quickstart and reference. For an always-current, interactive version you can call directly from your browser, see the live docs at [api.reps-log.com/v1/docs](https://api.reps-log.com/v1/docs). ## Before you start - **Premium required.** The API is available to REPSLog Premium subscribers only. Requests from non-Premium accounts return `403`. - **Get an API key.** Create one in the Developer Portal at [api.reps-log.com](https://api.reps-log.com). A key looks like `rl_.`. The secret is shown once at creation time and never again, so store it somewhere safe. If you lose it, rotate the key to issue a new secret. ## Base URL ``` https://api.reps-log.com/v1 ``` ## Authentication Every request to `/v1` must include a bearer token in the `Authorization` header. You can use either an API key or a WorkOS OAuth access token. ``` Authorization: Bearer rl_. ``` If a key is leaked, revoke it from the Developer Portal. Revocation takes effect immediately (the next request returns `401`). The raw secret is never logged on our side. ## Endpoints All paths below are relative to the base URL `https://api.reps-log.com/v1`. | Method | Path | Description | Key parameters | |---|---|---|---| | POST | `/time-logs` | Create a time log against an existing property | Body: `propertyId`, `description`, `durationMinutes` (required); `categoryId`, `performedOn`, `performedBy`, `isSTR` (optional). Header: `Idempotency-Key` (optional) | | GET | `/time-logs` | List time logs | `from`, `to`, `propertyId`, `categoryId`, `propertyType` (`str`/`ltr`), `limit`, `cursor` | | GET | `/properties` | List all of your properties (no pagination) | none | | GET | `/categories` | List your categories | none | | GET | `/participants` | List your participants | none | | GET | `/hours-summary` | Aggregate logged hours | `from`, `to`, `propertyId`, `categoryId`, `participantId`, `propertyType` (`str`/`ltr`) | | GET | `/user-settings` | Read whitelisted account settings | none. Returns `propertiesType` (`both`/`ltr`/`str`) and `internationalPropertiesEnabled` | ### Create time log body fields - `propertyId` (string, required): the property the work was performed against. - `description` (string, required, max 2000 chars): what the work was. - `durationMinutes` (integer, required, 1 to 1440): how long the work took. - `categoryId` (string, optional): the work category. - `performedOn` (date, optional, `YYYY-MM-DD`): when the work was done. Defaults to today if omitted. - `performedBy` (string, optional): `self` or `spouse`. - `isSTR` (boolean, optional): whether the work counts toward short-term rental hours. ## curl examples ### Create a time log The optional `Idempotency-Key` header lets you safely retry a create without logging it twice. Reusing the same key returns the original result instead of creating a duplicate. ```bash curl -X POST https://api.reps-log.com/v1/time-logs \ -H "Authorization: Bearer rl_abc123.s3cr3t" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 7f1c9e2a-0001" \ -d '{ "propertyId": "prop_maple_street", "description": "Met contractor to review kitchen renovation bids", "durationMinutes": 90, "categoryId": "cat_repairs", "performedOn": "2026-06-01", "performedBy": "self", "isSTR": false }' ``` A successful create returns `201`: ```json { "ok": true, "data": { "id": "log_8842", "propertyId": "prop_maple_street", "categoryId": "cat_repairs", "description": "Met contractor to review kitchen renovation bids", "durationMinutes": 90, "performedOn": "2026-06-01", "performedBy": "self", "isSTR": false, "isMaterial": true, "source": "public-api" } } ``` ### List time logs ```bash curl -G https://api.reps-log.com/v1/time-logs \ -H "Authorization: Bearer rl_abc123.s3cr3t" \ --data-urlencode "from=2026-01-01" \ --data-urlencode "to=2026-06-30" \ --data-urlencode "propertyId=prop_maple_street" \ --data-urlencode "limit=50" ``` Returns `200` with a paginated payload. When more results are available, `nextCursor` is set; pass it back as the `cursor` parameter to fetch the next page. ```json { "ok": true, "data": { "data": [ { "id": "log_8842", "propertyId": "prop_maple_street", "categoryId": "cat_repairs", "description": "Met contractor to review kitchen renovation bids", "durationMinutes": 90, "performedOn": "2026-06-01", "performedBy": "self", "isSTR": false, "isMaterial": true, "source": "public-api" } ], "nextCursor": "eyJwIjoyfQ" } } ``` ### Get an hours summary ```bash curl -G https://api.reps-log.com/v1/hours-summary \ -H "Authorization: Bearer rl_abc123.s3cr3t" \ --data-urlencode "from=2026-01-01" \ --data-urlencode "to=2026-06-30" \ --data-urlencode "propertyType=str" ``` Returns `200`: ```json { "ok": true, "data": { "totalHours": 142.5, "materialHours": 120.0, "strHours": 142.5, "entryCount": 96, "from": "2026-01-01", "to": "2026-06-30", "byProperty": [ { "propertyId": "prop_maple_street", "hours": 80.0, "entryCount": 54 }, { "propertyId": "prop_oak_avenue", "hours": 62.5, "entryCount": 42 } ] } } ``` ## Rate limits Requests are limited to **60 requests per 60 seconds** per API key (or per user for OAuth tokens). When you exceed the limit you get a `429` response. These responses include a `Retry-After` header telling you how long to wait, plus `RateLimit-*` headers describing your current quota. Back off and retry after the indicated delay. ## Error envelope Every error response uses the same JSON shape: ```json { "ok": false, "code": "validation_error", "message": "durationMinutes must be between 1 and 1440", "requestId": "req_a1b2c3", "details": {} } ``` - `ok` is always `false` on errors. - `code` is a stable machine-readable string you can branch on. - `message` is a human-readable explanation. - `requestId` identifies the request. Include it if you contact support. - `details` is optional and may carry field-level validation info. Common status codes: | Status | Meaning | |---|---| | `400` | Validation or bad request | | `401` | Missing, invalid, or revoked credentials | | `403` | Forbidden scope, or the account is not Premium | | `404` | Resource not found | | `429` | Rate limited (see `Retry-After`) | ## Interactive docs The full, always-current specification with a try-it console lives at [api.reps-log.com/v1/docs](https://api.reps-log.com/v1/docs). The raw OpenAPI document is at [api.reps-log.com/v1/openapi.json](https://api.reps-log.com/v1/openapi.json). Both are public and need no authentication to view.