Supplier invoice
ivy.agent.supplier-invoice · v0.1.0
ivyx
Reads a supplier's invoice (ulazna faktura), however it arrived (by e-mail, dropped into a folder or posted by a webhook): a model reads the text after a person has looked at the e-mail, then the numbers are checked against themselves (net plus VAT is the total, a dated and numbered invoice from a named supplier). What comes out is the invoice's fields and lines with kind: invoice, which IVYX Finance turns into a draft DOB voucher. An e-mail is marked read when the numbers added up.
Steps
In the order the agent's file lists them, each with where its inputs come from and the values the file fixes. A branch or a loop is a step too.
- 01Ivy NodeRead the invoice's textivy.node.pdf-text
Extracts the text of a PDF file, page by page and as one text, with the page count.
- takes
pathfrom the agent's input- returns
page_count
- 02Model turnRead the invoice with a model
The context is the text of a supplier's invoice (faktura) to the firm, in Montenegrin or English. Return a JSON object with: supplier (the supplier's name as printed, the legal form kept), supplier_pib (the supplier's tax number, PIB, digits only, or empty), iban (the supplier's bank account or IBAN as printed, or empty), number (the invoice number as printed), date (the invoice date, YYYY-MM-DD), due_date (the payment due date, YYYY-MM-DD, or empty), currency (ISO 4217, EUR when the invoice is in euros), net (the amount before VAT, a number), vat (the VAT amount, a number), total (the amount to pay, a number; decimal comma and thousand separators converted), description (one short line saying what was bought, from the invoice's own words), and lines: one object per invoice line, in the order printed, each with description, quantity (a number), unit_price (a number) and amount (a number). Copy the numbers as printed; do not compute a total the invoice does not print, and do not invent lines.
- takes
contextfrom step 1,text- returns
supplier,supplier_pib,iban,number,date,due_date,currency,net,vat,total,description,lines
- 03Ivy NodeDo the numbers add up?ivy.node.invoice-check
Checks what a model read off a supplier invoice against itself: the net and the VAT add up to the total, the date is a date, the number and the supplier are there.
- takes
supplierfrom step 2,output.suppliernumberfrom step 2,output.numberdatefrom step 2,output.datenetfrom step 2,output.netvatfrom step 2,output.vattotalfrom step 2,output.total- returns
kind,verified,problems
- 04BranchDid they?
Lets what follows run only when verified of step 3 is true.
- 05Ivy NodeDid it come by e-mail?ivy.node.has-mail
Says whether a statement came with an e-mail to mark: true when both the mail's uid and the mailbox login are known, false for a file dropped into a folder or posted by a webhook.
- takes
uidfrom the agent's inputusernamefrom the agent's input
- 06BranchIs there an e-mail to mark?
Lets what follows run only when has_mail of step 5 is true.
Runs only on the then branch of step 4.
- 07Ivy NodeMark the e-mail readivy.node.mail-mark
Marks messages of a mailbox folder as read or unread, moves them to another folder or adds a Gmail label, by uid over IMAP, and returns how many it changed.
Runs only on the then branch of step 6.
- takes
uidsfrom the agent's input,uidimap_hostfrom the agent's inputimap_portfrom the agent's inputuse_sslfrom the agent's inputusernamefrom the agent's inputfolderfrom the agent's inputmail_passwordfrom the agent's input- set
seentrue- returns
mail_marked
Nodes it brings
Adding this agent in IVYX Studio adds these nodes with it. A node your workspace already has is kept as it is, even at another version.
What it touches
Collected from what each of its nodes declares, plus the model call when a step is a model turn. A declaration is the author's statement, and it is what policy rules select on.
Inputs
| Field | Type | Description |
|---|---|---|
| pathrequired | string | The invoice file, a PDF, as a path under the project. |
| attachment | string | The attachment's file name. |
| from | string | Who sent the e-mail. |
| subject | string | The e-mail's subject. |
| received | string | When the e-mail arrived, ISO 8601. |
| uid | string | The e-mail's id in the mailbox. |
| imap_host | string | The mailbox the e-mail is in, as the source that saw it was configured; the agent marks the e-mail there. |
| imap_port | integer | The mailbox's IMAP port. |
| use_ssl | boolean | Whether the mailbox is reached over SSL. |
| username | string | The mailbox's login name. |
| folder | string | The folder the e-mail is in. |
| mail_password | string | The mailbox password as a reference to a stored secret ({ $secret: name }), handed on by the source that read the mail; the gateway resolves it inside the mark step and never records the value. |
Outputs
| Field | Type | Description |
|---|---|---|
| kind | string | invoice: what this output is, for a receiver that takes several kinds. |
| supplier | string | The supplier's name as printed. |
| supplier_pib | string | The supplier's tax number (PIB), when printed. |
| iban | string | The supplier's account or IBAN, when printed. |
| number | string | The invoice number as printed. |
| date | string | The invoice date, YYYY-MM-DD. |
| due_date | string | When it is due, YYYY-MM-DD, when printed. |
| currency | string | ISO 4217. |
| net | number | The amount before VAT. |
| vat | number | The VAT amount. |
| total | number | The amount to pay. |
| description | string | What was bought, in one line. |
| lines | array | The invoice's lines as printed. |
| page_count | integer | How many pages the invoice has. |
| verified | boolean | True when the net and the VAT add up to the total and the invoice names its supplier, number and date; false when a person should look. |
| problems | array | What did not hold, one sentence each. |
| mail_marked | integer | 1 when the e-mail was marked read: the numbers added up; absent for a file that came some other way. |
Tests
2 of 2 test cases passed on Oct 25, 2026, in the publisher's own environment, before this version was published. The registry keeps that record; it does not run the cases again.
Requires: python:3.9, pypdf, a model core
- adds-up
A supplier's invoice that adds up is read into its fields and verified, with nothing to mark since it came as a file.
- given
pathsamples/faktura-2026-117.pdf- expects
verifiedequals trueproblemsequals []numberequals 2026-117netequals 1000vatequals 210totalequals 1210suppliermatches MANUFAKTUR|Manufaktur
- off-total
An invoice whose total is not its net plus VAT is read and left unverified, the problem said in a sentence.
- given
pathsamples/faktura-2026-118.pdf- expects
verifiedequals falsetotalequals 1300problems.0matches add up to 1210.00, not the total 1300.00