Skip to content

Time, expenses and mileage

Explore here

Time, expenses, mileage and documents

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.

time

List

GET/v1/time-entries

List time entries, newest first.

Scope
time:read
Effect
Read only
MCP tool
list_time_entries
Retries
Safe to repeat

Parameters

List parameters
NameInTypeNotes
limitoptionalqueryintegermin 1 · max 50
cursoroptionalquerystringup to 256 chars
clientIdoptionalqueryid—
jobIdoptionalqueryid—
billedoptionalqueryboolean—

Returns

data: TimeEntry[]. Pass meta.cursor back as cursor for the next page.

Example requestSample
curl -X GET "https://api.billingmart.com/v1/time-entries" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY"

time

Create

POST/v1/time-entries

Record time. Minutes are integers — never a decimal of hours.

Scope
time:write
Effect
Writes a draft or record
MCP tool
record_time
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
FieldTypeNotes
daterequiredstringmatches ^\d{4}-\d{2}-\d{2}$
minutesrequiredintegermin 1 · max 1440
billablerequiredboolean—
clientIdoptionalid—
projectRefoptionalstringup to 120 chars
descriptionoptionalstringup to 2000 chars
hourlyRateoptionalobject—
hourlyRate.minorUnitsrequiredinteger—
hourlyRate.currencyrequiredCurrency—
businessIdoptionalid—

Returns

data: object

Example requestSample
curl -X POST "https://api.billingmart.com/v1/time-entries" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"date":"<date>","minutes":0,"billable":false,"hourlyRate":{"minorUnits":0,"currency":"USD"}}'

expenses

List

GET/v1/expenses

List expenses, newest first.

Scope
expenses:read
Effect
Read only
MCP tool
list_expenses
Retries
Safe to repeat

Parameters

List parameters
NameInTypeNotes
limitoptionalqueryintegermin 1 · max 50
cursoroptionalquerystringup to 256 chars
clientIdoptionalqueryid—
jobIdoptionalqueryid—
billedoptionalqueryboolean—

Returns

data: Expense[]. Pass meta.cursor back as cursor for the next page.

Example requestSample
curl -X GET "https://api.billingmart.com/v1/expenses" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY"

expenses

Create

POST/v1/expenses

Record an expense.

Scope
expenses:write
Effect
Writes a draft or record
MCP tool
record_expense
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
FieldTypeNotes
daterequiredstringmatches ^\d{4}-\d{2}-\d{2}$
amountrequiredobject—
amount.minorUnitsrequiredinteger—
amount.currencyrequiredCurrency—
rebillablerequiredboolean—
clientIdoptionalid—
projectRefoptionalstringup to 120 chars
categoryoptionalstringup to 80 chars
vendoroptionalstringup to 200 chars
descriptionoptionalstringup to 2000 chars
markupBasisPointsoptionalintegermin 0 · max 100000
businessIdoptionalid—

Returns

data: object

Example requestSample
curl -X POST "https://api.billingmart.com/v1/expenses" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"date":"<date>","amount":{"minorUnits":0,"currency":"USD"},"rebillable":false}'

mileage

List

GET/v1/mileage

List mileage entries, newest first.

Scope
mileage:read
Effect
Read only
MCP tool
list_mileage
Retries
Safe to repeat

Parameters

List parameters
NameInTypeNotes
limitoptionalqueryintegermin 1 · max 50
cursoroptionalquerystringup to 256 chars
clientIdoptionalqueryid—
jobIdoptionalqueryid—
billedoptionalqueryboolean—

Returns

data: Mileage[]. Pass meta.cursor back as cursor for the next page.

Example requestSample
curl -X GET "https://api.billingmart.com/v1/mileage" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY"

mileage

Create

POST/v1/mileage

Record a journey. Distance is in thousandths of the unit, as an integer.

Scope
mileage:write
Effect
Writes a draft or record
MCP tool
record_mileage
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
FieldTypeNotes
daterequiredstringmatches ^\d{4}-\d{2}-\d{2}$
distanceMillirequiredintegermin 1
distanceUnitrequiredenumOne of mile, kilometre
rebillablerequiredboolean—
clientIdoptionalid—
projectRefoptionalstringup to 120 chars
fromLocationoptionalstringup to 300 chars
toLocationoptionalstringup to 300 chars
purposeoptionalstringup to 500 chars
ratePerUnitoptionalobject—
ratePerUnit.minorUnitsrequiredinteger—
ratePerUnit.currencyrequiredCurrency—
businessIdoptionalid—

Returns

data: object

Example requestSample
curl -X POST "https://api.billingmart.com/v1/mileage" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"date":"<date>","distanceMilli":0,"distanceUnit":"mile","rebillable":false,"ratePerUnit":{"minorUnits":0,"currency":"USD"}}'

time

Update

PATCH/v1/time-entries/{entryId}

Correct an UNBILLED time entry. A billed one is refused; billed and billedInvoiceId are never accepted.

Scope
time:write
Effect
Writes a draft or record
MCP tool
update_time_entry
Retries
No Idempotency-Key on this route

Parameters

Update parameters
NameInTypeNotes
entryIdrequiredpathid—

Request body

JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.

Update request body
FieldTypeNotes
dateoptionalstringmatches ^\d{4}-\d{2}-\d{2}$
minutesoptionalintegermin 1 · max 1440
billableoptionalboolean—
clientIdoptionalid—
projectRefoptionalstringup to 120 chars
descriptionoptionalstringup to 2000 chars
hourlyRateoptionalobject—
hourlyRate.minorUnitsrequiredinteger—
hourlyRate.currencyrequiredCurrency—

Returns

data: TimeEntry

Errors this route can answer besides the shared ones: INVALID_TRANSITION.

Example requestSample
curl -X PATCH "https://api.billingmart.com/v1/time-entries/{entryId}" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hourlyRate":{"minorUnits":0,"currency":"USD"}}'

time

Start session

POST/v1/time-sessions

Start a timer for the signed-in person (one running at a time). Stopping it records a time entry. A repeated startRequestId answers the same timer.

Scope
time:write
Effect
Writes a draft or record
MCP tool
start_timer
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.

Start session request body
FieldTypeNotes
startRequestIdrequiredid—
clientIdoptionalid—
jobIdoptionalid—
projectRefoptionalstringup to 120 chars
businessIdoptionalid—

Returns

data: object

Errors this route can answer besides the shared ones: ALREADY_EXISTS, CLIENT_NOT_FOUND, CLIENT_ARCHIVED, PERMISSION_DENIED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/time-sessions" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"startRequestId":"<startRequestId>"}'

time

List sessions

GET/v1/time-sessions

The signed-in person’s timers and trips: the open ones by default, or stopped ones. Filter by kind to list only timers or only trips.

Scope
time:read
Effect
Read only
MCP tool
list_timers
Retries
Safe to repeat

Parameters

List sessions parameters
NameInTypeNotes
statusoptionalqueryenumOne of running, stopped
kindoptionalqueryenumOne of timer, trip

Returns

data: FieldSession[]. Pass meta.cursor back as cursor for the next page.

Errors this route can answer besides the shared ones: PERMISSION_DENIED.

Example requestSample
curl -X GET "https://api.billingmart.com/v1/time-sessions" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY"

time

Get session

GET/v1/time-sessions/{sessionId}

One of the signed-in person’s timers or trips by id: status, minutes, miles, client and job. Another person’s answers NOT_FOUND.

Scope
time:read
Effect
Read only
MCP tool
get_timer
Retries
Safe to repeat

Parameters

Get session parameters
NameInTypeNotes
sessionIdrequiredpathid—

Returns

data: FieldSession

Errors this route can answer besides the shared ones: NOT_FOUND, PERMISSION_DENIED.

Example requestSample
curl -X GET "https://api.billingmart.com/v1/time-sessions/{sessionId}" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY"

time

Pause session

POST/v1/time-sessions/{sessionId}/pause

Pause one of the signed-in person’s timers: the clock stops counting until it is resumed. A second pause answers the first. A trip cannot be paused.

Scope
time:write
Effect
Writes a draft or record
MCP tool
pause_timer
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours

Parameters

Pause session parameters
NameInTypeNotes
sessionIdrequiredpathid—

Returns

data: object

Errors this route can answer besides the shared ones: NOT_FOUND, INVALID_TRANSITION, PERMISSION_DENIED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/time-sessions/{sessionId}/pause" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

time

Resume session

POST/v1/time-sessions/{sessionId}/resume

Resume one of the signed-in person’s paused timers. A second resume answers the first.

Scope
time:write
Effect
Writes a draft or record
MCP tool
resume_timer
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours

Parameters

Resume session parameters
NameInTypeNotes
sessionIdrequiredpathid—

Returns

data: object

Errors this route can answer besides the shared ones: NOT_FOUND, INVALID_TRANSITION, PERMISSION_DENIED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/time-sessions/{sessionId}/resume" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

time

Stop session

POST/v1/time-sessions/{sessionId}/stop

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
NameInTypeNotes
sessionIdrequiredpathid—

Returns

data: object

Errors this route can answer besides the shared ones: NOT_FOUND, INVALID_TRANSITION, INVALID_KIND, PERMISSION_DENIED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/time-sessions/{sessionId}/stop" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

time

Stop all sessions

POST/v1/time-sessions/stop-all

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.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/time-sessions/stop-all" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

expenses

Update

PATCH/v1/expenses/{expenseId}

Correct an UNBILLED expense. A billed one is refused; billed and billedInvoiceId are never accepted.

Scope
expenses:write
Effect
Writes a draft or record
MCP tool
update_expense
Retries
No Idempotency-Key on this route

Parameters

Update parameters
NameInTypeNotes
expenseIdrequiredpathid—

Request body

JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.

Update request body
FieldTypeNotes
dateoptionalstringmatches ^\d{4}-\d{2}-\d{2}$
amountoptionalobject—
amount.minorUnitsrequiredinteger—
amount.currencyrequiredCurrency—
rebillableoptionalboolean—
clientIdoptionalid—
projectRefoptionalstringup to 120 chars
categoryoptionalstringup to 80 chars
vendoroptionalstringup to 200 chars
descriptionoptionalstringup to 2000 chars
markupBasisPointsoptionalintegermin 0 · max 100000

Returns

data: Expense

Errors this route can answer besides the shared ones: INVALID_TRANSITION.

Example requestSample
curl -X PATCH "https://api.billingmart.com/v1/expenses/{expenseId}" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":{"minorUnits":0,"currency":"USD"}}'

mileage

Update

PATCH/v1/mileage/{mileageId}

Correct an UNBILLED mileage entry. A billed one is refused; billed and billedInvoiceId are never accepted.

Scope
mileage:write
Effect
Writes a draft or record
MCP tool
update_mileage
Retries
No Idempotency-Key on this route

Parameters

Update parameters
NameInTypeNotes
mileageIdrequiredpathid—

Request body

JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.

Update request body
FieldTypeNotes
dateoptionalstringmatches ^\d{4}-\d{2}-\d{2}$
distanceMillioptionalintegermin 1
distanceUnitoptionalenumOne of mile, kilometre
rebillableoptionalboolean—
clientIdoptionalid—
projectRefoptionalstringup to 120 chars
fromLocationoptionalstringup to 300 chars
toLocationoptionalstringup to 300 chars
purposeoptionalstringup to 500 chars
ratePerUnitoptionalobject—
ratePerUnit.minorUnitsrequiredinteger—
ratePerUnit.currencyrequiredCurrency—

Returns

data: Mileage

Errors this route can answer besides the shared ones: INVALID_TRANSITION.

Example requestSample
curl -X PATCH "https://api.billingmart.com/v1/mileage/{mileageId}" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ratePerUnit":{"minorUnits":0,"currency":"USD"}}'

organizer

Create

POST/v1/organizer

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
FieldTypeNotes
contentTyperequiredenumOne of image/png, image/jpeg, image/webp, application/pdf
fileNameoptionalstringup to 200 chars
businessIdoptionalid—

Returns

data: object

Errors this route can answer besides the shared ones: BUSINESS_NOT_FOUND, AI_CONSENT_REQUIRED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/organizer" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"contentType":"image/png"}'

organizer

List

GET/v1/organizer

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
NameInTypeNotes
limitoptionalqueryintegermin 1 · max 50
cursoroptionalquerystringup to 256 chars
statusoptionalqueryenumOne 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
NameInTypeNotes
docIdrequiredpathid—

Returns

data: object

Errors this route can answer besides the shared ones: INVALID_TRANSITION, AI_CONSENT_REQUIRED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/organizer/{docId}/organize" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

organizer

Get

GET/v1/organizer/{docId}

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.

Scope
organizer:read
Effect
Read only
MCP tool
get_organizer_document
Retries
Safe to repeat

Parameters

Get parameters
NameInTypeNotes
docIdrequiredpathid—

Returns

data: OrganizerDoc

Example requestSample
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
NameInTypeNotes
docIdrequiredpathid—

Request body

JSON. Money is an integer count of minor units beside its currency; quantities are thousandths.

Confirm request body
FieldTypeNotes
kindrequiredenumOne of invoice, estimate, job, receipt, bill
amountrequiredobject—
amount.minorUnitsrequiredintegermin 1 · max 100000000000
amount.currencyrequiredCurrency—
businessIdoptionalid—
clientIdoptionalid—
vendorIdoptionalid—
vendorNameoptionalstringup to 200 chars
jobIdoptionalid—
jobLabeloptionalstringup to 200 chars
depositBasisPointsoptionalintegermin 1 · max 10000
descriptionoptionalstringup to 300 chars
documentNumberoptionalstringup to 60 chars
issueDateoptionalstring—
dueDateoptionalstring—
categoryoptionalstringup to 80 chars
notesoptionalstringup to 2000 chars
rebillableoptionalboolean—
lines[]optionalobject[]up to 50 items · at least 1
lines[].descriptionrequiredstringup to 300 chars
lines[].quantityMillirequiredintegermin 1 · max 1000000000
lines[].unitPriceMinorrequiredintegermin -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.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/organizer/{docId}/confirm" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"kind":"invoice","amount":{"minorUnits":0,"currency":"USD"}}'

organizer

Discard

POST/v1/organizer/{docId}/discard

Remove an organizer document that was not filed, and its file. A filed one is kept.

Scope
organizer:write
Effect
Writes a draft or record
MCP tool
discard_organizer_document
Retries
Send an Idempotency-Key; a repeat replays the stored answer for 24 hours

Parameters

Discard parameters
NameInTypeNotes
docIdrequiredpathid—

Returns

data: object

Errors this route can answer besides the shared ones: INVALID_TRANSITION.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/organizer/{docId}/discard" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

imports

Create

POST/v1/imports

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
FieldTypeNotes
entityrequiredenumOne of client, item, invoice, bill
businessIdoptionalid—
fileNameoptionalstringup to 255 chars
csvrequiredstringup to 262144 chars
mapping[]optionalobject[]up to 60 items
mapping[].columnrequiredstringup to 120 chars
mapping[].targetrequiredstringup to 40 chars
dateLayoutoptionalenumOne of iso, mdy, dmy
phoneCountryoptionalstringmatches ^[A-Za-z]{2}$
currencyoptionalCurrency—

Returns

data: object

Errors this route can answer besides the shared ones: BUSINESS_NOT_FOUND, VALIDATION_FAILED.

Example requestSample
curl -X POST "https://api.billingmart.com/v1/imports" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"entity":"client","csv":"<csv>"}'

imports

Get

GET/v1/imports/{importId}

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.

Scope
clients:read
Effect
Read only
MCP tool
get_import
Retries
Safe to repeat

Parameters

Get parameters
NameInTypeNotes
importIdrequiredpathid—

Returns

data: Import

Example requestSample
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.

Scope
clients:write
Effect
Writes a draft or record
MCP tool
discard_import
Retries
No Idempotency-Key on this route

Parameters

Discard parameters
NameInTypeNotes
importIdrequiredpathid—

Returns

data: Import

Example requestSample
curl -X DELETE "https://api.billingmart.com/v1/imports/{importId}" \
  -H "Authorization: Bearer $BILLINGMART_API_KEY"

Object

TimeEntry

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
FieldTypeNotes
idrequiredId—
tenantrequiredTenantRef—
clientIdoptionalId—
projectRefoptionalstringUntrusted textCarried by the API and MCP only inside the data envelope.
daterequiredDateOnly—
minutesrequiredintegerWhole minutes worked on this date.
descriptionoptionalstringUntrusted text—
userUidoptionalIdWho logged it. Taken from the verified token.
billablerequiredboolean—
hourlyRateoptionalMoneyRate per whole hour, in minor units. The line total is derived as round(minutes * rate / 60) by the one totals module.
billedoptionalbooleanSERVER-WRITTEN. Set exactly once, inside the transaction that adds the rebilled line to an invoice, so the same hour cannot be billed twice.
billedInvoiceIdoptionalId—
sourceoptionalEntrySourceHow 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.
fieldSessionIdoptionalIdSERVER-WRITTEN: the field session that made this tracked record.
overrideoptionalEntryOverrideSERVER-WRITTEN: set when a person shortened this tracked record.
createdAtrequiredIsoTimestamp—
updatedAtoptionalIsoTimestamp—
jobIdoptionalIdThe 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
FieldTypeNotes
idrequiredId—
tenantrequiredTenantRef—
clientIdoptionalId—
projectRefoptionalstringUntrusted textRendered as text; carried by the API and MCP only inside the data envelope.
daterequiredDateOnly—
categoryoptionalstringUntrusted text—
taxCategoryoptionalTaxCategoryCodeThe tax category a person confirmed (a code of the taxonomy). Never set by a suggestion alone.
taxCategoryVersionoptionalstringThe taxonomy edition taxCategory is a code of, e.g. us-sch-c-2026.
taxCategorySourceoptionalTaxCategorySource—
taxScheduleCodeoptionalTaxCategoryCodeThe 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.
taxScheduleLineoptionalstringThe form line of taxScheduleCode at confirmation, e.g. Line 8; absent where the category is not a line of the form.
vendoroptionalstringUntrusted text—
descriptionoptionalstringUntrusted text—
amountrequiredMoneyWhat was actually spent.
taxTreatmentoptionalTaxTreatment—
markupBasisPointsoptionalBasisPointsApplied 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.
receiptStoragePathoptionalstringCloud Storage path. Content-type and size are enforced by storage.rules, not just the UI.
rebillablerequiredboolean—
billedoptionalbooleanSERVER-WRITTEN. Set exactly once, inside the transaction that adds the rebilled line.
billedInvoiceIdoptionalId—
userUidoptionalId—
createdAtrequiredIsoTimestamp—
updatedAtoptionalIsoTimestamp—
jobIdoptionalIdThe work record this belongs to, when it does.
billIdoptionalIdThe 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
FieldTypeNotes
idrequiredId—
tenantrequiredTenantRef—
clientIdoptionalId—
projectRefoptionalstringUntrusted textRendered as text; carried by the API and MCP only inside the data envelope.
daterequiredDateOnly—
fromLocationoptionalstringUntrusted text—
toLocationoptionalstringUntrusted text—
purposeoptionalstringUntrusted text—
distanceMillirequiredintegerThousandths of distanceUnit. 12.4 miles is 12400.
distanceUnitrequiredDistanceUnit—
ratePerUnitoptionalMoneyRate per one whole mile or kilometre.
rebillablerequiredboolean—
billedoptionalbooleanSERVER-WRITTEN. Set exactly once.
billedInvoiceIdoptionalId—
userUidoptionalId—
sourceoptionalEntrySourceHow 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.
fieldSessionIdoptionalIdSERVER-WRITTEN: the field session that made this tracked record.
overrideoptionalEntryOverrideSERVER-WRITTEN: set when a person shortened this tracked record.
createdAtrequiredIsoTimestamp—
updatedAtoptionalIsoTimestamp—
jobIdoptionalIdThe 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
FieldTypeNotes
idrequiredId—
tenantrequiredTenantRef—
ownerUidrequiredIdThe person who started it: the verified ID token's uid, never the payload's. One person has at most one running session.
startRequestIdoptionalIdThe 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.
kindrequiredFieldSessionKind—
statusrequiredFieldSessionStatus—
clientIdoptionalIdThe client the work is for, when the person picked one.
jobRefoptionalJobRefThe job the work is for, copied from the invoice's job the person picked (a job is not a document: it is invoice.jobRef).
projectRefoptionalstringUntrusted textRendered as text; carried by the API and MCP only inside the data envelope.
startedAtrequiredIsoTimestampSERVER CLOCK at Start. The phone's counter runs from this, so it is right after a relaunch and with the phone locked.
pausedAtoptionalIsoTimestampSERVER CLOCK when the person last paused; present only while status is paused, removed at Resume.
pausedMsoptionalintegernow). The phone shows startedAt + pausedMs as the counter origin; Stop subtracts it from the minutes. Absent means 0.
endedAtoptionalIsoTimestampSERVER CLOCK at Stop (or at Discard).
lastPointAtoptionalIsoTimestampWhen the server last accepted points for a trip.
minutesoptionalintegerWhole minutes between startedAt and endedAt, derived by the server at Stop.
distanceMillioptionalintegerThousandths of distanceUnit, derived by the server at Stop over the accuracy- and speed-filtered points. A client-supplied distance is ignored.
distanceUnitoptionalDistanceUnitThe unit the distance was written in: the workspace's, at Stop.
pointCountoptionalintegerHow many points the server accepted (after dropping implausible and low-accuracy ones).
trackPolylineoptionalstringThe 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.
startPhotosoptionalFieldPhoto[]Photos added at Start, in the order added. At most 20, enforced by the server.
endPhotosoptionalFieldPhoto[]Photos added at Stop, in the order added. At most 20, enforced by the server.
timeEntryIdoptionalIdThe unbilled time entry Stop wrote, when it wrote one.
mileageIdoptionalIdThe unbilled mileage record Stop wrote, when it wrote one.
rawPointsExpireAtoptionalIsoTimestampSERVER-WRITTEN at Stop: 90 days later, the raw points in chunks are deleted and only trackPolyline stays.
createdAtrequiredIsoTimestamp—
updatedAtrequiredIsoTimestamp—
jobIdoptionalIdThe 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
FieldTypeNotes
idrequiredId—
tenantIdrequiredId—
ownerUidrequiredIdWho added it: the verified ID token's uid, or the credential id for an API key. Its files live under this id.
createdByrequiredWriteActorThe 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.
subjectUidoptionalIdFor 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.
businessIdoptionalIdThe business it was added for, when the person had one chosen. Filing may name another the person may act in.
sourcerequiredenumWhere it was added: the console, a conversation with the Agent, a phone's Capture tab, or REST v1 and MCP.
agentSessionIdoptionalIdThe Agent conversation it was dropped into, when it was.
statusrequiredenumawaitingUpload: created, its files not yet checked by the server. queued: organize accepted it. reading: the model is reading it. ready: read, candidates found.
filerequiredOrganizerFileThe 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.
classificationoptionalOrganizerClassification—
candidatesoptionalOrganizerCandidates—
failureoptionalOrganizerFailure—
filedoptionalOrganizerFiled—
attemptsoptionalintegerHow many times it was sent to the model.
leaseExpiresAtoptionalIsoTimestampWhile reading or filing: when a stalled run may be taken over.
expiresAtoptionalIsoTimestampWhen the 7-day sweep removes it and its files. Present until it is filed, then deleted.
createdAtrequiredIsoTimestamp—
updatedAtrequiredIsoTimestamp—

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
FieldTypeNotes
idrequiredId—
tenantIdrequiredId—
ownerUidrequiredIdWho brought the file in: the verified ID token's uid, or the credential id for an API key. The upload lives under this id.
createdByrequiredWriteActorThe credential that created the import, stamped by the server. SERVER-ONLY: REST v1 never returns it.
businessIdoptionalIdThe business the clients, items or invoices belong to. Required for items and invoices.
sourcerequiredenumWhere the file came in: an upload from the console, or CSV text sent to REST v1 or MCP.
entityrequiredenumWhat the file holds. One kind per file; an invoice or bill file is one row per line item.
layoutrequiredenumThe 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.
statusrequiredenummapping: 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.
fileNamerequiredstringUntrusted textThe file's name as uploaded.
fileHashrequiredstringSHA-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.
fileBytesrequiredinteger—
rowCountrequiredintegerData rows read, malformed ones included, blank ones not.
delimiteroptionalenumThe separator the file used, by name.
headersrequiredstring[]—
sampleoptionalImportSampleRow[]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.
currencyoptionalCurrencyThe one currency of the file's amounts. A file that mixes currencies is refused with its rows named.
dateLayoutoptionalenumHow 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.
phoneCountryoptionalCountryCodeThe 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.
mappingoptionalImportMappingEntry[]—
mappingSourceoptionalenumWhere the mapping came from. Whatever it was, a person confirmed it before the plan ran.
aiProposalIdoptionalIdThe aiProposals record of the model's mapping, when one was asked for.
planIdoptionalstringA hash of the file hash, the confirmed mapping and the settings. The write pass runs exactly this plan or refuses.
countsoptionalImportCounts—
errorsoptionalImportRowError[]The first rows that cannot be imported, each with its line. The count of all of them is counts.errors.
warningsoptionalImportWarning[]—
progressoptionalImportProgress—
createdAtrequiredIsoTimestamp—
updatedAtrequiredIsoTimestamp—
plannedAtoptionalIsoTimestamp—
finishedAtoptionalIsoTimestamp—
leaseExpiresAtoptionalIsoTimestampWhile 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.

Continue to Bills and vendors →

Try it against your sandbox

Create a bmk_test_ key in the console. It can only reach your sandbox workspace.

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