← Back to blog

Automate Accounts Payable with Make.com Router and Slack

Gmail → Cryvis Invoice API → Router on amount_due → Slack alert for high-value invoices and Google Sheets for the AP log.

What we're building

Every inbound invoice is logged to Sheets. Invoices with amount_due at or above a threshold also ping Slack so AP can prioritize. Below-threshold docs stay silent except for the sheet row.

Gmail: Watch Emails (label: AP)
        |
        v
Gmail: Get Attachment(s) + Filter (pdf/images)
        |
        v
HTTP: POST https://api.cryvis.com/v1/documents/invoice
        |
        v
JSON: Parse JSON
        |
        v
Router
   |
   +--[Route A: amount_due >= 5000]--> Slack: Create a Message
   |                                   + Sheets: Add a Row (priority=High)
   |
   +--[Route B: fallback]------------> Sheets: Add a Row (priority=Normal)

Threshold 5000 is an example — set it to your approval policy (same currency assumed; see production notes for multi-currency).

What you need

  • Make.com, Gmail, Slack, Google Sheets
  • Gmail label AP
  • Slack channel #ap-alerts (bot invited)
  • Sheet AP Log
  • Cryvis API key — Invoice
  • Two sample invoices: one under and one over the threshold

Credits: per page/image.

Create the scenario

  1. Gmail — Watch Emails
  2. Attachment download / iterator
  3. Filter — file type
  4. HTTP — Make a Request
  5. JSON — Parse JSON
  6. Router
  7. Route A: Filter (amount_due ≥ threshold) → Slack — Create a MessageSheets — Add a Row
  8. Route B: FallbackSheets — Add a Row

Put Sheets on both routes so every invoice is logged. Slack only on Route A.

Configure source

Watch Emails on label AP, unread preferred.

Attachment Filter:

extension in {pdf, png, jpg, jpeg, webp}

Ignore threads that are payment remittances without documents. If finance forwards “FYI” threads with old PDFs, teach them a dedicated AP-Inbound address instead of Reply-All chaos.

Configure Cryvis HTTP

SettingValue
URLhttps://api.cryvis.com/v1/documents/invoice
MethodPOST
Body typeMultipart/form-data
Fieldfile = attachment binary
HeaderAuthorization: Bearer <API_KEY>

Docs: extractInvoice.

Process response

Fields used for routing and logging:

  • data.amount_due — Router condition (prefer over total_amount when partial payments exist on the doc)
  • data.total_amount, data.subtotal, data.tax_total
  • data.invoice_number, data.invoice_date, data.due_date, data.currency
  • data.seller.name, data.buyer.name

Router Filter on Route A:

data.amount_due Greater than or equal to 5000

If amount_due is empty, fall through to Route B and set Priority Review in Sheets — do not Slack-alert on nulls as zero.

Router setup detail

  1. Add Router after Parse JSON.
  2. On the first route, open the funnel Filter icon between Router and Slack.
  3. Condition: amount_due Numeric: Greater than or equal to 5000 (map the field; do not compare as text or "5000.00" sorts wrong).
  4. Enable Fallback on the last route so unmatched bundles still hit Sheets.
  5. Clone the Sheets module onto both routes with Priority set differently — or use one Sheets module after a second Router merge if you prefer a single write (more complex; two writes is clearer).

Order modules on Route A as Sheets then Slack if you would rather log a High row even when Slack is rate-limited.

Configure destination

Slack (Route A)

Message example:

High-value invoice
Vendor: {{data.seller.name}}
Number: {{data.invoice_number}}
Amount due: {{data.currency}} {{data.amount_due}}
Due: {{data.due_date}}
From: {{gmail.from}}
Subject: {{gmail.subject}}

Pin the Cryvis dashboard or Airtable/Sheets link if you have one. Keep the message short — #ap-alerts fills up fast.

Sheets (both routes)

Columns:

Processed At | Priority | Invoice Number | Vendor | Buyer | Currency | Amount Due | Total | Due Date | From | Subject | Attachment | Gmail ID

PriorityRoute
HighA
NormalB
ReviewB when amount missing

Filters and error handling

  • Pre-HTTP MIME Filter (save credits).
  • Post-HTTP: only continue if success is true.
  • Error Handler on HTTP → Slack #ap-errors with subject + status code (separate from high-value alerts).
  • Error Handler on Slack should not block Sheets — if Slack fails, still log the row (reorder modules: Sheets then Slack, or use resume directives).
  • Data Store dedupe: seller.name|invoice_number before Router.

Currency trap: 5000 INR ≠ 5000 USD. Options:

  1. Separate labels / mailboxes per currency, or
  2. Router with compound Filters (currency = USD AND amount_due >= 5000) plus another route for EUR, or
  3. Normalize via a FX module before the Router (heavier).

Error Handler sketch

Attach an Error Handler route to the HTTP module:

HTTP (Invoice)
   |
   +-- success --> Router (amount routes)
   |
   +-- error ----> Slack #ap-errors
                    Sheets AP Errors tab
                    (file name, status, body snippet)

Do not put the Error Handler Slack message in #ap-alerts — ops will treat extraction failures as high-value invoices.

Test

  1. Label a low-amount invoice email → expect Sheets Normal, no Slack.
  2. Label a high-amount invoice → Slack + Sheets High.
  3. Corrupt/non-invoice PDF → Error Handler path, no AP Log success row.
  4. Duplicate send → Data Store blocks second pass.
  5. Invoice with amount_due blank but total_amount filled — confirm you either map a fallback ifempty(amount_due; total_amount) in the Filter or accept Review priority.

Ops playbook after go-live

  • AP owns the threshold number; engineering owns the scenario. Document both in the scenario notes field.
  • When Slack fires, the assignee should open the Sheets row (filter Priority = High) and the Gmail message ID, not argue in the channel.
  • Monthly: sample 10 Normal rows and 10 High rows against PDFs. Track extraction misses separately from policy misses (wrong threshold vs wrong amount_due).
  • If vendors send statement PDFs (many invoices in one file), this flow still creates one extraction / one Sheets row for the statement totals — line-level AP needs line items or a different document type.

Production considerations

  • Threshold changes: store the number in a Data Store or scenario variable so you do not edit Filters in three places.
  • Quiet hours: optional Filter on time-of-day before Slack; Sheets still writes.
  • Approval workflow: Slack message is a signal, not approval. Pair with Airtable AP status if you need state transitions.
  • Audit: keep Gmail message ID on every row for dispute trails.

Next steps

Line-level detail: Extract invoice line items. Vendor CRM: Extract vendor details. Error patterns: Handle API errors.

Invoice product · API docs · Make.com + Cryvis hub.