Developers

NORMAN DEVELOPERS

Invoice and product catalog API

Sync products, extract invoice proposals from contracts, retrieve PDF and XML files, match payments and manage existing recurring series.

INVOICING WORKFLOWS

Connect your catalog, contracts and invoices

Sync your product and service catalog

Catalog reads use read_invoices; creation, updates and archiving use write_invoices. Save the returned publicId in your ERP, then update the same record with PATCH. Prices use minor currency units.

curl --fail-with-body -X POST "https://api.norman.finance/api/v1/companies/$NORMAN_COMPANY_ID/products/" \
  -H "Authorization: Bearer $NORMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Consulting hour",
  "type": "SERVICES",
  "price": 15000,
  "vatRate": 19,
  "sku": "CONSULTING-HOUR"
}'

Search with GET /companies/{company_pk}/products/?search=CONSULTING. The default list contains active products. Use status=archived or status=all for archived entries. DELETE archives a product; PATCH with {"status": "active"} restores it. Existing invoice lines keep their recorded values.

Turn a contract into an invoice proposal

Use write_invoices, write_documents and read_clients. Upload a contract up to 10 MB, or pass an existing contract as attachmentId. Norman stores the source document and returns a draft, clientData and reviewNotes.

curl --fail-with-body -X POST "https://api.norman.finance/api/v1/companies/$NORMAN_COMPANY_ID/invoices/contract-draft/" \
  -H "Authorization: Bearer $NORMAN_API_KEY" \
  -F "file=@signed-contract.pdf"

Review the recipient, dates, VAT and notes before saving. Proposal line rates use major currency units; convert them to minor units for invoice creation. The proposal is not an invoice-create request body, and this operation does not create or email an invoice. Use the invoice draft recipe after mapping and reviewing the fields.

Retrieve invoice files and reconcile payments

With read_invoices, request a suggested number, an existing PDF download link or e-invoice XML. A suggested number is not reserved. XML generation validates the invoice and returns the file directly; it does not submit anything to a tax authority.

curl --fail-with-body "https://api.norman.finance/api/v1/companies/$NORMAN_COMPANY_ID/invoices/next-invoice-number/" \
  -H "Authorization: Bearer $NORMAN_API_KEY"

curl --fail-with-body "https://api.norman.finance/api/v1/companies/$NORMAN_COMPANY_ID/invoices/replace_with_invoice_uuid/pdf/" \
  -H "Authorization: Bearer $NORMAN_API_KEY"

curl --fail-with-body "https://api.norman.finance/api/v1/companies/$NORMAN_COMPANY_ID/invoices/replace_with_invoice_uuid/xml/" \
  -H "Authorization: Bearer $NORMAN_API_KEY" \
  -o invoice.xml

Find payment candidates with GET /invoices/{id}/suggest-transactions/below the company path using read_invoices and read_transactions. After review, link a payment with write_invoices and write_transactions.

curl --fail-with-body -X POST "https://api.norman.finance/api/v1/companies/$NORMAN_COMPANY_ID/invoices/replace_with_invoice_uuid/link-transaction/" \
  -H "Authorization: Bearer $NORMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "transaction": "replace_with_transaction_uuid"
}'

Follow up on overdue invoices and recurring schedules

POST /invoices/{id}/send-on-overdue/ sends a reminder with write_invoices. Email verification, plan eligibility and overdue-state checks still apply. The operation sends an email; avoid blind retries after a timeout. Read a client’s payment statistics with GET /clients/{id}/payment-stats/ and both read_clients and read_invoices.

For an existing recurring series, GET /recurring-invoices/{id}/children/previews issue and due dates with read_invoices. It returns a date schedule; existing invoice records are in the series’ invoices field. To stop the series, send an empty POST to /recurring-invoices/{id}/cancel/with write_invoices. Pending and draft children are removed; already issued invoices remain. Creating and editing recurring schedules stays in the Norman application.