How to Turn Emailed Vendor Invoices into MarketMan Purchase Orders

Receive a vendor invoice by email, pull the PDF attachment, extract its line items with a one-off Knowledge query, and create a matching draft order in MarketMan against the right vendor and category, all without typing a line item by hand.

What This Integration Does

Back-of-house teams lose hours retyping vendor invoices and delivery dockets into MarketMan so that costs, par levels, and ordering stay accurate. This Spojit workflow takes the invoice your supplier already emails you, reads the PDF, and turns it into a MarketMan purchase order with the correct vendor, catalog item codes, and quantities. You forward (or auto-forward) the invoice to a dedicated Spojit address and a draft order appears in MarketMan ready for a buyer to review and send.

The run starts on a Mailhook trigger: any mail to your generated address fires a run within seconds, with no mailbox to connect. An Attachment node fetches the PDF bytes, a Knowledge node embeds that single document into a Transient collection and queries it for structured line items, and a MarketMan Connector node maps the result onto create-order. Each email produces one independent run and one order; Mailhook deduplicates per message, so a re-sent or replayed email will not create a duplicate order. Re-runs from execution history replay the same extraction against the same retained email.

Prerequisites

  • A MarketMan connection added in Spojit under Connections with buyer access, so the workflow can read vendors and categories and create orders.
  • Your MarketMan vendor list set up, with catalog items that carry the CatalogItemCode values your suppliers use, so extracted codes match real items.
  • The vendor GUID for the supplier you are processing (read it once with get-vendors), or a plan to look it up dynamically per run.
  • A sample vendor invoice PDF for testing, ideally a real one from the supplier whose layout you want to support.
  • Permission to create workflows in your workspace and access to the Knowledge section in the sidebar.

Step 1: Receive the invoice with a Mailhook trigger

Create a new workflow and set the Trigger node type to Mailhook. Enter an optional Address prefix such as invoices (1 to 24 characters), then click Generate email address. Spojit produces a unique address like invoices-3f9a2b7c1d4e5f60@mailhook.spojit.com. Copy it and set your supplier or your mailbox forwarding rule to send invoices there. To cut noise, add a From allowlist with the supplier domain and an optional Subject regex such as invoice|docket. The trigger output is available downstream as {{ input }}, including {{ input.from }}, {{ input.subject }}, {{ input.replyTo }}, and {{ input.attachments }} (each attachment a reference of { id, filename, contentType }). Mailhook is always asynchronous, so there is no reply to the sender from the trigger itself.

Step 2: Fetch the PDF with an Attachment node

Add an Attachment node directly after the trigger. The designer only allows an Attachment node when the workflow uses a Mailhook trigger. Set Mode to Single so you get the first matching file as one object, set the Content type filter to application/pdf, and set the Filename pattern to *.pdf to ignore signature images and logos. Turn on Fail if no attachment matches so an invoice that arrives without a PDF stops the run loudly instead of creating an empty order. Name the output variable, for example invoicePdf. The node returns { filename, contentType, size, content }, where content is the base64 file body you will feed straight into the next step. Keep in mind the default limits of 10 MB per attachment and 25 MB per run.

Step 3: Embed the invoice into a Transient collection

Add a Knowledge node in Embed mode. In the Collection dropdown choose Transient: it is auto-created for this run, shared with later nodes in the same run, and cleaned up automatically when the run finishes, which is ideal for a one-off "embed then query then discard" on a single invoice. Transient mode needs no file name or embedding model. Set Document Type to PDF and set Document Input to the base64 body from the previous step:

{{ invoicePdf.content }}

Name the output variable, for example embedResult; it reports the chunk count and metadata so you can confirm the document was processed before you query it.

Step 4: Extract line items with a Knowledge query

Add a second Knowledge node in Query mode and choose Transient for the Collection so it reads the document embedded earlier in the same run. Write a Prompt that asks for exactly the fields MarketMan needs, and attach a Response Schema so the result is reliable structured JSON rather than prose. A prompt like the following works well:

Extract every ordered line item from this vendor invoice.
For each line return the supplier catalog item code, the
product description, and the quantity as a number. Also
return the vendor name and the invoice or delivery date.

Set a Response Schema that mirrors what create-order expects, for example an object with a vendorName string, a deliveryDate string, and an items array of { CatalogItemCode, description, Quantity }. Name the output variable extracted. Raise Result Count above the default of 5 if invoices run to many lines, so every chunk is retrieved. This is where Miraxa, the intelligent layer across your automation, does the heavy lifting: it reads the unstructured PDF and returns clean fields you can map deterministically.

Step 5: Resolve the vendor and category in MarketMan

MarketMan identifies a supplier by vendor GUID, not by the name printed on the invoice. If you always process one supplier, hard-code that GUID. To resolve it per run, add a Connector node for MarketMan in Direct mode and pick get-vendors to list every vendor connected to the buyer account, then add a Transform node to find the vendor whose name matches {{ extracted.vendorName }} and read its GUID. If your account books orders against a buyer category, add another MarketMan Direct-mode node calling get-categories and select the category your invoices belong to. Keep these reference calls in Direct mode: they are predictable single-tool calls and cost no AI credits.

Step 6: Create the draft order with create-order

Add a Connector node for MarketMan in Direct mode and select create-order. Map vendorGuid to the GUID resolved in the previous step and map catalogItems to the extracted lines, each an object of CatalogItemCode and Quantity. Leave orderStatus blank (or set it to Sent only once you trust the extraction) so the order lands as a draft a buyer reviews before it goes to the supplier. Set deliveryDateUTC from the extracted date in yyyy/mm/dd hh:mm:ss form, and use comment to record provenance such as the source email. A typical mapping looks like this:

{
  "vendorGuid": "{{ vendor.guid }}",
  "deliveryDateUTC": "{{ extracted.deliveryDate }}",
  "comment": "Auto-created by Spojit from {{ input.from }} - {{ input.subject }}",
  "catalogItems": {{ extracted.items }}
}

To close the loop, add a Send Email node after the order is created and send a short confirmation to {{ input.replyTo }} (or your purchasing inbox) summarizing the vendor, line count, and the new order. For invoices that fail validation, you can instead route to a Human approval node so a buyer confirms before create-order runs.

Tips

  • Use a Transient collection rather than a persistent one for single-invoice extraction; it needs no file name or embedding model and is cleaned up automatically, keeping your workspace storage tidy.
  • Always attach a Response Schema in the Query node. Forcing structured JSON makes the catalogItems mapping deterministic and prevents free-text answers from breaking create-order.
  • Resolve the vendor GUID with get-vendors once and cache it if you only handle one supplier, saving a call on every run.
  • Keep new orders as drafts (omit orderStatus) until extraction accuracy is proven on real invoices, then switch to Sent for true hands-off ordering.

Common Pitfalls

  • Supplier catalog codes that do not match your MarketMan CatalogItemCode values will create lines MarketMan cannot price. Reconcile codes first, or have the Query node return the supplier code and map it through a lookup before create-order.
  • Mailhook is async, so the sender never gets an automatic reply. If a supplier expects acknowledgement, add a Send Email node to reply to {{ input.replyTo }} explicitly.
  • Attachments larger than the 10 MB per-attachment or 25 MB per-run defaults will not be fetched. Multi-page scanned invoices can exceed this; ask suppliers for digital PDFs where possible.
  • Received emails are retained for 30 days, so a re-run from execution history older than that has no attachment to fetch. Re-process promptly if you need to replay.
  • If a non-PDF (such as a logo image) is the first attachment, the application/pdf content-type and *.pdf filename filters keep the Attachment node from grabbing the wrong file.

Testing

Before pointing live supplier mail at the address, keep the create-order step set to draft (no orderStatus) and forward a single known invoice to your Mailhook address from an allowlisted sender. Open the run in execution history and check each step in order: the Attachment node returned a PDF with a sensible size, the Embed node reported a non-zero chunk count, the Query node returned the expected vendor, date, and line items against your schema, and the MarketMan node created exactly one draft order with the right catalog codes and quantities. Once a handful of real invoice layouts extract cleanly, switch on auto-forwarding and, if you want fully hands-off ordering, set orderStatus to Sent.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.