Developers

The payed.me API

Everything you can do to a document or a record in the portal, your own software can do over HTTP. Create invoices from your own system, keep a client list in step with your CRM, push tracked hours in at the end of the week.

Base URL

https://api.payed.me/api

Availability

API tokens are included from the Professional plan. Every endpoint also stays behind whatever plan already gated it in the portal — a token never reaches further than your own account does.

Getting started

Authenticating

Create a token in the portal underSettings → API tokens. It is shown once, at the moment you create it, and never again — we store only a hash of it, so nobody can recover it for you afterwards. Keep it where you keep your other secrets, and if you lose it, revoke it and create another.

Send it on every request as a bearer token:

curl https://api.payed.me/api/invoices \
  -H "Authorization: Bearer pm_live_your_token_here"

A token is accepted in that header and nowhere else — not in a cookie, not in a query string. It identifies your account, so requests made with it see exactly the invoices, clients and records you see when you sign in.

Boundaries

What a token cannot do

A token reaches documents and records. It does not reach anything that would let it entrench itself or change what your account is:

  • It cannot create another token, or revoke one. If a token leaks, revoking it in the portal ends it — there is no way for the holder to mint a replacement.
  • It cannot sign in, change your password, or touch your personal details.
  • It cannot invite or remove colleagues. Team management is a portal action.
  • It cannot change your subscription, start a checkout or cancel a plan.
  • It cannot edit your settings or your invoice templates.

Anything not listed on this page answers 403. That is the default, not an exception: an endpoint has to be published deliberately before a token can reach it.

Conventions

Things that are true of every endpoint

Read this once and the reference below reads itself.

Every list endpoint returns a two-element array

Not an object. A list response is an array whose first element is the array of rows and whose second element is thetotal number of rows matching your filters, ignoring limitand offset. That total is what you page against.

GET /invoices?limit=2

[[{"id": "b81d4e77-…", "number": "INV-2026-014"}, {"id": "0c92f13a-…", "number": "INV-2026-013"}], 42]

Two rows came back; the total says 42 match. It is the single easiest thing to get wrong about this API, so it is the first thing on this page.

Paging

On the list endpoints, limitand offset are passed straight through to the database withno default and no maximum. Omitting limit returns every matching row, however many that is — always send one.

On GET /invoices/dashboard/customer-revenue the same parameter means something else: it is clamped to between 1 and 8, and defaults to 5. It is the number of clients in the breakdown, not a page size.

Filtering

  • search is a case-insensitive substring match, applied across a set of columns chosen per resource — an invoice search looks at its number, reference, status, type, currency, total and the client's name.
  • dateFrom anddateTo accept eitherYYYY-MM-DD or a full ISO timestamp, and bound that resource's own principal date column.dateTo is snapped to the end of that day, so a range ending today includes today.That column is createdAton every resource except two: expenses range overspentAt and mileage overtravelledOn — the date the thing happened, not the date it was entered. Note that invoices range over createdAt, not their issue or due date.
  • status takes both forms: repeat it (?status=draft&status=sent) or comma-separate it (?status=draft,sent). The accepted values are that resource's own statuses — the create body's status field in the reference below lists them where a resource has them.On three resources it does not filter a status at all, because they have none: on expenses and inventory it filterscategory, and on mileage it filters vehicleType. The parameter is still spelledstatus on all three.A value that is not one of them is dropped, not rejected, so a filter made entirely of unrecognised values behaves as no filter at all and you get everything back.
  • userId appears in the reference on a few list endpoints, butit does nothing for you. It is an administrator parameter for reading across accounts, and a token is never an administrator, so it is ignored rather than refused. Your requests already see only your own records — that is what the token scopes them to.

Ids, money and dates

  • Every record id is a UUID. Ids you send in a body are validated as one; the reference below marks those fieldsuuid.
  • Amounts are ordinary decimal numbers in the major unit —1265.50, not126550 — to at most two decimal places. currencyis a three-letter code from a fixed set, listed on the create bodies below. A line'svatRate is a percentage, so 20 means 20%.
  • On an invoice you do not send totals.totalAmount andtotalVat are computed from the lines on every create and update, and overwrite whatever you sent.
  • Dates are ISO — YYYY-MM-DDor a full timestamp.

A field we do not recognise is dropped, not refused

Request bodies are validated against the field list in the reference below, and any property that is not on it is stripped before the handler sees it. That is quiet by design, and it is the one failure mode to watch for: a mistyped field name does not produce an error, it produces a record missing a value. If something you sent did not stick, check its spelling against the reference first.

Worked example

Client to invoice to inbox, in three calls

Paste these in order with a real token. Every field name below is checked against the reference at build time.

01

Create the client

Everything except `paymentRemindersEnabled` is required. The response carries the client `id` you need for the next call.

curl -X POST https://api.payed.me/api/customers \
  -H "Authorization: Bearer pm_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Ridgeway Joinery Ltd",
  "email": "accounts@ridgeway-joinery.example",
  "phoneNumber": "+44 20 7946 0812",
  "website": "https://ridgeway-joinery.example",
  "accountNumber": "RJL-0041",
  "companyRegNumber": "09876543",
  "companyTaxNumber": "GB123456789",
  "paymentRemindersEnabled": true,
  "primaryPerson": {
    "firstname": "Dana",
    "lastname": "Okafor",
    "email": "dana@ridgeway-joinery.example"
  },
  "billingAddress": {
    "line": "14 Fenwick Road",
    "city": "Leeds",
    "state": "West Yorkshire",
    "postcode": "LS8 2AB",
    "country": "GB"
  },
  "deliveryAddress": {
    "line": "14 Fenwick Road",
    "city": "Leeds",
    "state": "West Yorkshire",
    "postcode": "LS8 2AB",
    "country": "GB"
  }
}'

Response (abridged)

{
  "id": "3f6a1c58-9b2d-4f0e-a7c1-8d5e2b41f930",
  "name": "Ridgeway Joinery Ltd",
  "email": "accounts@ridgeway-joinery.example",
  ...
}
02

Invoice them

Use the client `id` from step one as `customerId`. You do not send totals — `totalAmount` and `totalVat` are computed from the lines and overwrite anything you send. `vatRate` is a percentage, so 20 means 20%.

curl -X POST https://api.payed.me/api/invoices \
  -H "Authorization: Bearer pm_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
  "customerId": "3f6a1c58-9b2d-4f0e-a7c1-8d5e2b41f930",
  "number": "INV-2026-014",
  "reference": "Kitchen fit-out, phase 1",
  "currency": "GBP",
  "dueDate": "2026-10-09",
  "items": [
    {
      "name": "Cabinetry install",
      "description": "3 days on site",
      "qty": 3,
      "price": 480,
      "vatRate": 20
    },
    {
      "name": "Materials",
      "qty": 1,
      "price": 1265.5,
      "vatRate": 20
    }
  ]
}'

Response (abridged)

{
  "id": "b81d4e77-3a05-42c9-9f6b-1c0a7e5d2384",
  "number": "INV-2026-014",
  "status": "draft",
  "currency": "GBP",
  "totalAmount": 3246.60,
  "totalVat": 541.10,
  ...
}
03

Email it to them

No body. The PDF is rendered and attached server-side, and the mail goes to the client’s email address. The answer is 201 with `{"ksef": null}` once the email has gone. On an account that files to KSeF (a Polish issuer with a KSeF token added in the portal’s Account settings) it is `{"ksef": "queued"}` instead: the invoice is queued for KSeF and the email goes out after KSeF accepts it.

curl -X POST https://api.payed.me/api/invoices/b81d4e77-3a05-42c9-9f6b-1c0a7e5d2384/send \
  -H "Authorization: Bearer pm_live_your_token_here"

Response (abridged)

{
  "ksef": null
}
Reference

Endpoints

Every published route, with its parameters and body fields. Generated from the API itself.

Invoices

ON EVERY PLAN

Create, send and track invoices, including credit notes — a credit note is an invoice with a negative total and is served by these same endpoints. `bankAccount` must be one of the bank accounts saved in your Account settings: its `number` is compared ignoring spaces and hyphens and case, and a `swift`, when you send one, must match that saved account’s; anything else answers 400 `BANK_ACCOUNT_NOT_SAVED`. An invoice’s unchanged stored account always re-saves, even if it was later removed from settings, and the field is cleared on credit notes, receipts and self-billed invoices. On an account that files to KSeF, sending an invoice files it and emails it after KSeF accepts it, and a non-draft create or update files it without the email. While KSeF is filing an invoice or has accepted it, only its payment status may change: any other edit, a move back to draft or deleted, and a delete answer 409 `KSEF_INVOICE_LOCKED`. The KSeF token settings and the UPO download are portal-only.

GET/api/invoicesList invoices

Query

  • limit string
  • offset string
  • customerId string
  • search string
  • userId string
  • dateFrom string
  • dateTo string
  • status string
POST/api/invoicesCreate an invoice

Body — InvoiceAddition

FieldTypeRequiredConstraints
advanceAmountnumberoptionalminimum 0; at most 2 decimal place(s)
advanceInvoiceIdsarray of uuidoptionalat most 100 entries
advancePaymentsarray of AdvancePaymentInputoptionalat most 31 entries
amountnumberoptionalmust be positive; at most 2 decimal place(s)
dateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
fxRatenumberoptionalat most 6 decimal place(s)
bankAccountBankAccountInputoptional
bankNamestringoptionalmax length 256
descriptionstringoptionalmax length 256
numberstringrequireda valid IBAN (checksum), or 1-34 letters and digits; spaces and hyphens removed. For a Polish issuer, 20-30 digits must be a valid 26-digit NRB, and a PL prefix must be a valid PL IBAN (checked on a new or changed account)
ownBankstringoptionalone of: 1, 2, 3
swiftstringoptionalmust match /^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/
correctionReasonstringoptionalmax length 256
correctionTypenumberoptionalone of: 1, 2, 3
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
deliveryDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
dueDateISO daterequired
exemptionBasisstringoptionalmax length 256
exemptionBasisKindstringoptionalone of: act, directive, other
fiscalReceiptbooleanoptional
fxDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
fxFromstringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
fxRatenumeric stringoptional
fxRefstringoptionalmax length 64
fxSourcestringoptionalone of: nbp, manual, ecb
fxTostringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
issueDateISO dateoptional
itemsarray of InvoiceItemAdditionrequired
accountstringoptionalone of: 200 - Sales, 260 - Other Revenue, 270 - Interest Income
annex15booleanoptional
descriptionstringoptional
discountPercentnumberoptionalmaximum 100; minimum 0; at most 2 decimal place(s)
eServicebooleanoptional
excisenumberoptionalat most 2 decimal place(s)
gtustringoptionalone of: GTU_01, GTU_02, GTU_03, GTU_04, GTU_05, GTU_06, GTU_07, GTU_08, GTU_09, GTU_10, GTU_11, GTU_12, GTU_13
kindstringoptionalone of: goods, service
namestringrequired
ossRatenumberoptionalmaximum 100; minimum 0; at most 2 decimal place(s)
pricenumberrequiredat most 2 decimal place(s)
procedurestringoptionalone of: IED, I_42, I_63, B_SPV, B_SPV_DOSTAWA, B_MPV_PROWIZJA
qtynumberrequiredat most 2 decimal place(s)
supplyDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
unitstringoptionalmax length 256
vatRatenumber or VAT code (zw, np, oo)requiredat most 2 decimal place(s); from 0 to 100
marginProcedurestringoptionalone of: travel, used, art, antiques
newTransportNewTransportInputoptional
art42_5booleanrequired
vehiclesarray of NstVehicleInputrequiredat most 100 entries
colourstringoptionalmax length 256
firstUsestringrequiredmust match /^\d{4}-\d{2}-\d{2}$/
hoursstringoptionalmax length 256
hullNumberstringoptionalmax length 256
idstringoptionalmax length 256
idKindstringoptionalone of: vin, body, chassis, frame
lineintegerrequiredminimum 1
makestringoptionalmax length 256
mileagestringoptionalmax length 256
modelstringoptionalmax length 256
registrationstringoptionalmax length 256
serialNumberstringoptionalmax length 256
typestringrequiredone of: land, water, air
vehicleTypestringoptionalmax length 256
yearstringoptionalmax length 256
numberstringrequired
paidDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
partialPaymentsarray of PartialPaymentInputoptionalat most 100 entries
amountnumberoptionalmust be positive; at most 2 decimal place(s)
dateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
formstringoptionalone of: cash, card, voucher, cheque, credit, transfer, mobile, other
formDescriptionstringoptionalmax length 256
paymentDescriptionstringoptionalmax length 256
paymentFormstringoptionalone of: cash, card, voucher, cheque, credit, transfer, mobile, other
periodFromISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
periodToISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
referencestringrequired
relatedPartybooleanoptional
selfBillingbooleanoptional
skontoAmountstringoptionalmax length 256
skontoConditionsstringoptionalmax length 256
sourceExpenseIdsarray of uuidoptionalat most 200 entries
sourceInvoiceIduuidoptional
sourceInvoiceIdsarray of uuidoptional
sourceMileageIdsarray of uuidoptionalat most 200 entries
sourceTaskIdsarray of uuidoptionalat most 200 entries
splitPaymentbooleanoptional
statusstringoptionalone of: draft, sent, paid, deleted
templateIduuidoptional
thirdPartiesarray of ThirdPartyInputoptionalat most 100 entries
addressLinestringoptionalmax length 512
citystringoptionalmax length 256
countrystringoptionalmust match /^[A-Z]{2}$/
namestringrequiredmax length 512
postcodestringoptionalmax length 256
rolestringrequiredone of: 1, 2, 3, 4, 6, 8, 10, 11, other
roleDescriptionstringoptionalmax length 256
sharenumberoptionalmaximum 100; minimum 0; at most 6 decimal place(s)
taxNumberstringoptionalmax length 50
triangularbooleanoptional
typestringoptionalone of: invoice, credit_invoice, receipt, advance, settlement
GET/api/invoices/{invoiceId}Fetch one invoice

Path invoiceId

PUT/api/invoices/{invoiceId}Update an invoice

Path invoiceId

Body — InvoiceAddition

FieldTypeRequiredConstraints
advanceAmountnumberoptionalminimum 0; at most 2 decimal place(s)
advanceInvoiceIdsarray of uuidoptionalat most 100 entries
advancePaymentsarray of AdvancePaymentInputoptionalat most 31 entries
amountnumberoptionalmust be positive; at most 2 decimal place(s)
dateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
fxRatenumberoptionalat most 6 decimal place(s)
bankAccountBankAccountInputoptional
bankNamestringoptionalmax length 256
descriptionstringoptionalmax length 256
numberstringrequireda valid IBAN (checksum), or 1-34 letters and digits; spaces and hyphens removed. For a Polish issuer, 20-30 digits must be a valid 26-digit NRB, and a PL prefix must be a valid PL IBAN (checked on a new or changed account)
ownBankstringoptionalone of: 1, 2, 3
swiftstringoptionalmust match /^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/
correctionReasonstringoptionalmax length 256
correctionTypenumberoptionalone of: 1, 2, 3
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
deliveryDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
dueDateISO daterequired
exemptionBasisstringoptionalmax length 256
exemptionBasisKindstringoptionalone of: act, directive, other
fiscalReceiptbooleanoptional
fxDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
fxFromstringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
fxRatenumeric stringoptional
fxRefstringoptionalmax length 64
fxSourcestringoptionalone of: nbp, manual, ecb
fxTostringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
issueDateISO dateoptional
itemsarray of InvoiceItemAdditionrequired
accountstringoptionalone of: 200 - Sales, 260 - Other Revenue, 270 - Interest Income
annex15booleanoptional
descriptionstringoptional
discountPercentnumberoptionalmaximum 100; minimum 0; at most 2 decimal place(s)
eServicebooleanoptional
excisenumberoptionalat most 2 decimal place(s)
gtustringoptionalone of: GTU_01, GTU_02, GTU_03, GTU_04, GTU_05, GTU_06, GTU_07, GTU_08, GTU_09, GTU_10, GTU_11, GTU_12, GTU_13
kindstringoptionalone of: goods, service
namestringrequired
ossRatenumberoptionalmaximum 100; minimum 0; at most 2 decimal place(s)
pricenumberrequiredat most 2 decimal place(s)
procedurestringoptionalone of: IED, I_42, I_63, B_SPV, B_SPV_DOSTAWA, B_MPV_PROWIZJA
qtynumberrequiredat most 2 decimal place(s)
supplyDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
unitstringoptionalmax length 256
vatRatenumber or VAT code (zw, np, oo)requiredat most 2 decimal place(s); from 0 to 100
marginProcedurestringoptionalone of: travel, used, art, antiques
newTransportNewTransportInputoptional
art42_5booleanrequired
vehiclesarray of NstVehicleInputrequiredat most 100 entries
colourstringoptionalmax length 256
firstUsestringrequiredmust match /^\d{4}-\d{2}-\d{2}$/
hoursstringoptionalmax length 256
hullNumberstringoptionalmax length 256
idstringoptionalmax length 256
idKindstringoptionalone of: vin, body, chassis, frame
lineintegerrequiredminimum 1
makestringoptionalmax length 256
mileagestringoptionalmax length 256
modelstringoptionalmax length 256
registrationstringoptionalmax length 256
serialNumberstringoptionalmax length 256
typestringrequiredone of: land, water, air
vehicleTypestringoptionalmax length 256
yearstringoptionalmax length 256
numberstringrequired
paidDateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
partialPaymentsarray of PartialPaymentInputoptionalat most 100 entries
amountnumberoptionalmust be positive; at most 2 decimal place(s)
dateISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
formstringoptionalone of: cash, card, voucher, cheque, credit, transfer, mobile, other
formDescriptionstringoptionalmax length 256
paymentDescriptionstringoptionalmax length 256
paymentFormstringoptionalone of: cash, card, voucher, cheque, credit, transfer, mobile, other
periodFromISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
periodToISO dateoptionalmust match /^\d{4}-\d{2}-\d{2}$/
referencestringrequired
relatedPartybooleanoptional
selfBillingbooleanoptional
skontoAmountstringoptionalmax length 256
skontoConditionsstringoptionalmax length 256
sourceExpenseIdsarray of uuidoptionalat most 200 entries
sourceInvoiceIduuidoptional
sourceInvoiceIdsarray of uuidoptional
sourceMileageIdsarray of uuidoptionalat most 200 entries
sourceTaskIdsarray of uuidoptionalat most 200 entries
splitPaymentbooleanoptional
statusstringoptionalone of: draft, sent, paid, deleted
templateIduuidoptional
thirdPartiesarray of ThirdPartyInputoptionalat most 100 entries
addressLinestringoptionalmax length 512
citystringoptionalmax length 256
countrystringoptionalmust match /^[A-Z]{2}$/
namestringrequiredmax length 512
postcodestringoptionalmax length 256
rolestringrequiredone of: 1, 2, 3, 4, 6, 8, 10, 11, other
roleDescriptionstringoptionalmax length 256
sharenumberoptionalmaximum 100; minimum 0; at most 6 decimal place(s)
taxNumberstringoptionalmax length 50
triangularbooleanoptional
typestringoptionalone of: invoice, credit_invoice, receipt, advance, settlement
DELETE/api/invoices/{invoiceId}Delete an invoice

Path invoiceId

GET/api/invoices/{invoiceId}/printDownload the PDF

Path invoiceId

Responds with application/pdf and a Content-Disposition: attachment header — not JSON.

POST/api/invoices/{invoiceId}/sendEmail it to the client

Path invoiceId

POST/api/invoices/draft-from-sourcesDraft an invoice from tracked work, expenses or mileage

Body — InvoiceDraftRequest

FieldTypeRequiredConstraints
expenseIdsarray of uuidoptionalat most 200 entries
mileageIdsarray of uuidoptionalat most 200 entries
taskIdsarray of uuidoptionalat most 200 entries
GET/api/invoices/dashboard/statsTotals by status
GET/api/invoices/dashboard/revenueRevenue over time

Query

  • currency string
GET/api/invoices/dashboard/unbilledWork not yet invoiced

Query

  • currency string
GET/api/invoices/dashboard/customer-revenueRevenue by client

Query

  • currency string
  • limit number

Quotes

ON EVERY PLAN

Quotes from draft to accepted, rejected or expired.

GET/api/quotesList quotes

Query

  • limit string
  • offset string
  • customerId string
  • search string
  • userId string
  • dateFrom string
  • dateTo string
  • status string
POST/api/quotesCreate a quote

Body — QuoteAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
expiryDateISO dateoptional
issueDateISO dateoptional
itemsarray of QuoteItemAdditionrequired
accountstringoptionalone of: 200 - Sales, 260 - Other Revenue, 270 - Interest Income
descriptionstringoptional
namestringrequired
pricenumberrequiredat most 2 decimal place(s)
qtynumberrequiredat most 2 decimal place(s)
vatRatenumberrequiredmaximum 100; minimum 0; at most 2 decimal place(s)
notesstringoptional
numberstringrequiredmax length 255
referencestringrequiredmax length 255
statusstringoptionalone of: draft, sent, accepted, rejected, expired
templateIduuidoptional
GET/api/quotes/{quoteId}Fetch one quote

Path quoteId

PUT/api/quotes/{quoteId}Update a quote

Path quoteId

Body — QuoteAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
expiryDateISO dateoptional
issueDateISO dateoptional
itemsarray of QuoteItemAdditionrequired
accountstringoptionalone of: 200 - Sales, 260 - Other Revenue, 270 - Interest Income
descriptionstringoptional
namestringrequired
pricenumberrequiredat most 2 decimal place(s)
qtynumberrequiredat most 2 decimal place(s)
vatRatenumberrequiredmaximum 100; minimum 0; at most 2 decimal place(s)
notesstringoptional
numberstringrequiredmax length 255
referencestringrequiredmax length 255
statusstringoptionalone of: draft, sent, accepted, rejected, expired
templateIduuidoptional
DELETE/api/quotes/{quoteId}Delete a quote

Path quoteId

GET/api/quotes/{quoteId}/printDownload the PDF

Path quoteId

Responds with application/pdf and a Content-Disposition: attachment header — not JSON.

POST/api/quotes/{quoteId}/sendEmail it to the client

Path quoteId

GET/api/quotes/dashboard/statsTotals by status

Clients

ON EVERY PLAN

The people and companies you bill. Your plan caps how many you can save — the API answers HTTP 402 when you reach it, exactly as the portal does.

GET/api/customersList clients

Query

  • limit string
  • offset string
  • userId string
  • search string
  • dateFrom string
  • dateTo string
POST/api/customersCreate a client

Body — CustomerCreateData

FieldTypeRequiredConstraints
accountNumberstringrequired
billingAddressAddressDatarequired
citystringrequired
countrystringrequired
linestringrequired
postcodestringrequired
statestringrequired
companyRegNumberstringrequired
companyTaxNumberstringrequireda valid Polish NIP (10 digits, checksum) when taxCountry is PL
deliveryAddressAddressDatarequired
citystringrequired
countrystringrequired
linestringrequired
postcodestringrequired
statestringrequired
emailemailrequired
namestringrequired
paymentRemindersEnabledbooleanoptional
phoneNumberstringrequired
primaryPersonPersonDetailsDatarequired
emailemailrequired
firstnamestringrequired
lastnamestringrequired
taxCountrystringoptionalone of: AF, AX, AL, DZ, AD, AO, AI, AQ, AG, AN, SA, AR, AM, AW, AU, AT, AZ, BS, BH, BD, BB, BE, BZ, BJ, BM, BT, BY, BO, BQ, BA, BW, BR, BN, IO, BG, BF, BI, XC, CL, CN, HR, CW, CY, TD, ME, DK, DM, DO, DJ, EG, EC, ER, EE, ET, FK, FJ, PH, FI, FR, TF, GA, GM, GH, GI, GR, GD, GL, GE, GU, GG, GY, GF, GP, GT, GN, GQ, GW, HT, ES, HN, HK, IN, ID, IQ, IR, IE, IS, IL, JM, JP, YE, JE, JO, KY, KH, CM, CA, QA, KZ, KE, KG, KI, CO, KM, CG, CD, KP, XK, CR, CU, KW, LA, LS, LB, LR, LY, LI, LT, LV, LU, MK, MG, YT, MO, MW, MV, MY, ML, MT, MP, MA, MQ, MR, MU, MX, XL, FM, UM, MD, MC, MN, MS, MZ, MM, NA, NR, NP, NL, DE, NE, NG, NI, NU, NF, NO, NC, NZ, PS, OM, PK, PW, PA, PG, PY, PE, PN, PF, PL, GS, PT, PR, CF, CZ, KR, ZA, RE, RU, RO, RW, EH, BL, KN, LC, MF, VC, SV, WS, AS, SM, SN, RS, SC, SL, SG, SK, SI, SO, LK, PM, US, SZ, SD, SS, SR, SJ, SH, SY, CH, SE, TJ, TH, TW, TZ, TG, TK, TO, TT, TN, TR, TM, TV, UG, UA, UY, UZ, VU, WF, VA, HU, VE, GB, VN, IT, TL, CI, BV, CX, IM, SX, CK, VI, VG, HM, CC, MH, FO, SB, ST, TC, ZM, CV, ZW, AE, XI
websitestringrequired
GET/api/customers/{customerId}Fetch one client

Path customerId

PUT/api/customers/{customerId}Update a client

Path customerId

Body — CustomerCreateData

FieldTypeRequiredConstraints
accountNumberstringrequired
billingAddressAddressDatarequired
citystringrequired
countrystringrequired
linestringrequired
postcodestringrequired
statestringrequired
companyRegNumberstringrequired
companyTaxNumberstringrequireda valid Polish NIP (10 digits, checksum) when taxCountry is PL
deliveryAddressAddressDatarequired
citystringrequired
countrystringrequired
linestringrequired
postcodestringrequired
statestringrequired
emailemailrequired
namestringrequired
paymentRemindersEnabledbooleanoptional
phoneNumberstringrequired
primaryPersonPersonDetailsDatarequired
emailemailrequired
firstnamestringrequired
lastnamestringrequired
taxCountrystringoptionalone of: AF, AX, AL, DZ, AD, AO, AI, AQ, AG, AN, SA, AR, AM, AW, AU, AT, AZ, BS, BH, BD, BB, BE, BZ, BJ, BM, BT, BY, BO, BQ, BA, BW, BR, BN, IO, BG, BF, BI, XC, CL, CN, HR, CW, CY, TD, ME, DK, DM, DO, DJ, EG, EC, ER, EE, ET, FK, FJ, PH, FI, FR, TF, GA, GM, GH, GI, GR, GD, GL, GE, GU, GG, GY, GF, GP, GT, GN, GQ, GW, HT, ES, HN, HK, IN, ID, IQ, IR, IE, IS, IL, JM, JP, YE, JE, JO, KY, KH, CM, CA, QA, KZ, KE, KG, KI, CO, KM, CG, CD, KP, XK, CR, CU, KW, LA, LS, LB, LR, LY, LI, LT, LV, LU, MK, MG, YT, MO, MW, MV, MY, ML, MT, MP, MA, MQ, MR, MU, MX, XL, FM, UM, MD, MC, MN, MS, MZ, MM, NA, NR, NP, NL, DE, NE, NG, NI, NU, NF, NO, NC, NZ, PS, OM, PK, PW, PA, PG, PY, PE, PN, PF, PL, GS, PT, PR, CF, CZ, KR, ZA, RE, RU, RO, RW, EH, BL, KN, LC, MF, VC, SV, WS, AS, SM, SN, RS, SC, SL, SG, SK, SI, SO, LK, PM, US, SZ, SD, SS, SR, SJ, SH, SY, CH, SE, TJ, TH, TW, TZ, TG, TK, TO, TT, TN, TR, TM, TV, UG, UA, UY, UZ, VU, WF, VA, HU, VE, GB, VN, IT, TL, CI, BV, CX, IM, SX, CK, VI, VG, HM, CC, MH, FO, SB, ST, TC, ZM, CV, ZW, AE, XI
websitestringrequired
DELETE/api/customers/{customerId}Delete a client

Path customerId

Receipts

FROM BASIC

Receipts you issue against payments received.

GET/api/receiptsList receipts

Query

  • limit string
  • offset string
  • customerId string
  • search string
  • userId string
  • dateFrom string
  • dateTo string
  • status string
POST/api/receiptsCreate a receipt

Body — ReceiptAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
invoiceIduuidoptional
issueDateISO dateoptional
itemsarray of ReceiptItemAdditionrequired
accountstringoptionalone of: 200 - Sales, 260 - Other Revenue, 270 - Interest Income
descriptionstringoptional
namestringrequired
pricenumberrequiredat most 2 decimal place(s)
qtynumberrequiredat most 2 decimal place(s)
vatRatenumberrequiredmaximum 100; minimum 0; at most 2 decimal place(s)
notesstringoptional
numberstringrequired
referencestringrequired
statusstringoptionalone of: draft, issued, sent
templateIduuidoptional
GET/api/receipts/{receiptId}Fetch one receipt

Path receiptId

PUT/api/receipts/{receiptId}Update a receipt

Path receiptId

Body — ReceiptAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
invoiceIduuidoptional
issueDateISO dateoptional
itemsarray of ReceiptItemAdditionrequired
accountstringoptionalone of: 200 - Sales, 260 - Other Revenue, 270 - Interest Income
descriptionstringoptional
namestringrequired
pricenumberrequiredat most 2 decimal place(s)
qtynumberrequiredat most 2 decimal place(s)
vatRatenumberrequiredmaximum 100; minimum 0; at most 2 decimal place(s)
notesstringoptional
numberstringrequired
referencestringrequired
statusstringoptionalone of: draft, issued, sent
templateIduuidoptional
DELETE/api/receipts/{receiptId}Delete a receipt

Path receiptId

GET/api/receipts/{receiptId}/printDownload the PDF

Path receiptId

Responds with application/pdf and a Content-Disposition: attachment header — not JSON.

POST/api/receipts/{receiptId}/sendEmail it

Path receiptId

GET/api/receipts/dashboard/statsTotals by period

Expenses

FROM BASIC

What you spend, with an optional attachment on each record.

GET/api/expensesList expenses

Query

  • limit string
  • offset string
  • search string
  • userId string
  • billable string
  • customerId string
  • dateFrom string
  • dateTo string
  • status string
POST/api/expensesCreate an expense

Body — ExpenseAddition

FieldTypeRequiredConstraints
billablebooleanoptional
categorystringrequiredone of: travel, software, equipment, office, marketing, professional_services, other
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidoptionalmust not be empty
descriptionstringoptional
netAmountnumberrequiredminimum 0
notesstringoptional
purchaseInvoiceIduuidoptional
referencestringoptionalmax length 255
spentAtISO daterequired
vatAmountnumberoptionalminimum 0
vatRatenumberoptionalmaximum 100; minimum 0
vendorstringrequiredmax length 255
GET/api/expenses/{expenseId}Fetch one expense

Path expenseId

PUT/api/expenses/{expenseId}Update an expense

Path expenseId

Body — ExpenseAddition

FieldTypeRequiredConstraints
billablebooleanoptional
categorystringrequiredone of: travel, software, equipment, office, marketing, professional_services, other
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidoptionalmust not be empty
descriptionstringoptional
netAmountnumberrequiredminimum 0
notesstringoptional
purchaseInvoiceIduuidoptional
referencestringoptionalmax length 255
spentAtISO daterequired
vatAmountnumberoptionalminimum 0
vatRatenumberoptionalmaximum 100; minimum 0
vendorstringrequiredmax length 255
DELETE/api/expenses/{expenseId}Delete an expense

Path expenseId

POST/api/expenses/{expenseId}/attachmentUpload a receipt image or PDF

Path expenseId

Send the file as multipart/form-data. There is no JSON body on this request.

GET/api/expenses/{expenseId}/attachmentDownload the attachment

Path expenseId

Responds with application/pdf and a Content-Disposition: attachment header — not JSON.

DELETE/api/expenses/{expenseId}/attachmentRemove the attachment

Path expenseId

GET/api/expenses/dashboard/statsTotals by period
GET/api/expenses/dashboard/spendingSpending by category

Query

  • currency string

Inventory

FROM PROFESSIONAL

Stock items, movements and counts.

GET/api/inventoryList items

Query

  • limit string
  • offset string
  • search string
  • lowStock string
  • dateFrom string
  • dateTo string
  • status string
POST/api/inventoryCreate an item

Body — InventoryItemAddition

FieldTypeRequiredConstraints
categorystringrequiredone of: product, material, part, consumable, packaging, equipment, other
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
descriptionstringoptionalmax length 2000
locationstringoptionalmax length 255
namestringrequiredmax length 255; min length 1
notesstringoptionalmax length 2000
reorderLevelnumberoptionalminimum 0
skustringrequiredmax length 64; min length 1
unitstringrequiredone of: unit, kg, g, l, ml, m, hour, box, pack
unitCostnumberoptionalminimum 0; at most 2 decimal place(s)
unitPricenumberoptionalminimum 0; at most 2 decimal place(s)
GET/api/inventory/{itemId}Fetch one item

Path itemId

PUT/api/inventory/{itemId}Update an item

Path itemId

Body — InventoryItemUpdate

FieldTypeRequiredConstraints
categorystringoptionalone of: product, material, part, consumable, packaging, equipment, other
currencystringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
descriptionstringoptionalmax length 2000
locationstringoptionalmax length 255
namestringoptionalmax length 255; min length 1
notesstringoptionalmax length 2000
reorderLevelnumberoptionalminimum 0
skustringoptionalmax length 64; min length 1
unitstringoptionalone of: unit, kg, g, l, ml, m, hour, box, pack
unitCostnumberoptionalminimum 0; at most 2 decimal place(s)
unitPricenumberoptionalminimum 0; at most 2 decimal place(s)
DELETE/api/inventory/{itemId}Delete an item

Path itemId

GET/api/inventory/{itemId}/movementsMovement history

Path itemId

Query

  • limit string
  • offset string
POST/api/inventory/{itemId}/movementsRecord a movement

Path itemId

Body — InventoryMovementAddition

FieldTypeRequiredConstraints
kindstringrequiredmust not equal "count"; one of: receipt, issue, adjustment, count
occurredAtISO dateoptional
quantityDeltanumberrequiredmust not equal 0
reasonstringoptionalmax length 2000
unitCostnumberoptionalminimum 0; at most 2 decimal place(s)
POST/api/inventory/{itemId}/countRecord a stock count

Path itemId

Body — InventoryCountAddition

FieldTypeRequiredConstraints
countedQuantitynumberrequiredminimum 0
occurredAtISO dateoptional
reasonstringoptionalmax length 2000
GET/api/inventory/dashboard/statsStock value and low stock

Query

  • currency string

Purchase requests

FROM PROFESSIONAL

What you intend to buy, with lines and a printable document.

GET/api/purchase-requestsList requests

Query

  • limit string
  • offset string
  • search string
  • dateFrom string
  • dateTo string
POST/api/purchase-requestsCreate a request

Body — PurchaseRequestAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
linesarray of PurchaseRequestLineAdditionrequiredat most 200 entries; at least 1 entry
descriptionstringrequiredmax length 255; min length 1
itemIduuidoptional
quantitynumberrequiredmust be positive
skustringoptionalmax length 64
unitstringrequiredone of: unit, kg, g, l, ml, m, hour, box, pack
unitCostnumberrequiredminimum 0; at most 2 decimal place(s)
neededByISO dateoptional
notesstringoptionalmax length 2000
requestedDateISO dateoptional
supplierNamestringoptionalmax length 255
GET/api/purchase-requests/{requestId}Fetch one request

Path requestId

PUT/api/purchase-requests/{requestId}Update a request

Path requestId

Body — PurchaseRequestUpdate

FieldTypeRequiredConstraints
currencystringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
linesarray of PurchaseRequestLineAdditionoptionalat most 200 entries; at least 1 entry
descriptionstringrequiredmax length 255; min length 1
itemIduuidoptional
quantitynumberrequiredmust be positive
skustringoptionalmax length 64
unitstringrequiredone of: unit, kg, g, l, ml, m, hour, box, pack
unitCostnumberrequiredminimum 0; at most 2 decimal place(s)
neededByISO dateoptional
notesstringoptionalmax length 2000
requestedDateISO dateoptional
supplierNamestringoptionalmax length 255
DELETE/api/purchase-requests/{requestId}Delete a request

Path requestId

GET/api/purchase-requests/{requestId}/printDownload the PDF

Path requestId

Responds with application/pdf and a Content-Disposition: attachment header — not JSON.

Tasks and time

FROM PROFESSIONAL

Tasks and the hours logged against them. Both sit behind the one time-tracking flag, together with mileage below.

GET/api/tasksList tasks

Query

  • limit string
  • offset string
  • search string
  • customerId string
  • dateFrom string
  • dateTo string
  • status string
POST/api/tasksCreate a task

Body — TaskAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
defaultHourlyRatenumberoptionalminimum 0; at most 2 decimal place(s)
descriptionstringoptionalmax length 2000
namestringrequiredmax length 255; min length 1
statusstringoptionalone of: open, closed
GET/api/tasks/{taskId}Fetch one task

Path taskId

PUT/api/tasks/{taskId}Update a task

Path taskId

Body — TaskAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
defaultHourlyRatenumberoptionalminimum 0; at most 2 decimal place(s)
descriptionstringoptionalmax length 2000
namestringrequiredmax length 255; min length 1
statusstringoptionalone of: open, closed
DELETE/api/tasks/{taskId}Delete a task

Path taskId

POST/api/tasks/{taskId}/time-logsLog time against a task

Path taskId

Body — TimeLogAddition

FieldTypeRequiredConstraints
descriptionstringrequiredmax length 2000; min length 1
loggedOnISO dateoptional
minutesintegerrequiredmaximum 1440; minimum 1
PUT/api/tasks/{taskId}/time-logs/{timeLogId}Update a time log

Path taskIdtimeLogId

Body — TimeLogAddition

FieldTypeRequiredConstraints
descriptionstringrequiredmax length 2000; min length 1
loggedOnISO dateoptional
minutesintegerrequiredmaximum 1440; minimum 1
DELETE/api/tasks/{taskId}/time-logs/{timeLogId}Delete a time log

Path taskIdtimeLogId

Mileage

FROM PROFESSIONAL

Trips, with an optional attachment on each record.

GET/api/mileageList trips

Query

  • limit string
  • offset string
  • search string
  • customerId string
  • dateFrom string
  • dateTo string
  • status string
POST/api/mileageRecord a trip

Body — MileageAddition

FieldTypeRequiredConstraints
currencystringrequiredone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidrequired
distancenumberrequiredmust be positive; at most 2 decimal place(s)
distanceUnitstringrequiredone of: mile, km
fromLocationstringrequiredmax length 255; min length 1
purposestringoptionalmax length 2000
ratePerUnitnumberrequiredminimum 0; at most 2 decimal place(s)
toLocationstringrequiredmax length 255; min length 1
travelledOnISO daterequired
vehiclestringrequiredmax length 255; min length 1
vehicleTypestringrequiredone of: car, van, truck, motorcycle
GET/api/mileage/{mileageId}Fetch one trip

Path mileageId

PUT/api/mileage/{mileageId}Update a trip

Path mileageId

Body — MileageUpdate

FieldTypeRequiredConstraints
currencystringoptionalone of: GBP, USD, EUR, CHF, CNY, PLN
customerIduuidoptional
distancenumberoptionalmust be positive; at most 2 decimal place(s)
distanceUnitstringoptionalone of: mile, km
fromLocationstringoptionalmax length 255; min length 1
purposestringoptionalmax length 2000
ratePerUnitnumberoptionalminimum 0; at most 2 decimal place(s)
toLocationstringoptionalmax length 255; min length 1
travelledOnISO dateoptional
vehiclestringoptionalmax length 255; min length 1
vehicleTypestringoptionalone of: car, van, truck, motorcycle
DELETE/api/mileage/{mileageId}Delete a trip

Path mileageId

POST/api/mileage/{mileageId}/attachmentUpload an attachment

Path mileageId

Send the file as multipart/form-data. There is no JSON body on this request.

GET/api/mileage/{mileageId}/attachmentDownload the attachment

Path mileageId

Responds with application/pdf and a Content-Disposition: attachment header — not JSON.

DELETE/api/mileage/{mileageId}/attachmentRemove the attachment

Path mileageId

Responses

What comes back

Written by hand against the database entities — the API carries no runtime description of its return types, so a generated version of this would be a guess.

Invoices

  • id
  • number
  • reference
  • type
  • status
  • ksefStatus
  • currency
  • issueDate
  • dueDate
  • totalAmount
  • totalVat
  • correctionReason
  • correctionType
  • items
  • customerId
  • templateId
  • lastSentAt
  • createdAt
  • updatedAt

Each row also embeds the full `customer` object and the `template` it was rendered with. `items` is the array of lines you sent, each with its computed `amount` (price × qty) and a 1-based `id` within the invoice. `totalAmount` includes VAT; `totalVat` is the VAT part of it. `ksefStatus` is not a column: the API adds the status of the invoice’s latest KSeF filing attempt, one of `queued`, `sending`, `accepted`, `rejected` or `failed`, or null for an invoice never sent to KSeF. `correctionReason` and `correctionType` are a Polish credit note’s KSeF correction (KOR) details: the reason (up to 256 characters) and when the correction takes effect, 1 at the corrected invoice’s date, 2 at the credit note’s own date (the default when omitted), 3 other. They are null on every other invoice and for non-Polish issuers, where anything sent is discarded. Create and update answer with the saved invoice plus `ksefQueued`, true when that save queued a KSeF filing (a non-draft save on an account that files to KSeF); a save never emails the client.

Single fetch differs. Fetching one invoice additionally loads `sourceInvoices` — the invoices this credit note was raised against — and `creditNotes`, the credit notes raised against this invoice. It also loads `advanceInvoices`: for a settlement invoice the advance invoices it deducts, for an advance invoice the earlier advances of the same order it lists (advance and settlement invoices are for Polish issuers only); `settlements`, the invoices that link this advance; and `advanceChain`, the linked advances plus every earlier advance they in turn list, each with its own `advanceInvoices`, so the whole chain can be totalled (empty when nothing is linked). `ksef` is null if the invoice was never sent to KSeF, otherwise it carries `status`, `ksefNumber` (once accepted), `environment` (`test`, `demo` or `prod`), `acceptedAt`, `canRetry`, `emailPending` (accepted, client email not sent yet), `upoAvailable` (KSeF’s official receipt, the UPO, is held; download it in the portal) and `attempts`, newest first, each with `status`, `referenceNumber`, `ksefNumber`, `errorCode`, `errorMessage`, `createdAt` and `acceptedAt`. When `canRetry` is true, sending the invoice again files a new attempt; sending it after a rejection, without editing it since, answers 409 `KSEF_RETRY_NOT_ALLOWED`. The filed XML is never returned. None of these is present on a list row.

Quotes

  • id
  • number
  • reference
  • status
  • currency
  • issueDate
  • expiryDate
  • totalAmount
  • totalVat
  • items
  • notes
  • customerId
  • createdAt
  • updatedAt

Each row embeds the `customer` object. Totals are computed from the lines on write, exactly as on an invoice.

Clients

  • id
  • name
  • accountNumber
  • email
  • phoneNumber
  • website
  • companyRegNumber
  • companyTaxNumber
  • primaryPerson
  • billingAddress
  • deliveryAddress
  • paymentRemindersEnabled
  • createdAt
  • updatedAt

`primaryPerson` is an object of `firstname`, `lastname`, `email`; both addresses are objects of `line`, `city`, `state`, `postcode`, `country`. No related documents are loaded.

Receipts

  • id
  • number
  • reference
  • status
  • currency
  • issueDate
  • totalAmount
  • totalVat
  • items
  • notes
  • customerId
  • invoiceId
  • createdAt
  • updatedAt

Each row embeds the `customer` object.

Single fetch differs. Fetching one receipt additionally loads the whole `invoice` object it was issued against, where there is one. A list row carries only `invoiceId`.

Expenses

  • id
  • vendor
  • description
  • category
  • reference
  • spentAt
  • currency
  • netAmount
  • vatAmount
  • vatRate
  • totalAmount
  • billable
  • customerId
  • invoicedInvoiceId
  • attachmentFilename
  • attachmentContentType
  • attachmentByteSize
  • createdAt
  • updatedAt

`invoicedInvoiceId` is set once the expense has been billed onto an invoice, and is null until then. The attachment columns describe the stored file; the bytes come from the download endpoint, never inline.

Single fetch differs. ⚠ Expenses are the one resource where the single fetch returns LESS than a list row, not more. A list row embeds the `customer` object; fetching one expense loads no relations at all, so it carries `customerId` and no `customer`. If you need the client details, take them from the list, or fetch the client by its id.

Inventory

  • id
  • sku
  • name
  • description
  • category
  • unit
  • location
  • quantityOnHand
  • reorderLevel
  • unitCost
  • unitPrice
  • currency
  • notes
  • createdAt
  • updatedAt

Movements are a separate resource and are never embedded in an item. A movement row is `id`, `itemId`, `kind`, `quantityDelta`, `quantityAfter`, `unitCost`, `reason`, `occurredAt`, `createdAt` — `quantityAfter` is the running balance as at that movement.

Purchase requests

  • id
  • number
  • supplierName
  • requestedDate
  • neededBy
  • currency
  • notes
  • lines
  • createdAt
  • updatedAt

`lines` is loaded on both the list and the single fetch — a request is not useful without them. A purchase request carries no status column; there is nothing to filter or transition.

Tasks and time

  • id
  • name
  • description
  • status
  • currency
  • defaultHourlyRate
  • customerId
  • totalMinutes
  • unInvoicedMinutes
  • createdAt
  • updatedAt

⚠ The list returns `TaskListRow`, which is the task entity PLUS two computed totals — it is a projection, not the bare entity. `totalMinutes` is everything ever logged; `unInvoicedMinutes` is the part not yet billed onto an invoice, and the two are meant to disagree: invoicing a partly-billed task bills only the remainder.

Single fetch differs. Fetching one task adds its `timeLogs` array, newest first, each entry being `id`, `taskId`, `description`, `loggedOn`, `minutes`, `invoicedInvoiceId`. That array is the only thing the single fetch adds — the embedded `customer` object is on list rows too.

Mileage

  • id
  • travelledOn
  • vehicle
  • vehicleType
  • fromLocation
  • toLocation
  • purpose
  • distance
  • distanceUnit
  • ratePerUnit
  • currency
  • customerId
  • invoicedInvoiceId
  • attachmentFilename
  • attachmentContentType
  • attachmentByteSize
  • attachmentUploadedAt
  • createdAt
  • updatedAt

Each row embeds the `customer` object. `distanceUnit` and `vehicleType` are enumerations; `ratePerUnit` is money per unit of `distanceUnit`.

Payment links

  • url

The only endpoint here that does not return a record. The response is a single-key object carrying the public, token-addressed payment page URL for that invoice. Calling it again for the same invoice returns the same link rather than minting a second one.

The responses that are not JSON

6 routes answer withapplication/pdf and aContent-Disposition: attachmentheader rather than a record — the print routes:

  • /api/invoices/{invoiceId}/print
  • /api/quotes/{quoteId}/print
  • /api/receipts/{receiptId}/print
  • /api/expenses/{expenseId}/attachment
  • /api/purchase-requests/{requestId}/print
  • /api/mileage/{mileageId}/attachment

2 routes takemultipart/form-data instead of a JSON body — the attachment uploads. The file goes in a form field named file:

  • /api/expenses/{expenseId}/attachment
  • /api/mileage/{mileageId}/attachment

Both lists are read from the generated reference, so they cannot drift from the routes above.

Errors

When a request is refused

StatusWhat happenedWhat to do
401The token is missing, unknown, revoked or expired.Check the Authorization header. The API deliberately does not say which of the four it was — mint a new token if you are unsure.
402Your plan does not include the API, or does not include the resource you asked for.The body names the capability and the plan that includes it.
403The endpoint exists but is not part of the API.Settings, team, billing and token management are portal-only. Only the endpoints on this page accept a token.
404No such record, or it belongs to another account.These two answer identically on purpose, so ids cannot be probed.
400The body failed validation.The response lists the fields that were rejected.

Errors come back as JSON with a readable message. Plan refusals also carry a code and the plan that includes the capability, so your software can tell "upgrade needed" apart from "you sent something wrong".

Get started

Get started with payed.me today

Join payed.me today to streamline your invoicing process and achieve greater efficiency in your business.