API Documentation
Getting Started
Overview
The Log My Business API allows third-party applications to access and manage organization data including customers, projects, tasks, time entries, and mileage records. All API endpoints are scoped to an organization and require proper authentication.
Base URL
https://app.logmybusiness.com/api
Organization ID
All API endpoints require your Organization ID in the path. You can find it in two places:
- The Developer Portal displays your Organization ID at the top of the page
-
Authorization Code flow only: Call
GET /api/organization/my-organizationswith your access token to list all organizations the authenticated user belongs to
Quick Start
- Go to the Developer Portal and register a new application
- Choose Confidential for server-to-server access or Public for browser/mobile apps
- Select the API scopes your application needs
- Save your Client ID and Client Secret (shown only once)
- Use the credentials to obtain an access token
- Include the access token in the
Authorizationheader of your API requests
Two Authentication Flows
Client Credentials (Server-to-Server)
For backend services that need to access organization data without user interaction. The token acts on behalf of the organization, not a specific user.
Best for: cron jobs, data sync, reporting tools, backend integrations
Authorization Code + PKCE (User-Delegated)
For applications that need to act on behalf of a specific user. The user authorizes the application via a consent screen, and the token carries their identity and permissions.
Best for: web apps, mobile apps, third-party dashboards
Authentication
Client Credentials Flow
Exchange your client credentials for an access token. Requires a confidential client.
Request
POST /connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&scope=api:customers:read api:projects:read
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
Authorization Code + PKCE Flow
For applications that need user-delegated access. Works with both public and confidential clients.
Step 1: Redirect user to authorize
GET /connect/authorize?
client_id=YOUR_CLIENT_ID
&response_type=code
&redirect_uri=https://your-app.com/callback
&scope=openid email profile api:customers:read
&code_challenge=YOUR_PKCE_CHALLENGE
&code_challenge_method=S256
The user will see a consent screen listing the requested permissions. After approving, they'll be
redirected to your redirect_uri with an authorization code.
Step 2: Exchange code for token
POST /connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=YOUR_CLIENT_ID
&code=AUTHORIZATION_CODE
&redirect_uri=https://your-app.com/callback
&code_verifier=YOUR_PKCE_VERIFIER
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"id_token": "eyJhbGciOiJSUzI1NiIs..."
}
Refreshing Tokens
POST /connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&client_id=YOUR_CLIENT_ID
&refresh_token=YOUR_REFRESH_TOKEN
Using Access Tokens
Include the access token in the Authorization header of every API request:
GET /api/customer/{organizationId}
Authorization: Bearer YOUR_ACCESS_TOKEN
Scopes
API Scopes
Scopes control what data your application can access. Request only the scopes you need.
| Scope | Description | Access Level |
|---|---|---|
api:customers:read | View customers and their details | Read |
api:customers:write | Create, update, and delete customers | Write |
api:projects:read | View projects and their details | Read |
api:projects:write | Create, update, and delete projects | Write |
api:tasks:read | View tasks and their details | Read |
api:tasks:write | Create, update, and delete tasks | Write |
api:time-entries:read | View time tracking entries | Read |
api:time-entries:write | Create, update, and delete time entries | Write |
api:mileage:read | View mileage tracking entries | Read |
api:mileage:write | Create, update, and delete mileage entries | Write |
api:members:read | View organization members and their roles | Read |
api:tags:read | View tags | Read |
api:tags:write | Create, update, and delete tags | Write |
api:invoices:read | View invoices, estimates, payments, and invoice settings | Read |
api:invoices:write | Create, update, send, and void invoices and estimates | Write |
api:expenses:read | View expenses and expense categories | Read |
api:expenses:write | Create, update, and delete expenses and categories | Write |
api:catalog:read | View products and services | Read |
api:catalog:write | Create, update, and delete products and services | Write |
openid, email, profile)
are also available for Authorization Code flow to access user identity information.
Endpoints
All endpoints require authentication and are scoped to an organization via the
{organizationId} path parameter. Abbreviated as {orgId} below.
Organization Members
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/organization/{orgId}/members | api:members:read | List organization members |
Response
[
{
"userId": "abc-123",
"email": "user@example.com",
"displayName": "Jane Smith",
"firstName": "Jane",
"lastName": "Smith",
"role": "Admin",
"joinedAt": "2025-06-15T10:30:00Z"
}
]
Customers
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/customer/{orgId} | api:customers:read | List all customers |
| GET | /api/customer/{orgId}/{id} | api:customers:read | Get customer details |
| POST | /api/customer/{orgId} | api:customers:write | Create a customer |
| PUT | /api/customer/{orgId}/{id} | api:customers:write | Update a customer |
| DELETE | /api/customer/{orgId}/{id} | api:customers:write | Delete a customer |
Create / Update Request Body
{
"name": "Acme Corp", // required
"companyName": "Acme Corporation",
"email": "contact@acme.com",
"phoneNumber": "555-0100",
"addressLine1": "123 Main St",
"city": "Springfield",
"stateProvince": "IL",
"postalCode": "62704",
"country": "US",
"customerType": "Business",
"status": "Active",
"notes": "Key account",
"creditLimit": 10000.00
}
Projects
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/project/{orgId} | api:projects:read | List all projects |
| GET | /api/project/{orgId}/{id} | api:projects:read | Get project details |
| POST | /api/project/{orgId} | api:projects:write | Create a project |
| PUT | /api/project/{orgId}/{id} | api:projects:write | Update a project |
| DELETE | /api/project/{orgId}/{id} | api:projects:write | Delete a project |
| GET | /api/project/{orgId}/{id}/users | api:projects:read | List project members |
| GET | /api/project/{orgId}/{id}/stats | api:projects:read | Get project statistics |
Create / Update Request Body
{
"name": "Website Redesign", // required
"customerId": 1, // optional, link to customer
"description": "Full site overhaul",
"status": "Active",
"projectCode": "WEB-001",
"hourlyRate": 150.00,
"isBillable": true,
"startDate": "2025-01-15",
"endDate": "2025-06-30",
"budgetAmount": 50000.00
}
Tasks
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/task/{orgId} | api:tasks:read | List all tasks |
| GET | /api/task/{orgId}/{id} | api:tasks:read | Get task details |
| GET | /api/task/{orgId}/kanban | api:tasks:read | Get kanban board view |
| POST | /api/task/{orgId} | api:tasks:write | Create a task |
| PUT | /api/task/{orgId}/{id} | api:tasks:write | Update a task |
| DELETE | /api/task/{orgId}/{id} | api:tasks:write | Delete a task |
| POST | /api/task/{orgId}/{id}/move | api:tasks:write | Change task status |
| POST | /api/task/{orgId}/{id}/assign | api:tasks:write | Assign users to task |
| POST | /api/task/{orgId}/{id}/tags/{tagId} | api:tasks:write | Add tag to task |
| DELETE | /api/task/{orgId}/{id}/tags/{tagId} | api:tasks:write | Remove tag from task |
| GET | /api/task/{orgId}/{id}/comments | api:tasks:read | List comments on a task |
| POST | /api/task/{orgId}/{id}/comments | api:tasks:write | Add a comment to a task |
| PUT | /api/task/{orgId}/{id}/comments/{commentId} | api:tasks:write | Update a comment (author only) |
| DELETE | /api/task/{orgId}/{id}/comments/{commentId} | api:tasks:write | Delete a comment (author, Admin, or Owner) |
Create Request Body
{
"title": "Design homepage mockup", // required
"projectId": 1, // required
"description": "Create initial wireframes",
"priority": 2, // 0=Low, 1=Medium, 2=High, 3=Critical
"dueDate": "2025-02-28",
"startDate": "2025-02-01",
"estimatedHours": 8.0,
"assigneeIds": ["user-id-1", "user-id-2"],
"tagIds": [1, 3]
}
Update Request Body (all fields optional)
{
"title": "Updated title",
"status": "InProgress", // Todo, InProgress, Review, Done
"priority": 3, // 0=Low, 1=Medium, 2=High, 3=Critical
"progress": 50,
"actualHours": 4.5
}
Comment Request Body (POST / PUT)
{
"comment": "Looks good — ready for review" // required, max 5000 chars
}
Comment Response
{
"id": 42,
"taskId": 5,
"userId": "abc-123",
"userName": "Jane Smith",
"profilePictureUrl": null,
"comment": "Looks good — ready for review",
"createdAt": "2026-05-05T14:22:00Z",
"updatedAt": null,
"isSystemGenerated": false
}
Tags
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/tag/{orgId} | api:tags:read | List all tags |
| GET | /api/tag/{orgId}/{id} | api:tags:read | Get tag details |
| POST | /api/tag/{orgId} | api:tags:write | Create a tag |
| PUT | /api/tag/{orgId}/{id} | api:tags:write | Update a tag |
| DELETE | /api/tag/{orgId}/{id} | api:tags:write | Delete a tag |
| GET | /api/tag/{orgId}/{id}/tasks | api:tags:read | List tasks with this tag |
Create / Update Request Body
{
"name": "Urgent", // required
"color": "#EF4444", // required, hex color
"description": "High priority items"
}
Time Entries
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/timeentry/{orgId}/week | api:time-entries:read | Get weekly time view |
| GET | /api/timeentry/{orgId}/day | api:time-entries:read | Get daily time view |
| GET | /api/timeentry/{orgId}/report | api:time-entries:read | Get time report |
| POST | /api/timeentry/{orgId} | api:time-entries:write | Create a time entry |
| PUT | /api/timeentry/{orgId}/{id} | api:time-entries:write | Update a time entry |
| DELETE | /api/timeentry/{orgId}/{id} | api:time-entries:write | Delete a time entry |
Create / Update Request Body
{
"projectId": 1, // required
"date": "2025-02-15", // required
"hours": 4.5, // required, 0.01-24
"categoryId": 2, // optional project category
"taskId": 5, // optional link to task
"description": "Frontend work",
"startTime": "09:00:00", // optional
"endTime": "13:30:00" // optional
}
Mileage
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/mileage/{orgId} | api:mileage:read | List mileage entries |
| GET | /api/mileage/{orgId}/{id} | api:mileage:read | Get mileage entry details |
| POST | /api/mileage/{orgId} | api:mileage:write | Create a mileage entry |
| PUT | /api/mileage/{orgId}/{id} | api:mileage:write | Update a mileage entry |
| DELETE | /api/mileage/{orgId}/{id} | api:mileage:write | Delete a mileage entry |
Create Request Body
{
"projectId": 1, // required
"date": "2025-02-15", // required
"totalMiles": 45.2, // required
"startMiles": 12500.0, // optional, odometer start
"endMiles": 12545.2, // optional, odometer end
"mileageRate": 0.67, // optional, override default
"description": "Client site visit",
"isBillable": true
}
Invoices & Estimates
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/invoice/{orgId} | api:invoices:read | List invoices and estimates |
| GET | /api/invoice/{orgId}/{id} | api:invoices:read | Get invoice details (lines, payments) |
| GET | /api/invoice/{orgId}/{id}/pdf | api:invoices:read | Download the invoice PDF |
| GET | /api/invoice/{orgId}/billable-items | api:invoices:read | Uninvoiced time/mileage/expense items |
| GET | /api/invoice/{orgId}/settings | api:invoices:read | Invoice settings (numbering, terms, tax) |
| POST | /api/invoice/{orgId} | api:invoices:write | Create an invoice or estimate |
| PUT | /api/invoice/{orgId}/{id} | api:invoices:write | Update a draft invoice |
| POST | /api/invoice/{orgId}/{id}/send | api:invoices:write | Send (and optionally email) an invoice |
| POST | /api/invoice/{orgId}/{id}/payment | api:invoices:write | Record a manual payment |
| POST | /api/invoice/{orgId}/{id}/void | api:invoices:write | Void an invoice |
| POST | /api/invoice/{orgId}/{id}/convert | api:invoices:write | Convert an estimate to an invoice |
| DELETE | /api/invoice/{orgId}/{id} | api:invoices:write | Delete a draft invoice |
Tax-rate management (/api/invoice/{orgId}/tax-rates) and CSV export
(/api/invoice/{orgId}/export) follow the same read/write scope split.
Expenses
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/expense/{orgId} | api:expenses:read | List expenses (filter by date, project, task) |
| GET | /api/expense/{orgId}/{id} | api:expenses:read | Get expense details |
| POST | /api/expense/{orgId} | api:expenses:write | Create an expense |
| PUT | /api/expense/{orgId}/{id} | api:expenses:write | Update an expense (locked once invoiced) |
| DELETE | /api/expense/{orgId}/{id} | api:expenses:write | Delete an expense (locked once invoiced) |
| GET | /api/expensecategory/{orgId} | api:expenses:read | List expense categories |
| POST | /api/expensecategory/{orgId} | api:expenses:write | Create a category (Owner/Admin) |
Create Request Body
{
"projectId": 1, // required
"taskId": 42, // optional, link to a task
"date": "2025-02-15", // required
"categoryId": 3, // required
"description": "Parts for job", // required
"amount": 129.99, // required
"merchant": "Hardware Depot", // optional
"isBillable": true
}
Products & Services Catalog
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/catalogitem/{orgId} | api:catalog:read | List catalog items |
| GET | /api/catalogitem/{orgId}/{id} | api:catalog:read | Get catalog item details |
| POST | /api/catalogitem/{orgId} | api:catalog:write | Create a catalog item (Owner/Admin) |
| PUT | /api/catalogitem/{orgId}/{id} | api:catalog:write | Update a catalog item (Owner/Admin) |
| DELETE | /api/catalogitem/{orgId}/{id} | api:catalog:write | Delete a catalog item (Owner/Admin) |
Errors
Error Handling
The API uses standard HTTP status codes to indicate success or failure.
Error Response Format
{
"message": "A human-readable error description"
}
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid request body or parameters |
401 | Unauthorized | Missing or invalid access token |
403 | Forbidden | Token lacks required scope or organization access |
404 | Not Found | Resource does not exist |
500 | Server Error | Unexpected server error |
401 error, your access token may have expired.
Use the refresh token to obtain a new access token.