Made by Quorra Agency. Questions: cayla@quorra.agency.

Set it up with your AI assistant

Prefer to be walked through it? Copy this prompt and paste it into ChatGPT, Claude, Gemini or Copilot. It will guide you one step at a time and is told never to ask for your Stripe key.

  1. Click Copy the prompt.
  2. Open your AI assistant and paste it as your first message.
  3. Answer its questions and say "done" after each step.
You are helping me set up the Hourly Invoice Sheet, a Google Sheets template with an attached Apps Script made by Quorra Agency. It tracks my hours and creates Stripe invoices from them. The full guide is at https://quorra.agency/tools/hourly-invoice-sheet/setup/

Walk me through setup ONE step at a time. After each step, wait for me to say "done" or describe what I see before moving on. Keep each instruction short and tell me exactly where to click.

Security rules you must follow:
- Never ask me to paste any Stripe key (rk_ or sk_) into this chat. I paste keys only into the sheet's Invoice > Setup > Connect Stripe box.
- Only a RESTRICTED key is used, with Invoices: Write and Customers: Read, everything else None. Never tell me to use a secret (sk_) key.
- The customer id (cus_...) is fine to share with you.

The steps:
1. Copy the sheet: open the template link from my purchase email or the thanks page and choose File > Make a copy. Rename it for my client. Work only in my copy.
2. Authorize: reload my copy, click Invoice > Setup > Check the Stripe connection. Google shows "Google hasn't verified this app" for every copied script. Click Advanced, then Go to Hourly Invoice Sheet (unsafe), then Allow.
3. In Stripe: Customers > Add customer with my client's name and billing email. Copy the cus_ id.
4. In Stripe: Developers > API keys > Create restricted key, named "Invoice sheet". Invoices = Write, Customers = Read, all else None. Copy it.
5. In the sheet: Invoice > Setup > Connect Stripe, paste the restricted key.
6. Setup tab, required: RATE (number, e.g. 85), CLIENT_NAME, STRIPE_CUSTOMER (the cus_ id). Optional: CURRENCY (usd), BILLING_PERIOD (weekly, biweekly or monthly), FIRST_PERIOD_START (YYYY-MM-DD), DUE_DAYS (7), ROUND_TO (0.25), PERIOD_CAP_HOURS, TERM_CAP_HOURS, PAYMENT_METHODS (card, or us_bank_account,card), CATEGORIES, SERVICE, FOOTER_NOTE, YOUR_EMAIL. Then run Invoice > Setup > Check the Stripe connection; it should name my customer.
7. Invoice > Add the next invoice period.
8. Recommended test run: switch Stripe to Test mode, make a test customer and a test restricted key, connect it, log a short block (Invoice > Start a work block, then Stop the open block), run Invoice > Review and send (a black TEST banner shows), create the invoice, pay it with card 4242 4242 4242 4242, then Invoice > Refresh paid status. When the row says Paid, reconnect with my live key and live customer id.
9. Finally: Invoice > Setup > Turn on the daily 7am check.

If something goes wrong:
- No Invoice menu: reload the sheet and wait 10 seconds.
- "No such customer": the cus_ id and the key are from different modes (test vs live) or different Stripe accounts.
- Permission or 401 errors: the key is wrong, expired, or missing Invoices: Write.
- The review screen warns about open blocks, duplicates or caps: fix those rows in the Log tab first.

Start with step 1 and ask me what I already have (Google account, Stripe account, the template link).

Never paste a Stripe key into any chat. Keys go only into the sheet's Connect Stripe box.

How it works

Four moments, all inside your own Google Sheet and your own Stripe account.

  1. 1

    Track your time

    Invoice menu, Start a work block. Stop when you finish. Hours fill in.

  2. 2

    Review on one screen

    On invoice day it totals the period and checks for mistakes before anything is created.

  3. 3

    Your client gets a Stripe invoice

    Sent from your Stripe account, with a Pay button and the full time log at the bottom.

  4. 4

    You hear when it is paid

    A daily check reads Stripe and emails you. It never sends anything to your client on its own.

Your Google Sheet→Your Stripe account→Your client pays you

What you get

A Google Sheet with three tabs and a script that adds an Invoice menu. Everything runs from that menu.

  • Setup: your rate, client, billing period and a few options.
  • Log: one row per work block. Start and Stop stamp the times; Hours computes itself.
  • Invoices: one row per billing period. The script fills hours, amount, status, the Stripe link and the paid date.

Before you start

You need a free Stripe account and a Google account. Your client needs nothing; they get an ordinary Stripe invoice email with a Pay button. Invoices go out from your Stripe account and the money goes to your bank.

Setup, step by step

  1. Copy the sheet. Open the template link from your purchase email or the thanks page and choose File, Make a copy. Rename it for your client and work only in your copy.
  2. Authorize the script. Reload your copy, then Invoice, Setup, Check the Stripe connection. Google shows "Google hasn't verified this app" for every copied script. Click Advanced, then Go to Hourly Invoice Sheet (unsafe), then Allow. The script can edit this spreadsheet only, call Stripe, email you and run a daily timer. It never reads your other files or your Gmail.
  3. Create the customer in Stripe. Customers, Add customer. Enter your client's name and the email the invoice should go to. Copy the customer id, which starts with cus_.
  4. Make a restricted key. Developers, API keys, Create restricted key. Name it "Invoice sheet". Invoices: Write. Customers: Read. Everything else: None. Copy it (it starts with rk_).
  5. Connect. Invoice, Setup, Connect Stripe. Paste the restricted key. It is stored in the script's own properties and never appears in the sheet.
  6. Fill in the Setup tab (settings below), then run Invoice, Setup, Check the Stripe connection. It should name your customer.
  7. Add your first period. Invoice, Add the next invoice period. Run it again whenever you need the next one.
  8. Dry run in test mode (recommended). In Stripe switch to Test mode, make a test customer and a test restricted key, connect with the test key, log a short block and run Invoice, Review and send. A black TEST banner shows. Create the invoice, pay it with Stripe's test card 4242 4242 4242 4242, then Invoice, Refresh paid status. When the row says Paid, reconnect with your live key and live customer id.
  9. Turn on the daily check. Invoice, Setup, Turn on the daily 7am check.

Why a restricted key: it can only create invoices and read customers. It cannot move money, change your bank account or read payments. If it ever leaks, roll it in Stripe and paste the new one.

Setup tab settings

Required

RATE
Your hourly rate as a number, for example 85.
CLIENT_NAME
How the client is named on the invoice and the review screen.
STRIPE_CUSTOMER
The cus_ id from step 3.

Optional, with defaults

CURRENCY
usd. Also eur, gbp, cad, aud.
BILLING_PERIOD
biweekly. Also weekly or monthly.
FIRST_PERIOD_START
First day of your first period, for example 2026-10-01. Blank means today.
DUE_DAYS
7. Days after the period ends that the invoice is due.
ROUND_TO
0.25 rounds billed hours to the quarter hour. Blank means exact.
PERIOD_CAP_HOURS, TERM_CAP_HOURS
Contract hour caps. The script refuses to invoice over a cap unless a row in the period has Approved overage? set to Yes.
PAYMENT_METHODS
card. Use us_bank_account,card to offer ACH first.
CATEGORIES
The Category dropdown, comma separated.
SERVICE
The phrase on the invoice line, for example Design retainer.
INVOICE_DESCRIPTION, LINE_DESCRIPTION
Templates. Fields: {service} {client} {period} {number} {due_days} {hours} {rate}.
FOOTER_NOTE
A line under the time log on the invoice, for example "ACH preferred."
YOUR_EMAIL
Where the daily check emails you. Blank means the account running the script.

Daily use

  • Start work: Invoice, Start a work block. Pick a category and describe the task.
  • Stop: Invoice, Stop the open block. Hours fills in.
  • Invoice day: Invoice, Review and send the current invoice. Read the warnings, click Create and email, then click again to confirm.
  • Getting paid: the daily check refreshes paid status and emails you when the client pays, on invoice day, and when anything is overdue. It never sends anything to your client on its own.

What the review screen checks

  • Duplicate rows (same date, start and end).
  • Open blocks with no End time, which would bill zero.
  • Rows with no category.
  • Hours over your period or term cap without approved overage.
  • Periods that end today, so you log today's work first.
  • Whether Stripe is connected. If Stripe's total does not match hours times rate, the invoice is voided and nothing is sent.

Troubleshooting

  • No Invoice menu: reload the sheet and wait about ten seconds.
  • "No such customer": the customer id and the key are from different modes (test and live) or different Stripe accounts.
  • Permission or 401 errors: the key is wrong, rolled, or missing Invoices: Write.

FAQ

More than one client?

Make one copy of the sheet per client. Each copy has its own Setup tab and Stripe customer. One restricted key can serve all of them.

Can my client see the log?

The full log is printed in the invoice footer. For a live view, share a filtered copy of the Log tab.

Fixed-fee invoices?

Not in this version. It bills hours times rate. For a fixed fee, create that invoice directly in Stripe.

Taxes?

It sends the amount you logged. For sales tax or VAT, turn on Stripe Tax for the customer; the script does not add tax lines.

Changing my rate mid-contract?

Change RATE on the Setup tab. Invoices already created keep the rate they were sent with.

Refunds?

If the sheet does not work for you within 14 days, email cayla@quorra.agency with your purchase email for a full refund.

Privacy

The script runs in your Google account and talks only to Stripe's API. Nothing is sent to Quorra Agency. Your Stripe key stays in your script's properties.