Work logged during the month, billed onto an invoice exactly once, and paper read from a photo or PDF into a draft a person files. A CSV of clients, items or open invoices can be dry-run here; a person runs the import in the console.
Stop one of the signed-in person’s timers, including one started on the phone; a minute or more records an unbilled time entry. A second stop answers the first. A mileage trip is refused (INVALID_KIND): it is stopped on the phone.
Scope
time:write
Effect
Writes a draft or record
MCP tool
stop_timer
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours
Parameters
Stop session parameters
Name
In
Type
Notes
sessionIdrequired
path
id
—
Returns
data: object
Errors this route can answer besides the shared ones: NOT_FOUND, INVALID_TRANSITION, INVALID_KIND, PERMISSION_DENIED.
Stop every open timer of the signed-in person, one after another; each of a minute or more records its own unbilled time entry. A timer that cannot stop stays open. A trip is not stopped.
Scope
time:write
Effect
Writes a draft or record
MCP tool
stop_all_timers
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours
Returns
data: object
Errors this route can answer besides the shared ones: PERMISSION_DENIED.
Add a document to the organizer: answers it and a short-lived signed URL to PUT its one file to (a PNG, JPEG, WebP or PDF, at most 5 MiB and 4 pages), with the headers to send. Nothing is read until organize is called. Refused with AI_CONSENT_REQUIRED until the person behind the credential (a connected app user, or the API key creator) has allowed Capture to send documents to Google Gemini in the product; an assistant cannot allow it for them.
Scope
organizer:write
Effect
Writes a draft or record
MCP tool
add_to_organizer
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours
Request body
JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.
Create request body
Field
Type
Notes
contentTyperequired
enum
One of image/png, image/jpeg, image/webp, application/pdf
fileNameoptional
string
up to 200 chars
businessIdoptional
id
—
Returns
data: object
Errors this route can answer besides the shared ones: BUSINESS_NOT_FOUND, AI_CONSENT_REQUIRED.
Organizer documents, newest first, optionally by status.
Scope
organizer:read
Effect
Read only
MCP tool
list_organizer_documents
Retries
Safe to repeat
Parameters
List parameters
Name
In
Type
Notes
limitoptional
query
integer
min 1 · max 50
cursoroptional
query
string
up to 256 chars
statusoptional
query
enum
One of awaitingUpload, queued, reading, ready, failed, filing, filed
Returns
data: OrganizerDoc[]. Pass meta.cursor back as cursor for the next page.
Example requestSample
curl -X GET "https://api.billingmart.com/v1/organizer" \
-H "Authorization: Bearer $BILLINGMART_API_KEY"
organizer
Organize
POST/v1/organizer/{docId}/organize
Ask the model to read an uploaded document. Answers at once with status queued; the result lands on the document. The server refuses a missing file, another type than declared, more than 5 MiB or a PDF of more than 4 pages. Uses AI credits. Refused with AI_CONSENT_REQUIRED if that consent was withdrawn since the document was added.
Scope
organizer:write
Effect
Writes a draft or record
MCP tool
organize_document
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours
Parameters
Organize parameters
Name
In
Type
Notes
docIdrequired
path
id
—
Returns
data: object
Errors this route can answer besides the shared ones: INVALID_TRANSITION, AI_CONSENT_REQUIRED.
One organizer document: its status, what the model read (a proposal, never a stored value) and the server's candidates. Candidates of a kind appear only with that kind's read scope.
curl -X GET "https://api.billingmart.com/v1/organizer/{docId}" \
-H "Authorization: Bearer $BILLINGMART_API_KEY"
organizer
Confirm
POST/v1/organizer/{docId}/confirm
File a document as a DRAFT invoice, estimate, job invoice, expense or bill, through the same cores as the console. The kind, every id and the amount are the caller's: candidates are never applied by themselves, the stored amount is the one submitted, and lines that do not add up to it are refused. Needs the kind's own write scope and plan feature. Never sends.
Scope
organizer:write
Effect
Writes a draft or record
MCP tool
file_organizer_document
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours
Parameters
Confirm parameters
Name
In
Type
Notes
docIdrequired
path
id
—
Request body
JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.
Confirm request body
Field
Type
Notes
kindrequired
enum
One of invoice, estimate, job, receipt, bill
amountrequired
object
—
amount.minorUnitsrequired
integer
min 1 · max 100000000000
amount.currencyrequired
Currency
—
businessIdoptional
id
—
clientIdoptional
id
—
vendorIdoptional
id
—
vendorNameoptional
string
up to 200 chars
jobIdoptional
id
—
jobLabeloptional
string
up to 200 chars
depositBasisPointsoptional
integer
min 1 · max 10000
descriptionoptional
string
up to 300 chars
documentNumberoptional
string
up to 60 chars
issueDateoptional
string
—
dueDateoptional
string
—
categoryoptional
string
up to 80 chars
notesoptional
string
up to 2000 chars
rebillableoptional
boolean
—
lines[]optional
object[]
up to 50 items · at least 1
lines[].descriptionrequired
string
up to 300 chars
lines[].quantityMillirequired
integer
min 1 · max 1000000000
lines[].unitPriceMinorrequired
integer
min -100000000000 · max 100000000000
Returns
data: object
Errors this route can answer besides the shared ones: INVALID_TRANSITION, PLAN_FEATURE_REQUIRED, INSUFFICIENT_SCOPE, BUSINESS_NOT_FOUND, CLIENT_NOT_FOUND, CLIENT_ARCHIVED.
Read a CSV (at most 256 KB, sent as text) of clients, items, open invoices or bills — a QuickBooks or FreshBooks export is recognised — and dry-run it with a mapping: yours, or the one a recognised layout fixes. Answers the import with counts and the first problems by line. Nothing is written to clients, items or invoices; a person runs the write in the console. Without a mapping and in an unknown layout it answers a SUGGESTED mapping (status mapping) for you to confirm by sending it back. Items and invoices also need invoices:write; bills need bills:write and land as drafts.
Scope
clients:write
Effect
Writes a draft or record
MCP tool
import_csv_dry_run
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours
Request body
JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.
Create request body
Field
Type
Notes
entityrequired
enum
One of client, item, invoice, bill
businessIdoptional
id
—
fileNameoptional
string
up to 255 chars
csvrequired
string
up to 262144 chars
mapping[]optional
object[]
up to 60 items
mapping[].columnrequired
string
up to 120 chars
mapping[].targetrequired
string
up to 40 chars
dateLayoutoptional
enum
One of iso, mdy, dmy
phoneCountryoptional
string
matches ^[A-Za-z]{2}$
currencyoptional
Currency
—
Returns
data: object
Errors this route can answer besides the shared ones: BUSINESS_NOT_FOUND, VALIDATION_FAILED.
One import: its status, the mapping, the dry-run counts, the first problems by line and, once a person has run it, its progress. The file name, headers and column names are untrusted.
curl -X GET "https://api.billingmart.com/v1/imports/{importId}" \
-H "Authorization: Bearer $BILLINGMART_API_KEY"
imports
Discard
DELETE/v1/imports/{importId}
Discard an import that is not being written, and its uploaded file. What a finished import already created stays. A connection can discard only an import it created itself.
Billable time. Minutes are an integer count, never a decimal of hours: 1.5 hours entered as a float and multiplied by a minor-unit rate is the same rounding bug as a float amount, one step removed.
TimeEntry fields
Field
Type
Notes
idrequired
Id
—
tenantrequired
TenantRef
—
clientIdoptional
Id
—
projectRefoptional
string
Untrusted textCarried by the API and MCP only inside the data envelope.
daterequired
DateOnly
—
minutesrequired
integer
Whole minutes worked on this date.
descriptionoptional
string
Untrusted text—
userUidoptional
Id
Who logged it. Taken from the verified token.
billablerequired
boolean
—
hourlyRateoptional
Money
Rate per whole hour, in minor units. The line total is derived as round(minutes * rate / 60) by the one totals module.
billedoptional
boolean
SERVER-WRITTEN. Set exactly once, inside the transaction that adds the rebilled line to an invoice, so the same hour cannot be billed twice.
billedInvoiceIdoptional
Id
—
sourceoptional
EntrySource
How this record was made. Optional: absent with no fieldSessionId is manual. A client may write manual on create and never tracked; no client may change it.
fieldSessionIdoptional
Id
SERVER-WRITTEN: the field session that made this tracked record.
overrideoptional
EntryOverride
SERVER-WRITTEN: set when a person shortened this tracked record.
createdAtrequired
IsoTimestamp
—
updatedAtoptional
IsoTimestamp
—
jobIdoptional
Id
The work record this belongs to, when it does.
Object
Expense
A cost incurred, optionally rebilled to a client with a markup. Markup is basis points, not a float multiplier.
Expense fields
Field
Type
Notes
idrequired
Id
—
tenantrequired
TenantRef
—
clientIdoptional
Id
—
projectRefoptional
string
Untrusted textRendered as text; carried by the API and MCP only inside the data envelope.
daterequired
DateOnly
—
categoryoptional
string
Untrusted text—
taxCategoryoptional
TaxCategoryCode
The tax category a person confirmed (a code of the taxonomy). Never set by a suggestion alone.
taxCategoryVersionoptional
string
The taxonomy edition taxCategory is a code of, e.g. us-sch-c-2026.
taxCategorySourceoptional
TaxCategorySource
—
taxScheduleCodeoptional
TaxCategoryCode
The TOP category taxCategory resolved to when it was confirmed (itself for a top category; a sub-category's parent), so a later rename or move never rewrites a past report.
taxScheduleLineoptional
string
The form line of taxScheduleCode at confirmation, e.g. Line 8; absent where the category is not a line of the form.
vendoroptional
string
Untrusted text—
descriptionoptional
string
Untrusted text—
amountrequired
Money
What was actually spent.
taxTreatmentoptional
TaxTreatment
—
markupBasisPointsoptional
BasisPoints
Applied when rebilling. 15% is 1500. The rebilled amount is round(amount * (10000 + markup) / 10000) — the rounding is explicit and testable, never implicit in a float.
receiptStoragePathoptional
string
Cloud Storage path. Content-type and size are enforced by storage.rules, not just the UI.
rebillablerequired
boolean
—
billedoptional
boolean
SERVER-WRITTEN. Set exactly once, inside the transaction that adds the rebilled line.
billedInvoiceIdoptional
Id
—
userUidoptional
Id
—
createdAtrequired
IsoTimestamp
—
updatedAtoptional
IsoTimestamp
—
jobIdoptional
Id
The work record this belongs to, when it does.
billIdoptional
Id
The vendor bill this expense is already on, so a cost is counted once: an expense with a billId is left out of a record's costs, the bill carries it.
Object
Mileage
A trip, optionally rebilled. Distance is an integer count of thousandths of the declared unit — 12.4 miles is 12400 — for the same reason quantities and amounts are integers. A float distance times a minor-unit rate is a rounding bug with a delivery date.
Mileage fields
Field
Type
Notes
idrequired
Id
—
tenantrequired
TenantRef
—
clientIdoptional
Id
—
projectRefoptional
string
Untrusted textRendered as text; carried by the API and MCP only inside the data envelope.
daterequired
DateOnly
—
fromLocationoptional
string
Untrusted text—
toLocationoptional
string
Untrusted text—
purposeoptional
string
Untrusted text—
distanceMillirequired
integer
Thousandths of distanceUnit. 12.4 miles is 12400.
distanceUnitrequired
DistanceUnit
—
ratePerUnitoptional
Money
Rate per one whole mile or kilometre.
rebillablerequired
boolean
—
billedoptional
boolean
SERVER-WRITTEN. Set exactly once.
billedInvoiceIdoptional
Id
—
userUidoptional
Id
—
sourceoptional
EntrySource
How this record was made. Optional: absent with no fieldSessionId is manual. A client may write manual on create and never tracked; no client may change it.
fieldSessionIdoptional
Id
SERVER-WRITTEN: the field session that made this tracked record.
overrideoptional
EntryOverride
SERVER-WRITTEN: set when a person shortened this tracked record.
createdAtrequired
IsoTimestamp
—
updatedAtoptional
IsoTimestamp
—
jobIdoptional
Id
The work record this belongs to, when it does.
Object
FieldSession
One stretch of field work tracked from a phone — a running timer or a GPS trip — from Start to Stop. The phone sends points and photos; every number here is derived by the SERVER: the minutes from its own clock, the distance from the filtered points.
FieldSession fields
Field
Type
Notes
idrequired
Id
—
tenantrequired
TenantRef
—
ownerUidrequired
Id
The person who started it: the verified ID token's uid, never the payload's. One person has at most one running session.
startRequestIdoptional
Id
The id the phone minted for this Start, so a repeated Start (a retry after a dropped connection) returns this session instead of making a second one.
kindrequired
FieldSessionKind
—
statusrequired
FieldSessionStatus
—
clientIdoptional
Id
The client the work is for, when the person picked one.
jobRefoptional
JobRef
The job the work is for, copied from the invoice's job the person picked (a job is not a document: it is invoice.jobRef).
projectRefoptional
string
Untrusted textRendered as text; carried by the API and MCP only inside the data envelope.
startedAtrequired
IsoTimestamp
SERVER CLOCK at Start. The phone's counter runs from this, so it is right after a relaunch and with the phone locked.
pausedAtoptional
IsoTimestamp
SERVER CLOCK when the person last paused; present only while status is paused, removed at Resume.
pausedMsoptional
integer
now). The phone shows startedAt + pausedMs as the counter origin; Stop subtracts it from the minutes. Absent means 0.
endedAtoptional
IsoTimestamp
SERVER CLOCK at Stop (or at Discard).
lastPointAtoptional
IsoTimestamp
When the server last accepted points for a trip.
minutesoptional
integer
Whole minutes between startedAt and endedAt, derived by the server at Stop.
distanceMillioptional
integer
Thousandths of distanceUnit, derived by the server at Stop over the accuracy- and speed-filtered points. A client-supplied distance is ignored.
distanceUnitoptional
DistanceUnit
The unit the distance was written in: the workspace's, at Stop.
pointCountoptional
integer
How many points the server accepted (after dropping implausible and low-accuracy ones).
trackPolylineoptional
string
The compacted track as an encoded polyline, written at Stop and kept after the raw points are purged. A person's location history: the REST API and MCP mask it unless the credential may read contacts.
startPhotosoptional
FieldPhoto[]
Photos added at Start, in the order added. At most 20, enforced by the server.
endPhotosoptional
FieldPhoto[]
Photos added at Stop, in the order added. At most 20, enforced by the server.
timeEntryIdoptional
Id
The unbilled time entry Stop wrote, when it wrote one.
mileageIdoptional
Id
The unbilled mileage record Stop wrote, when it wrote one.
rawPointsExpireAtoptional
IsoTimestamp
SERVER-WRITTEN at Stop: 90 days later, the raw points in chunks are deleted and only trackPolyline stays.
createdAtrequired
IsoTimestamp
—
updatedAtrequired
IsoTimestamp
—
jobIdoptional
Id
The work record this belongs to, when it does. FUNCTION-WRITTEN: set by the callables that check the record is in the same business, never by a payload alone.
Object
OrganizerDoc
One document the organizer is reading or has read: a photo or file a person added, what the model read on it, and the server's candidates for where it belongs.
OrganizerDoc fields
Field
Type
Notes
idrequired
Id
—
tenantIdrequired
Id
—
ownerUidrequired
Id
Who added it: the verified ID token's uid, or the credential id for an API key. Its files live under this id.
createdByrequired
WriteActor
The credential that added it, stamped by the server: the member, or the API key or grant. The model is run under it, so the AI credits and the audit are that actor's. SERVER-ONLY: REST v1 never returns it.
subjectUidoptional
Id
For a grant (an MCP connection or the Agent): the member it acts for, read from the live grant. SERVER-ONLY: REST v1 never returns it.
businessIdoptional
Id
The business it was added for, when the person had one chosen. Filing may name another the person may act in.
sourcerequired
enum
Where it was added: the console, a conversation with the Agent, a phone's Capture tab, or REST v1 and MCP.
agentSessionIdoptional
Id
The Agent conversation it was dropped into, when it was.
statusrequired
enum
awaitingUpload: created, its files not yet checked by the server. queued: organize accepted it. reading: the model is reading it. ready: read, candidates found.
filerequired
OrganizerFile
The one photo or file: an image, or a PDF of at most 4 pages. A document of several pages arrives as one PDF, so a receipt or bill keeps its one original file when it is filed.
classificationoptional
OrganizerClassification
—
candidatesoptional
OrganizerCandidates
—
failureoptional
OrganizerFailure
—
filedoptional
OrganizerFiled
—
attemptsoptional
integer
How many times it was sent to the model.
leaseExpiresAtoptional
IsoTimestamp
While reading or filing: when a stalled run may be taken over.
expiresAtoptional
IsoTimestamp
When the 7-day sweep removes it and its files. Present until it is filed, then deleted.
createdAtrequired
IsoTimestamp
—
updatedAtrequired
IsoTimestamp
—
Object
Import
One file a person (or an API client) is bringing clients, items or open invoices in from: which file, how its columns are mapped, what a dry run found, and how far the write has got. FUNCTION-WRITTEN ONLY: create, update and delete are `if false` for clients, and staff read is the only client access.
Import fields
Field
Type
Notes
idrequired
Id
—
tenantIdrequired
Id
—
ownerUidrequired
Id
Who brought the file in: the verified ID token's uid, or the credential id for an API key. The upload lives under this id.
createdByrequired
WriteActor
The credential that created the import, stamped by the server. SERVER-ONLY: REST v1 never returns it.
businessIdoptional
Id
The business the clients, items or invoices belong to. Required for items and invoices.
sourcerequired
enum
Where the file came in: an upload from the console, or CSV text sent to REST v1 or MCP.
entityrequired
enum
What the file holds. One kind per file; an invoice or bill file is one row per line item.
layoutrequired
enum
The export layout the headers matched, or csv for anything else. A known layout fixes the date format and pre-fills the mapping; the person still confirms it.
statusrequired
enum
mapping: read, waiting for a confirmed mapping. planned: dry run done, nothing written. running: the write pass has started and may be resumed. done: every row is accounted for.
fileNamerequired
string
Untrusted textThe file's name as uploaded.
fileHashrequired
string
SHA-256 of the file's bytes. The write pass refuses a plan whose file no longer hashes to this, and every record it writes has an id derived from it, so the same file imported twice is the same records.
fileBytesrequired
integer
—
rowCountrequired
integer
Data rows read, malformed ones included, blank ones not.
delimiteroptional
enum
The separator the file used, by name.
headersrequired
string[]
—
sampleoptional
ImportSampleRow[]
At most five rows of MASKED values: each value reduced to its shape (letters a, digits 9). What a model is shown, and all of it.
currencyoptional
Currency
The one currency of the file's amounts. A file that mixes currencies is refused with its rows named.
dateLayoutoptional
enum
How the file writes dates: year-month-day, month/day/year, or day/month/year. Fixed by the layout or chosen by a person, never guessed per row.
phoneCountryoptional
CountryCode
The country a phone number written without a country code belongs to, for a clients file: chosen by a person, else the business's own address country, else US.
mappingoptional
ImportMappingEntry[]
—
mappingSourceoptional
enum
Where the mapping came from. Whatever it was, a person confirmed it before the plan ran.
aiProposalIdoptional
Id
The aiProposals record of the model's mapping, when one was asked for.
planIdoptional
string
A hash of the file hash, the confirmed mapping and the settings. The write pass runs exactly this plan or refuses.
countsoptional
ImportCounts
—
errorsoptional
ImportRowError[]
The first rows that cannot be imported, each with its line. The count of all of them is counts.errors.
warningsoptional
ImportWarning[]
—
progressoptional
ImportProgress
—
createdAtrequired
IsoTimestamp
—
updatedAtrequired
IsoTimestamp
—
plannedAtoptional
IsoTimestamp
—
finishedAtoptional
IsoTimestamp
—
leaseExpiresAtoptional
IsoTimestamp
While the write pass is running: when its claim lapses. A second pass cannot start before this, and a pass that died is taken over after it. Never set once the import is done.
Next section
Bills and vendors
The other side of the ledger: vendors, the bills they send, and what has been paid against them.
We use Google Analytics on our website by default to understand visits. Choose Decline to turn it off; you can change this at any time on the Cookies page. We never send Google your name, email or account. Cookie policy