Paystubs
/v1/paystubsList paystubs
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 | |
has_more boolean · required | |
next_cursor string | null · required |
curl -X GET "https://api.lumaledger.app/v1/paystubs" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/paystubsUpload a paystub
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 | 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. |
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.
/v1/paystubs/{paystub_id}Delete a paystub
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.
curl -X DELETE "https://api.lumaledger.app/v1/paystubs/{paystub_id}" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/paystubs/{paystub_id}Get a paystub
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 | What the employer paid on top (its payroll taxes and contributions), never deducted from the employee. |
employer_name string | null · required | |
gross_pay | |
hours string | null · required | Hours paid, as a decimal string. |
id integer · required | |
imputed_pay | Taxable benefits added to gross that were never cash. |
lines | |
mime_type string · required | |
net_pay | |
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 | |
pre_tax_deductions | |
reconcile_error string | null · required | Set when the stub was read but its own totals do not add up. |
reimbursements | |
size_bytes integer · required | |
source string · required | |
status string · required | pending (being read), parsed or failed (see parse_error). |
taxes | |
ytd_gross_pay | |
ytd_net_pay |
curl -X GET "https://api.lumaledger.app/v1/paystubs/{paystub_id}" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/paystubs/{paystub_id}/downloadDownload a paystub's file
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. |
curl -X GET "https://api.lumaledger.app/v1/paystubs/{paystub_id}/download" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/paystubs/{paystub_id}/reprocessRead a paystub again
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 | What the employer paid on top (its payroll taxes and contributions), never deducted from the employee. |
employer_name string | null · required | |
gross_pay | |
hours string | null · required | Hours paid, as a decimal string. |
id integer · required | |
imputed_pay | Taxable benefits added to gross that were never cash. |
lines | |
mime_type string · required | |
net_pay | |
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 | |
pre_tax_deductions | |
reconcile_error string | null · required | Set when the stub was read but its own totals do not add up. |
reimbursements | |
size_bytes integer · required | |
source string · required | |
status string · required | pending (being read), parsed or failed (see parse_error). |
taxes | |
ytd_gross_pay | |
ytd_net_pay |
curl -X POST "https://api.lumaledger.app/v1/paystubs/{paystub_id}/reprocess" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/paystubs/breakdownBreak down a year of pay
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 | |
employer_cost Money · required | |
employers | |
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 | |
net Money · required | |
post_tax Money · required | |
pre_tax Money · required | |
reimbursements Money · required | |
reported_ytd_gross | 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 | |
stub_count integer · required | |
taxes Money · required | |
year integer · required |
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 |
BreakdownMonth
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 | |
employer_cost Money · required | |
employers | |
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 | |
net Money · required | |
post_tax Money · required | |
pre_tax Money · required | |
reimbursements Money · required | |
reported_ytd_gross | 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 | |
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 | What the employer paid on top (its payroll taxes and contributions), never deducted from the employee. |
employer_name string | null · required | |
gross_pay | |
hours string | null · required | Hours paid, as a decimal string. |
id integer · required | |
imputed_pay | Taxable benefits added to gross that were never cash. |
lines | |
mime_type string · required | |
net_pay | |
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 | |
pre_tax_deductions | |
reconcile_error string | null · required | Set when the stub was read but its own totals do not add up. |
reimbursements | |
size_bytes integer · required | |
source string · required | |
status string · required | pending (being read), parsed or failed (see parse_error). |
taxes | |
ytd_gross_pay | |
ytd_net_pay |
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 |
PaystubList
A page of paystubs, newest pay date first; unreadable ones lead.
Fields
data | |
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 | What the employer paid on top (its payroll taxes and contributions), never deducted from the employee. |
employer_name string | null · required | |
gross_pay | |
hours string | null · required | Hours paid, as a decimal string. |
id integer · required | |
imputed_pay | Taxable benefits added to gross that were never cash. |
lines | |
mime_type string · required | |
net_pay | |
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 | |
pre_tax_deductions | |
reconcile_error string | null · required | Set when the stub was read but its own totals do not add up. |
reimbursements | |
size_bytes integer · required | |
source string · required | |
status string · required | pending (being read), parsed or failed (see parse_error). |
taxes | |
ytd_gross_pay | |
ytd_net_pay |
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 | 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. |