Skip to content

Every 15 minutes

Create QuickBooks invoices from emails you label

Label an email thread Invoice Needed and a QuickBooks invoice for the client and items it mentions is created and sent.

Runs
Every 15 minutes
Apps
Gmail, QuickBooks
AI
Yes, uses the built-in AI allowance
Access
Gmail modify; QBO accounting

Send this to your assistant

Create a ClickRuntime automation: every 15 minutes, read Gmail threads labelled Invoice Needed, work out the client, items and amounts with AI, create and send the invoice in QuickBooks, and move the thread to Invoiced.

Paste it into your assistant. It tells you what it will send or change before it runs live.

First time? Adding ClickRuntime to your assistant takes about two minutes.

Why use it

Why teams use this automation

For a freelancer or small studio, the agreement to do the work is an email thread: scope, price, a 'go ahead'. Turning that into an invoice means switching to QuickBooks and copying the details across, so invoices go out days after the work is agreed or finished.

Labelling the thread is quicker than opening QuickBooks. The invoice is drafted from what the email says, sent, and the thread relabelled so you can see it's done.

What you get out of it

  • Invoice from where the deal happens

    One label in Gmail replaces switching tools and re-typing what was agreed.

  • Invoices go out the same day

    Billing promptly is one of the simplest ways to get paid sooner.

  • Clear status in your inbox

    Threads move from Invoice Needed to Invoiced, so you can see at a glance what's been billed.

  • New clients are handled

    If the client isn't in QuickBooks yet, they're added from the email.

How it works

What happens, step by step

  1. Every 15 minutes, ClickRuntime looks for Gmail threads with the Invoice Needed label.

  2. AI reads each thread and picks out the client, their email address, and the items and amounts agreed.

  3. It finds or creates the client in QuickBooks, creates the invoice and sends it.

  4. It swaps the thread's label to Invoiced so it's never billed twice.

Before it runs live

  • Connect Google through your own Google app (a one-time, 10-minute setup), so it works with your own Gmail
  • Connect QuickBooks

What you get

RunsEvery 15 minutes
Create QuickBooks invoices from emails you labeltoday, 9:00Succeeded
Gmail · InvoicedAcme Corp – Website refresh: invoice 1058 for $4,200.00 created and sent

Build your own

Need it to work differently?

This template is a starting point. Copy the prompt and change it, or describe a different automation from scratch, with your own conditions, more apps or an AI step. Your assistant writes it, tests it and runs it on ClickRuntime.
  • Your own rules

    Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.

  • Any number of apps

    One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.

  • AI where it helps

    Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.

  • On a schedule or on each event

    Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.

Changes you can ask for

  • Act only on the items that match your own rules, and skip the rest
  • Change what the AI looks for, or how it writes the result
  • Add another app, for example also send it to Slack
  • Combine it with other Gmail and QuickBooks steps into one automation

Under the hood

The code that runs this automation

This is the Python script that runs each time the automation starts. Your AI assistant writes it for you when you send the prompt, and you allow each step in your assistant. To change how the automation works, describe the change to your assistant and it updates the script for you. For every function it can use, see the script reference.
create_quickbooks_invoices_from_labelled_gmail_threads.pyexample
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from clickruntime import on_trigger, credentials, http, ai, log, report_fetched
API = "https://quickbooks.api.intuit.com/v3/company/1234567890"  # your QuickBooks company id

def qb(method, path, **kw):
    r = http.request(method, API + path, params={"minorversion": 73, **kw.pop("params", {})}, **kw, headers={"Accept": "application/json", "Authorization": "Bearer " + credentials.connection("quickbooks", "company")})
    return r.raise_for_status() or r.json()

NEEDED, DONE = "Label_InvoiceNeeded", "Label_Invoiced"  # your Gmail label ids
SCHEMA = {"type": "object", "properties": {"client": {"type": "string"}, "email": {"type": "string"},
          "items": {"type": "array", "items": {"type": "object", "properties": {"description": {"type": "string"}, "amount": {"type": "number"}}}}}}

@on_trigger
def run(event):
    gmail = build("gmail", "v1", credentials=Credentials(credentials.connection("google", "work")), cache_discovery=False)
    threads = gmail.users().threads().list(userId="me", labelIds=[NEEDED]).execute().get("threads", [])
    report_fetched(len(threads))
    if not threads:
        return {"summary": "Nothing new"}
    for t in threads:
        text = "\n".join(m["snippet"] for m in gmail.users().threads().get(userId="me", id=t["id"]).execute()["messages"])[-4000:]
        f = ai.generate(f"Extract the client, their email and the agreed line items with amounts:\n{text}", json_schema=SCHEMA, max_output_tokens=300).json
        if not f.get("items"):
            log.warning("No clear amounts, left for review", {"thread": t["id"]})
            continue
        found = qb("GET", "/query", params={"query": f"select * from Customer where PrimaryEmailAddr = '{f['email']}'"})["QueryResponse"].get("Customer")
        cust = found[0] if found else qb("POST", "/customer", json={"DisplayName": f["client"], "PrimaryEmailAddr": {"Address": f["email"]}})["Customer"]
        inv = qb("POST", "/invoice", json={"CustomerRef": {"value": cust["Id"]}, "BillEmail": {"Address": f["email"]}, "Line": [
            {"Amount": i["amount"], "Description": i["description"], "DetailType": "SalesItemLineDetail",
             "SalesItemLineDetail": {"ItemRef": {"value": "1"}}} for i in f["items"]]})["Invoice"]
        qb("POST", f"/invoice/{inv['Id']}/send")
        gmail.users().threads().modify(userId="me", id=t["id"], body={"addLabelIds": [DONE], "removeLabelIds": [NEEDED]}).execute()
    return {"threads": len(threads)}

FAQ

Common questions

What if the email doesn't state a clear price?
The thread is left with its label and you get a note, rather than an invoice with a guessed amount.
Can I check invoices before they're sent?
Yes. Ask for invoices to be created without sending, and send them yourself from QuickBooks.
Which address does the invoice go to?
The client's email address from the thread, which is also saved on their QuickBooks customer record.
What permissions does it need?
Gmail modify; QBO accounting. Nothing else in your accounts is used.
Does it need AI?
Yes. It uses ClickRuntime's built-in AI, so you don't need an OpenAI or Anthropic key. Every plan includes a monthly AI allowance.
How many runs does it use?
One run each time it checks. Checks that find nothing new and stop right away aren't counted.
Can I change how it works?
Yes. Describe the change to your AI assistant, for example a different schedule, channel or filter. It updates the automation, tests it and tells you what changed.

Set up “Create QuickBooks invoices from emails you label” from your assistant

Copy the prompt above, or connect your assistant first. Free plan, no credit card.