Developers
API reference

Paystubs

get/v1/paystubs

List paystubs

paystubs.listread tokenidempotent

The ledger's paystubs with every row read from them, newest pay date first. Stubs that could not be read (no pay date) come first.

Parameters

limit
integer · query
Page size, 1–200.
cursor
string | null · query
The next_cursor of the previous page.
status
string | null · query
Only paystubs in this state: pending, parsed, failed.
year
integer | null · query
Only paychecks paid in this year.
X-Organization-Id
string | null · header

Returns 200 · PaystubList

data
array of Paystub · required
has_more
boolean · required
next_cursor
string | null · required
Example
curl -X GET "https://api.lumaledger.app/v1/paystubs" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN"
post/v1/paystubs

Upload a paystub

paystubs.createwrite tokenidempotent

Upload a paystub as multipart/form-data. One stub is read before the answer (a few seconds). A payroll export holding many paychecks is split into one paystub each and read in the background: they come back pending, and reading says how many to wait for. A paycheck already on file is not added twice (duplicate).

Parameters

Idempotency-Key
string | null · header
Any unique string (a UUID is ideal). A retry with the same key returns the first attempt's response instead of doing the work twice. Keys are kept for 24 hours.
X-Organization-Id
string | null · header

Body · multipart/form-data

file
file · required
A paystub, or a payroll export of many, as PDF or image; at most 10 MB.

Returns 201 · PaystubUpload

paystubs
array of PaystubResult · required
Newest pay date first.
reading
integer · required
How many are still pending, being read in the background. Poll paystubs.get until it is 0.
split
boolean · required
True when the file held more than one paycheck.
Example
curl -X POST "https://api.lumaledger.app/v1/paystubs" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@path/to/file"

Try it isn't available for file uploads — use the curl example above.

delete/v1/paystubs/{paystub_id}

Delete a paystub

paystubs.deletewrite tokendestructiveidempotent

Delete a paystub, its rows and its file.

Parameters

paystub_id
integer · path · required
X-Organization-Id
string | null · header

Returns 204 with no body.

Example
curl -X DELETE "https://api.lumaledger.app/v1/paystubs/{paystub_id}" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN"
get/v1/paystubs/{paystub_id}

Get a paystub

paystubs.getread tokenidempotent

One paystub with every row read from it.

Parameters

paystub_id
integer · path · required
X-Organization-Id
string | null · header

Returns 200 · Paystub

created_at
datetime · required
currency
string · required
employee_name
string | null · required
employer_cost
Money | null · required
What the employer paid on top (its payroll taxes and contributions), never deducted from the employee.
employer_name
string | null · required
gross_pay
Money | null · required
hours
string | null · required
Hours paid, as a decimal string.
id
integer · required
imputed_pay
Money | null · required
Taxable benefits added to gross that were never cash.
lines
array of PaystubLine · required
mime_type
string · required
net_pay
Money | null · required
original_name
string | null · required
parse_error
string | null · required
Why the file could not be read at all.
parsed_at
datetime | null · required
pay_date
date | null · required
period_end
date | null · required
period_start
date | null · required
post_tax_deductions
Money | null · required
pre_tax_deductions
Money | null · required
reconcile_error
string | null · required
Set when the stub was read but its own totals do not add up.
reimbursements
Money | null · required
size_bytes
integer · required
source
string · required
status
string · required
pending (being read), parsed or failed (see parse_error).
taxes
Money | null · required
ytd_gross_pay
Money | null · required
ytd_net_pay
Money | null · required
Example
curl -X GET "https://api.lumaledger.app/v1/paystubs/{paystub_id}" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN"
get/v1/paystubs/{paystub_id}/download

Download a paystub's file

paystubs.downloadread tokenidempotent

A short-lived URL for the paystub's PDF or image. A stub cut out of a payroll export is its own file, just its pages.

Parameters

paystub_id
integer · path · required
X-Organization-Id
string | null · header

Returns 200 · Download

expires_at
datetime | null · required
When a signed url stops working. Null for a data: URL.
url
string · required
A signed HTTPS URL for the file, or a data: URL carrying the file itself when it is stored inline. Needs no credential.
Example
curl -X GET "https://api.lumaledger.app/v1/paystubs/{paystub_id}/download" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN"
post/v1/paystubs/{paystub_id}/reprocess

Read a paystub again

paystubs.reprocesswrite token

Read the file again, for a stub that failed or whose numbers did not add up. If the new reading is a paycheck already on file, this copy is dropped and the one on file is returned with duplicate.

Parameters

paystub_id
integer · path · required
X-Organization-Id
string | null · header

Returns 200 · PaystubResult

created_at
datetime · required
currency
string · required
duplicate
boolean · required
True when this turned out to be a paycheck already on file: the one already held is returned and the new copy was dropped.
employee_name
string | null · required
employer_cost
Money | null · required
What the employer paid on top (its payroll taxes and contributions), never deducted from the employee.
employer_name
string | null · required
gross_pay
Money | null · required
hours
string | null · required
Hours paid, as a decimal string.
id
integer · required
imputed_pay
Money | null · required
Taxable benefits added to gross that were never cash.
lines
array of PaystubLine · required
mime_type
string · required
net_pay
Money | null · required
original_name
string | null · required
parse_error
string | null · required
Why the file could not be read at all.
parsed_at
datetime | null · required
pay_date
date | null · required
period_end
date | null · required
period_start
date | null · required
post_tax_deductions
Money | null · required
pre_tax_deductions
Money | null · required
reconcile_error
string | null · required
Set when the stub was read but its own totals do not add up.
reimbursements
Money | null · required
size_bytes
integer · required
source
string · required
status
string · required
pending (being read), parsed or failed (see parse_error).
taxes
Money | null · required
ytd_gross_pay
Money | null · required
ytd_net_pay
Money | null · required
Example
curl -X POST "https://api.lumaledger.app/v1/paystubs/{paystub_id}/reprocess" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN"
get/v1/paystubs/breakdown

Break down a year of pay

paystubs.breakdownread tokenidempotent

Where a year's gross pay went (taxes, retirement, health, other deductions, net), by band, by employer and by month, from the stubs on file. Only what was uploaded is counted; reported_ytd_gross is the employer's own figure for the whole year so far.

Parameters

year
integer · query · required
The calendar year of the pay dates.
X-Organization-Id
string | null · header

Returns 200 · PayBreakdown

bands
array of BreakdownBand · required
employer_cost
Money · required
employers
array of BreakdownRow · required
gross
Money · required
imputed
Money · required
latest_pay_date
date | null · required
mixed_currency
boolean · required
True when the year's stubs are in more than one currency. Nothing is converted: the totals are plain sums.
months
array of BreakdownMonth · required
net
Money · required
post_tax
Money · required
pre_tax
Money · required
reimbursements
Money · required
reported_ytd_gross
Money | null · required
The employer's own year-to-date gross from the latest stub. It counts every pay period, including ones not uploaded, so the gap to gross is what is missing.
reported_ytd_net
Money | null · required
stub_count
integer · required
taxes
Money · required
year
integer · required
Example
curl -X GET "https://api.lumaledger.app/v1/paystubs/breakdown" \
  -H "Authorization: Bearer $LUMALEDGER_TOKEN"

Objects

BreakdownBand

Fields

amount
Money · required
group
string · required
rows
array of BreakdownRow · required

BreakdownMonth

Fields

deductions
Money · required
gross
Money · required
month
integer · required
1–12.
net
Money · required
taxes
Money · required

BreakdownRow

Fields

amount
Money · required
key
string · required
The concept key, or ?<printed wording> for a row that was not recognized.
label
string | null · required
The employer's wording, when there is no concept key.

Download

Where to fetch a file. Fetch it promptly: the URL stops working at expires_at, and asking again gives a fresh one.

Fields

expires_at
datetime | null · required
When a signed url stops working. Null for a data: URL.
url
string · required
A signed HTTPS URL for the file, or a data: URL carrying the file itself when it is stored inline. Needs no credential.

Money

An amount and its currency. `amount` is a base-10 string with two decimal places and an optional leading minus sign. Parse it with a decimal type, not a float.

Fields

amount
string · required
Pattern: ^-?\d+\.\d{2}$.
currency
string · required
ISO 4217 code. Pattern: ^[A-Z]{3}$.

PayBreakdown

Where a year's gross pay went, from the stubs on file.

Fields

bands
array of BreakdownBand · required
employer_cost
Money · required
employers
array of BreakdownRow · required
gross
Money · required
imputed
Money · required
latest_pay_date
date | null · required
mixed_currency
boolean · required
True when the year's stubs are in more than one currency. Nothing is converted: the totals are plain sums.
months
array of BreakdownMonth · required
net
Money · required
post_tax
Money · required
pre_tax
Money · required
reimbursements
Money · required
reported_ytd_gross
Money | null · required
The employer's own year-to-date gross from the latest stub. It counts every pay period, including ones not uploaded, so the gap to gross is what is missing.
reported_ytd_net
Money | null · required
stub_count
integer · required
taxes
Money · required
year
integer · required

Paystub

One paycheck and its gross-to-net. Amounts are in the stub's currency, or the ledger's base currency while it is unread.

Fields

created_at
datetime · required
currency
string · required
employee_name
string | null · required
employer_cost
Money | null · required
What the employer paid on top (its payroll taxes and contributions), never deducted from the employee.
employer_name
string | null · required
gross_pay
Money | null · required
hours
string | null · required
Hours paid, as a decimal string.
id
integer · required
imputed_pay
Money | null · required
Taxable benefits added to gross that were never cash.
lines
array of PaystubLine · required
mime_type
string · required
net_pay
Money | null · required
original_name
string | null · required
parse_error
string | null · required
Why the file could not be read at all.
parsed_at
datetime | null · required
pay_date
date | null · required
period_end
date | null · required
period_start
date | null · required
post_tax_deductions
Money | null · required
pre_tax_deductions
Money | null · required
reconcile_error
string | null · required
Set when the stub was read but its own totals do not add up.
reimbursements
Money | null · required
size_bytes
integer · required
source
string · required
status
string · required
pending (being read), parsed or failed (see parse_error).
taxes
Money | null · required
ytd_gross_pay
Money | null · required
ytd_net_pay
Money | null · required

PaystubLine

One row of the stub, as printed.

Fields

account_mask
string | null · required
Deposit rows: the last digits of the account paid into.
amount
Money · required
concept
string | null · required
What the row is, as a stable key (federal_income_tax, regular). Null when the wording was not recognized.
description
string · required
Exactly as the employer printed it.
group
string · required
The band of the gross-to-net breakdown it belongs to.
hours
string | null · required
Decimal string.
id
integer · required
kind
string · required
Which block of the stub it came from: earning, tax, deduction, deposit, …
line_no
integer · required
rate
string | null · required
Pay rate, as a decimal string (up to four places).
ytd_amount
Money | null · required

PaystubList

A page of paystubs, newest pay date first; unreadable ones lead.

Fields

data
array of Paystub · required
has_more
boolean · required
next_cursor
string | null · required

PaystubResult

Fields

created_at
datetime · required
currency
string · required
duplicate
boolean · required
True when this turned out to be a paycheck already on file: the one already held is returned and the new copy was dropped.
employee_name
string | null · required
employer_cost
Money | null · required
What the employer paid on top (its payroll taxes and contributions), never deducted from the employee.
employer_name
string | null · required
gross_pay
Money | null · required
hours
string | null · required
Hours paid, as a decimal string.
id
integer · required
imputed_pay
Money | null · required
Taxable benefits added to gross that were never cash.
lines
array of PaystubLine · required
mime_type
string · required
net_pay
Money | null · required
original_name
string | null · required
parse_error
string | null · required
Why the file could not be read at all.
parsed_at
datetime | null · required
pay_date
date | null · required
period_end
date | null · required
period_start
date | null · required
post_tax_deductions
Money | null · required
pre_tax_deductions
Money | null · required
reconcile_error
string | null · required
Set when the stub was read but its own totals do not add up.
reimbursements
Money | null · required
size_bytes
integer · required
source
string · required
status
string · required
pending (being read), parsed or failed (see parse_error).
taxes
Money | null · required
ytd_gross_pay
Money | null · required
ytd_net_pay
Money | null · required

PaystubUpload

What one uploaded file became. A payroll export is often a year of paychecks in one PDF, so it may be several paystubs.

Fields

paystubs
array of PaystubResult · required
Newest pay date first.
reading
integer · required
How many are still pending, being read in the background. Poll paystubs.get until it is 0.
split
boolean · required
True when the file held more than one paycheck.