API reference
Project
A job for one customer. Its invoices, sales receipts and credits belong to it, and bill and expense lines, time and expense claims can be put on it; its numbers come from those (all dates).
The project object
- object string
- string
- Always "project".
- id id
- id
- The project's id (a UUID). Use it to fetch it, or to refer to it from other things.
- name string
- string
- Its name (each of a customer's projects has its own).
- customer_id id
- id
- The customer it's for.
- status string
- string
- not_started, in_progress, completed or canceled. New work goes only on projects not started or in progress.
- start_date date or null
- date or null
- When it starts.
- end_date date or null
- date or null
- When it ends.
- notes string or null
- string or null
- Notes.
- currency string
- string
- The business's currency: USD or CAD. All _cents amounts are in it.
- income_cents integer
- integer
- Income from its invoices, sales receipts and credits (in the books).
- cost_cents integer
- integer
- Costs in the books: its bill, expense, bank and journal lines, expense claims, and the cost of what it sold.
- labour_cents integer
- integer
- Employees' hours on it × their cost rate (not in the books until payroll).
- profit_cents integer
- integer
- income_cents − cost_cents − labour_cents.
- hours number
- number
- Time worked on it, in hours.
- unbilled_time_cents integer
- integer
- Billable time on it that isn't on an invoice yet.
- open_invoices_cents integer
- integer
- What's still owed on its sent invoices.
- created_at timestamp
- timestamp
- When it was added, in UTC.
- updated_at timestamp
- timestamp
- When it last changed.
Example
{
"object": "project",
"id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108",
"name": "Kitchen remodel",
"customer_id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708101",
"status": "in_progress",
"start_date": "2026-10-06",
"end_date": null,
"notes": null,
"currency": "USD",
"income_cents": 480000,
"cost_cents": 126000,
"labour_cents": 84000,
"profit_cents": 270000,
"hours": 40,
"unbilled_time_cents": 36000,
"open_invoices_cents": 120000,
"created_at": "2026-10-06T14:30:00.000Z",
"updated_at": "2026-10-06T14:30:00.000Z"
}List projects
GET /api/v1/projects
Projects (a job for a customer), newest first, each with its income, costs, labour and profit so far.
Key: any (Read only works).
Query
- limit integer
- integer
- How many, 1 to 100 (default 25).
- starting_after id
- id
- The last id of the page before, for the next page (when has_more is true).
- filters
- customer_id, status (not_started, in_progress, completed, canceled)
Newest first. Answers a list: { object: "list", url, has_more, data }.
Request
curl https://tallypip.com/api/v1/projects?limit=3 \ -H "Authorization: Bearer tpk_your_key"
Answer: 200
{
"object": "list",
"url": "/api/v1/projects",
"has_more": false,
"data": [
{
"object": "project",
"id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108",
"name": "Kitchen remodel",
"customer_id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708101",
"status": "in_progress",
"start_date": "2026-10-06",
"end_date": null,
"notes": null,
"currency": "USD",
"income_cents": 480000,
"cost_cents": 126000,
"labour_cents": 84000,
"profit_cents": 270000,
"hours": 40,
"unbilled_time_cents": 36000,
"open_invoices_cents": 120000,
"created_at": "2026-10-06T14:30:00.000Z",
"updated_at": "2026-10-06T14:30:00.000Z"
}
]
}Try it
With your own key (Settings › Connected apps). It stays in this page only, and reading can't change anything.
Create a project
POST /api/v1/projects
Start a project for a customer.
Key: Read and change.
Body (JSON)
- customer_id id
- id
- Required to start one. It can change only while nothing is on the project.
- name string
- string
- Required to start one. Each of a customer's projects has its own name.
- status string
- string
- not_started, in_progress (the default), completed or canceled. New work goes only on projects not started or in progress.
- start_date, end_date date
- date
- Optional. On a change, null clears one.
- notes string
- string
- Optional.
Answers 201 with the new project. Refused with 400 and the reason (nothing is saved); send an Idempotency-Key so a retry can't make it twice.
Request
curl https://tallypip.com/api/v1/projects \
-H "Authorization: Bearer tpk_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: <a new id for each change>" \
-d '{
"customer_id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708101",
"name": "Kitchen remodel",
"start_date": "2026-10-06"
}'Answer: 201
{
"object": "project",
"id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108",
"name": "Kitchen remodel",
"customer_id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708101",
"status": "in_progress",
"start_date": "2026-10-06",
"end_date": null,
"notes": null,
"currency": "USD",
"income_cents": 480000,
"cost_cents": 126000,
"labour_cents": 84000,
"profit_cents": 270000,
"hours": 40,
"unbilled_time_cents": 36000,
"open_invoices_cents": 120000,
"created_at": "2026-10-06T14:30:00.000Z",
"updated_at": "2026-10-06T14:30:00.000Z"
}Retrieve a project
GET /api/v1/projects/{id}
One project with its numbers.
Key: any (Read only works).
Request
curl https://tallypip.com/api/v1/projects/3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108 \ -H "Authorization: Bearer tpk_your_key"
Answer: 200
{
"object": "project",
"id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108",
"name": "Kitchen remodel",
"customer_id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708101",
"status": "in_progress",
"start_date": "2026-10-06",
"end_date": null,
"notes": null,
"currency": "USD",
"income_cents": 480000,
"cost_cents": 126000,
"labour_cents": 84000,
"profit_cents": 270000,
"hours": 40,
"unbilled_time_cents": 36000,
"open_invoices_cents": 120000,
"created_at": "2026-10-06T14:30:00.000Z",
"updated_at": "2026-10-06T14:30:00.000Z"
}Try it
With your own key (Settings › Connected apps). It stays in this page only, and reading can't change anything.
Update a project
PATCH /api/v1/projects/{id}
Change a project: send only what changes (its status, to complete or cancel it; its dates; its name).
Key: Read and change.
Body (JSON)
- customer_id id
- id
- Required to start one. It can change only while nothing is on the project.
- name string
- string
- Required to start one. Each of a customer's projects has its own name.
- status string
- string
- not_started, in_progress (the default), completed or canceled. New work goes only on projects not started or in progress.
- start_date, end_date date
- date
- Optional. On a change, null clears one.
- notes string
- string
- Optional.
Send only what changes. Answers 200 with the project as it is now. Refused with 400 and the reason (nothing is changed).
Request
curl -X PATCH https://tallypip.com/api/v1/projects/3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108 \
-H "Authorization: Bearer tpk_your_key" \
-H "Content-Type: application/json" \
-d '{
"status": "completed",
"end_date": "2026-12-18"
}'Answer: 200
{
"object": "project",
"id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708108",
"name": "Kitchen remodel",
"customer_id": "3f6c1e2a-8b4d-4c1e-9a7b-2d5e6f708101",
"status": "in_progress",
"start_date": "2026-10-06",
"end_date": null,
"notes": null,
"currency": "USD",
"income_cents": 480000,
"cost_cents": 126000,
"labour_cents": 84000,
"profit_cents": 270000,
"hours": 40,
"unbilled_time_cents": 36000,
"open_invoices_cents": 120000,
"created_at": "2026-10-06T14:30:00.000Z",
"updated_at": "2026-10-06T14:30:00.000Z"
}