LoopFour

Finance Teams

Workflow patterns for finance and billing automation

Finance Team Workflows

Automate invoicing, payment reconciliation, revenue recognition, and financial operations across your billing and accounting systems.

Why Automate Finance Operations?

Finance teams face unique challenges:

  • Manual data entry across multiple systems (CRM, billing, accounting)
  • Delayed invoicing waiting for deal information from sales
  • Reconciliation bottlenecks matching payments to invoices
  • Month-end crunches racing to close books on time
  • Audit trail gaps when processes aren't documented

Workflow automation solves these by:

  • Eliminating copy-paste between systems
  • Triggering actions instantly when events occur
  • Maintaining audit trails automatically
  • Reducing errors from manual data entry
  • Freeing up time for strategic analysis

Common Workflow Patterns

Invoice Automation

Trigger: CRM deal closes won Actions: Create invoice, send to customer, update CRM

Automatically generate invoices when sales deals close, eliminating the handoff delay between sales and finance.

{
  "name": "Deal Close → Invoice",
  "trigger": {
    "type": "webhook",
    "provider": "salesforce",
    "events": ["opportunity.updated"],
    "filter": {
      "StageName": { "$eq": "Closed Won" }
    }
  },
  "steps": [
    {
      "id": "get-account",
      "type": "action",
      "config": {
        "connector": "salesforce",
        "action": "getAccount",
        "accountId": "{{input.payload.AccountId}}"
      }
    },
    {
      "id": "create-invoice",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "createInvoice",
        "customer": "{{steps.get-account.output.Stripe_Customer_ID__c}}",
        "collection_method": "send_invoice",
        "days_until_due": 30
      }
    },
    {
      "id": "add-line-item",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "createInvoiceItem",
        "customer": "{{steps.get-account.output.Stripe_Customer_ID__c}}",
        "invoice": "{{steps.create-invoice.output.id}}",
        "description": "{{input.payload.Name}}",
        "amount": "{{input.payload.Amount | multiply: 100}}",
        "currency": "usd"
      }
    },
    {
      "id": "finalize-and-send",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "sendInvoice",
        "invoiceId": "{{steps.create-invoice.output.id}}"
      }
    },
    {
      "id": "update-opportunity",
      "type": "action",
      "config": {
        "connector": "salesforce",
        "action": "updateOpportunity",
        "opportunityId": "{{input.payload.Id}}",
        "fields": {
          "Invoice_URL__c": "{{steps.finalize-and-send.output.hosted_invoice_url}}",
          "Invoice_Status__c": "Sent"
        }
      }
    }
  ]
}

Benefits:

  • Invoice sent within seconds of deal close
  • No manual data entry errors
  • Full audit trail in CRM
  • Customer receives invoice immediately

Full Invoice Automation Tutorial →


Payment Reconciliation

Trigger: Payment received in Stripe Actions: Match to invoice, update accounting, notify team

Automatically reconcile payments when they arrive, updating both accounting and CRM systems.

{
  "name": "Payment Reconciliation",
  "trigger": {
    "type": "webhook",
    "provider": "stripe",
    "events": ["invoice.payment_succeeded"]
  },
  "steps": [
    {
      "id": "get-invoice-details",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "getInvoice",
        "invoiceId": "{{input.data.object.id}}"
      }
    },
    {
      "id": "find-qb-invoice",
      "type": "action",
      "config": {
        "connector": "quickbooks",
        "action": "query",
        "query": "SELECT * FROM Invoice WHERE DocNumber = '{{steps.get-invoice-details.output.number}}'"
      }
    },
    {
      "id": "record-payment",
      "type": "action",
      "config": {
        "connector": "quickbooks",
        "action": "createPayment",
        "CustomerRef": {
          "value": "{{steps.find-qb-invoice.output.QueryResponse.Invoice.[0].CustomerRef.value}}"
        },
        "TotalAmt": "{{input.data.object.amount_paid | divided_by: 100}}",
        "Line": [{
          "Amount": "{{input.data.object.amount_paid | divided_by: 100}}",
          "LinkedTxn": [{
            "TxnId": "{{steps.find-qb-invoice.output.QueryResponse.Invoice.[0].Id}}",
            "TxnType": "Invoice"
          }]
        }]
      }
    },
    {
      "id": "update-crm",
      "type": "action",
      "config": {
        "connector": "salesforce",
        "action": "query",
        "query": "UPDATE Opportunity SET Invoice_Status__c = 'Paid' WHERE Stripe_Invoice_ID__c = '{{input.data.object.id}}'"
      }
    },
    {
      "id": "notify-finance",
      "type": "slack",
      "config": {
        "action": "sendMessage",
        "channel": "#finance-payments",
        "text": "Payment received: ${{input.data.object.amount_paid | divided_by: 100}} from {{steps.get-invoice-details.output.customer_name}} for invoice #{{steps.get-invoice-details.output.number}}"
      }
    }
  ]
}

Benefits:

  • Real-time payment tracking
  • Automatic QuickBooks reconciliation
  • CRM status always current
  • Finance team notified instantly

Revenue Recognition

Trigger: Scheduled monthly (1st of month) Actions: Query subscriptions, calculate MRR/ARR, update spreadsheet

Automate monthly revenue calculations for accurate financial reporting.

{
  "name": "Monthly Revenue Recognition",
  "trigger": {
    "type": "schedule",
    "cron": "0 6 1 * *"
  },
  "steps": [
    {
      "id": "get-active-subscriptions",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "listSubscriptions",
        "status": "active"
      }
    },
    {
      "id": "calculate-metrics",
      "type": "transform",
      "config": {
        "operation": "reduce",
        "data": "{{steps.get-active-subscriptions.output.data}}",
        "accumulator": {
          "mrr": 0,
          "customer_count": 0
        },
        "expression": {
          "mrr": "{{acc.mrr + (item.items.data.[0].price.unit_amount / 100)}}",
          "customer_count": "{{acc.customer_count + 1}}"
        }
      }
    },
    {
      "id": "create-journal-entry",
      "type": "action",
      "config": {
        "connector": "netsuite",
        "action": "createJournalEntry",
        "subsidiary": { "id": "1" },
        "trandate": "{{now | date: '%Y-%m-01'}}",
        "memo": "Monthly Revenue Recognition - {{now | date: '%B %Y'}}",
        "line": [
          {
            "account": { "id": "123" },
            "debit": "{{steps.calculate-metrics.output.mrr}}"
          },
          {
            "account": { "id": "456" },
            "credit": "{{steps.calculate-metrics.output.mrr}}"
          }
        ]
      }
    },
    {
      "id": "notify-finance",
      "type": "slack",
      "config": {
        "action": "sendMessage",
        "channel": "#finance-metrics",
        "blocks": [
          {
            "type": "header",
            "text": { "type": "plain_text", "text": "Monthly Revenue Report" }
          },
          {
            "type": "section",
            "fields": [
              { "type": "mrkdwn", "text": "*MRR:* ${{steps.calculate-metrics.output.mrr | number_format: 2}}" },
              { "type": "mrkdwn", "text": "*ARR:* ${{steps.calculate-metrics.output.mrr | multiply: 12 | number_format: 2}}" },
              { "type": "mrkdwn", "text": "*Active Customers:* {{steps.calculate-metrics.output.customer_count}}" }
            ]
          }
        ]
      }
    }
  ]
}

Benefits:

  • Consistent monthly calculations
  • Automatic journal entries
  • Team visibility into metrics
  • Reduces month-end workload

Dunning Automation

Trigger: Invoice overdue Actions: Send reminder emails, update customer status, notify sales

Automatically follow up on overdue invoices without manual tracking.

{
  "name": "Invoice Dunning",
  "trigger": {
    "type": "webhook",
    "provider": "stripe",
    "events": ["invoice.payment_failed"]
  },
  "steps": [
    {
      "id": "get-customer",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "getCustomer",
        "customerId": "{{input.data.object.customer}}"
      }
    },
    {
      "id": "send-reminder-email",
      "type": "email",
      "config": {
        "action": "send",
        "provider": "sendgrid",
        "to": "{{steps.get-customer.output.email}}",
        "from": "billing@company.com",
        "subject": "Payment Failed - Action Required",
        "body": {
          "html": "<p>Hi {{steps.get-customer.output.name}},</p><p>We were unable to process your payment of ${{input.data.object.amount_due | divided_by: 100}} for invoice #{{input.data.object.number}}.</p><p>Please update your payment method to avoid service interruption.</p><p><a href='{{input.data.object.hosted_invoice_url}}'>Update Payment Method</a></p>"
        }
      }
    },
    {
      "id": "update-hubspot-status",
      "type": "action",
      "config": {
        "connector": "hubspot",
        "action": "updateContact",
        "email": "{{steps.get-customer.output.email}}",
        "properties": {
          "payment_status": "Failed",
          "last_payment_attempt": "{{now | date: '%Y-%m-%d'}}"
        }
      }
    },
    {
      "id": "notify-account-owner",
      "type": "slack",
      "config": {
        "action": "sendMessage",
        "channel": "#sales-alerts",
        "text": ":warning: Payment failed for {{steps.get-customer.output.name}}. Invoice #{{input.data.object.number}} for ${{input.data.object.amount_due | divided_by: 100}}. <{{input.data.object.hosted_invoice_url}}|View Invoice>"
      }
    }
  ]
}

Benefits:

  • Immediate customer notification
  • Sales visibility into at-risk accounts
  • Consistent follow-up process
  • Reduced churn from payment issues

Subscription Billing Sync

Trigger: Subscription changes in Stripe Actions: Update accounting records, sync to ERP

Keep billing and accounting systems in sync when subscriptions change.

{
  "name": "Subscription → Accounting Sync",
  "trigger": {
    "type": "webhook",
    "provider": "stripe",
    "events": ["customer.subscription.updated", "customer.subscription.deleted"]
  },
  "steps": [
    {
      "id": "get-subscription",
      "type": "action",
      "config": {
        "connector": "stripe",
        "action": "getSubscription",
        "subscriptionId": "{{input.data.object.id}}"
      }
    },
    {
      "id": "find-netsuite-customer",
      "type": "action",
      "config": {
        "connector": "netsuite",
        "action": "searchRecords",
        "query": "SELECT id FROM customer WHERE custentity_stripe_id = '{{input.data.object.customer}}'"
      }
    },
    {
      "id": "update-subscription-record",
      "type": "action",
      "config": {
        "connector": "netsuite",
        "action": "updateRecord",
        "type": "customrecord_subscription",
        "id": "{{steps.find-netsuite-customer.output.id}}",
        "values": {
          "custrecord_sub_status": "{{input.data.object.status}}",
          "custrecord_sub_mrr": "{{steps.get-subscription.output.items.data.[0].price.unit_amount | divided_by: 100}}",
          "custrecord_sub_next_billing": "{{input.data.object.current_period_end | date: '%Y-%m-%d'}}"
        }
      }
    }
  ]
}

Expense Approval Workflow

Trigger: Expense submitted via API Actions: Route for approval, notify manager, process payment

Automate expense approval workflows with Slack integration.

{
  "name": "Expense Approval",
  "trigger": {
    "type": "api"
  },
  "steps": [
    {
      "id": "determine-approver",
      "type": "transform",
      "config": {
        "operation": "map",
        "data": {
          "approver": "{{#if (gt input.amount 1000)}}cfo@company.com{{else}}manager@company.com{{/if}}",
          "approverSlackId": "{{#if (gt input.amount 1000)}}U_CFO{{else}}U_MANAGER{{/if}}"
        }
      }
    },
    {
      "id": "request-approval",
      "type": "slack",
      "config": {
        "action": "sendMessage",
        "channel": "#expense-approvals",
        "blocks": [
          {
            "type": "header",
            "text": { "type": "plain_text", "text": "Expense Approval Request" }
          },
          {
            "type": "section",
            "fields": [
              { "type": "mrkdwn", "text": "*Submitted By:* {{input.employee_name}}" },
              { "type": "mrkdwn", "text": "*Amount:* ${{input.amount}}" },
              { "type": "mrkdwn", "text": "*Category:* {{input.category}}" },
              { "type": "mrkdwn", "text": "*Description:* {{input.description}}" }
            ]
          },
          {
            "type": "actions",
            "elements": [
              {
                "type": "button",
                "text": { "type": "plain_text", "text": "Approve" },
                "style": "primary",
                "action_id": "approve_expense_{{input.expense_id}}"
              },
              {
                "type": "button",
                "text": { "type": "plain_text", "text": "Reject" },
                "style": "danger",
                "action_id": "reject_expense_{{input.expense_id}}"
              }
            ]
          }
        ]
      }
    }
  ]
}

Key Integrations

IntegrationUse Cases
StripeInvoicing, payments, subscriptions, customer management
QuickBooksAccounting records, payments, journal entries
NetSuiteERP integration, revenue recognition, multi-entity
SalesforceCRM updates, opportunity tracking, customer data
HubSpotCustomer status, lifecycle tracking
SlackNotifications, approvals, alerts
EmailCustomer invoices, payment reminders

Best Practices

1. Idempotency

Always include unique identifiers to prevent duplicate processing:

{
  "metadata": {
    "salesforce_opportunity_id": "{{input.payload.Id}}",
    "processed_at": "{{now}}"
  }
}

2. Error Handling

Use graceful degradation for non-critical steps:

{
  "onError": {
    "action": "continue",
    "fallback": { "id": null }
  }
}

3. Audit Trails

Always update source systems with results:

{
  "id": "update-source",
  "type": "action",
  "config": {
    "connector": "salesforce",
    "action": "updateOpportunity",
    "fields": {
      "Invoice_Created_At__c": "{{now}}",
      "Invoice_ID__c": "{{steps.create-invoice.output.id}}"
    }
  }
}

4. Amount Handling

Remember Stripe amounts are in cents:

{
  "amount": "{{input.Amount | multiply: 100}}",
  "display_amount": "{{input.data.object.amount | divided_by: 100}}"
}

Getting Started

  1. Invoice Automation Tutorial - Start with deal-to-invoice automation
  2. Stripe Integration Guide - Set up your Stripe connection
  3. QuickBooks Integration Guide - Connect your accounting system
  4. Transform Steps - Learn data transformation patterns