StudioDocs
Invoice Studio documentation

From first setup to a sent invoice.

Practical guides for running Invoice Studio day to day, plus an exact self-hosting reference for operators. Every behavior here is grounded in the current product.

Start here

Product overview

Invoice Studio is a multi-workspace invoicing app for freelancers, founders, and small teams. It saves customer companies, payout accounts, and sender identities, then combines them into GST-ready INR invoices and generated PDF documents.

Core concepts

ConceptWhat it meansChoose it when
OrganizationAn isolated workspace containing its own customers, profiles, invoices, documents, and members.You operate a separate business or need a hard data boundary.
CompanyThe customer being billed.You want to reuse a customer’s address, GSTIN, and delivery email.
Sender profileThe identity printed on an invoice, including PAN, GSTIN, GST rate, branding, email, and signature.You bill through different legal identities or tax contexts.
Bank detailsThe payout instructions printed on the invoice.You receive money into different accounts or currencies.
Draft / issuedDrafts remain editable. Issued invoices are final in the current product.Use draft while facts may change; issue only after review.
What Invoice Studio does not do

It does not process payments, reconcile bank transactions, create recurring invoices, support multiple currencies, or keep an audit-history screen. “Paid” is a manual tracking flag.

Getting started

Your first successful workflow

The reliable order is sender → bank → customer → invoice. This avoids reaching the invoice form without the reusable records it expects.

  1. 1

    Create an account and organization

    Sign up with email and a password of at least 6 characters, or use Google if the deployment enables it. Name your first organization.

  2. 2

    Create a sender profile

    Open Sender Profiles. Add the email that should receive customer replies, your tax identity, a GST rate, invoice headings, and an optional PNG signature.

  3. 3

    Add payout details

    Open Bank Details. Save the account name, number, bank, branch, IFSC and, when needed, SWIFT. A tag helps distinguish similar accounts.

  4. 4

    Save the customer

    Open Company Details. Name is required. Add the customer email before you intend to send from the app.

  5. 5

    Create and issue

    Open Invoice Workspace, choose the saved records, set an issue date, add descriptions and amounts, review GST and total, then choose Issue Invoice.

  6. 6

    Generate or send the PDF

    Preview HTML first if desired. Generate a PDF for the Documents library, or send it to the company email. Sending always renders a fresh PDF.

Everyday workflows

Workspaces and switching

Organizations separate all operational records. Your most recently selected organization is saved in this browser as activeOrganizationId. With one membership the app selects it automatically; with several, it asks you to choose.

How to create or switch

  1. 1

    Open the organization switcher

    Use the workspace control in the dashboard sidebar.

  2. 2

    Select an existing workspace

    The dashboard reloads data in that organization context.

  3. 3

    Or create another

    Choose the new-organization option and enter a non-empty name. The creator becomes its owner.

Data never follows a switch

Companies, sender profiles, bank details, invoices, PDFs, and team membership stay inside their organization. Recreate a record when it is genuinely shared; there is no cross-workspace copy operation.

Everyday workflows

Customer companies

Use companies for reusable bill-to information. Do not create a company for your own identity—that belongs in Sender Profiles.

UI fieldAPI propertyRequiredBehavior
NamenameYesTrimmed before storage; the only server-required company field.
GSTINgstinNoPrinted with the customer address; format is not validated.
EmailemailNo for saving; required for sendingBrowser validates email shape. Server requires a non-empty saved value before send.
AddressaddressNoLine breaks are retained in the invoice address block.
NotesnotesNoInternal saved text; not rendered on invoices.

How to: add details and select Save Company. Use Edit to update the same record. Duplicate fills a new unsaved form; save it to create a separate company. Search currently matches company name only.

Everyday workflows

Bank details

A bank record supplies payment instructions on the generated invoice. Choose a specific record per invoice. If an invoice has none selected, rendering falls back to the newest bank record in the organization.

UI fieldAPI propertyDefaultNotes
Account NameaccountNameemptyPrinted as account holder.
Account NumberaccountNumberemptyStored as text; no checksum or masking.
Bank NamebankNameemptyPrinted in payment details.
BranchbranchemptyPrinted in payment details.
IFSCifscemptyNo format validation.
SWIFTswiftemptyThe row is omitted from the PDF when empty.
TagtagemptyOrganizational label such as Primary or USD.
Tag ColortagColor#0f766eFive presets plus a custom color picker.
NotesnotesemptyInternal; not printed.

When not to use it: do not place card numbers, passwords, or online-banking secrets here. These fields are shared with every member who can read the organization.

Everyday workflows

Sender profiles

Sender profiles let one organization bill from different identities. The selected profile controls GST calculation and the identity, tax, branding, signature, and reply address used in the invoice.

UI fieldAPI propertyDefault / validationEffect
TagtagemptyPicker label only.
Tag ColortagColor#0f766eVisual distinction in pickers.
Sender NamesenderNameoptionalShown near the signature and used as the invoice-email sender name fallback.
EmailemailRequired by UI and for sendingLowercased; replies to invoice emails go here.
PANpanemptyPrinted with the sender tax block.
GSTINgstinemptyPrinted when the PAN block is present.
Invoice HeaderheaderNameemptyMain invoice heading/brand text.
Invoice TaglineheaderTaglineemptySupporting header text.
GST Rate (%)gstRate18UI minimum 0 and step 0.01. Server does not enforce a maximum.
Invoice FooterfooterTextPDF fallback: “Thank You for Your Business”Footer printed on the PDF.
SignaturesignaturePathoptional PNG onlyPNG data URL, valid PNG bytes, .png filename, maximum 5 MB.
Choose the tax rate deliberately

GST is applied to the complete subtotal. Use 0 for a zero-tax invoice. The app does not model per-line tax rates, tax categories, discounts, withholding, or cess.

Everyday workflows

Create an invoice

Invoice numbers are assigned automatically per organization as INV-001, INV-002, and so on. The visible invoice-number field is read-only in practice: the server assigns the committed number.

FieldRequiredDefaultValidation and calculation
CompanyYesnoneMust reference a company in the active organization.
Bank DetailsNonone selectedIf omitted, PDF rendering uses the newest bank record.
Sender ProfileNonone selectedIf omitted, calculation/rendering use the newest profile; GST defaults to 18 if no usable profile rate exists.
Issue DateYestoday when the form opensSent as a date string.
Line descriptionUI: yesone empty rowTrimmed by the server.
Line amountUI: yes0Converted to a number. Server does not reject negative values.
StatusYes by actionissued unless explicitly draftOnly the exact value `draft` stays editable.

Draft versus issued

ActionUse whenResult
Save DraftDetails may still change.Number is reserved and the invoice can be edited later. PDF generation and sending are blocked.
Issue InvoiceThe customer, dates, lines, and tax are final.The invoice becomes immutable in the current app and can be rendered or sent.
Calculation rule

subtotal = sum(item.amount), GST = subtotal × profile GST rate / 100, and total = subtotal + GST. Currency formatting and amount-in-words are INR/rupees.

Everyday workflows

Manage invoices

The invoice list supports company, draft/issued, paid/unpaid, and issue-date-range filters. Filters affect the current browser view; they are not saved to the server.

How to handle common jobs

  1. 1

    Edit a draft

    Choose the edit action on a Draft row, change fields, then save as draft or issue. Issued rows cannot be edited.

  2. 2

    Preview before PDF

    Open the HTML preview. It is membership-protected and uses the latest related records currently saved.

  3. 3

    Generate a PDF

    Use Generate PDF on an issued invoice. A fresh PDF is uploaded to object storage and linked to the invoice.

  4. 4

    Send an invoice

    Ensure both customer and sender-profile emails exist. Sending renders a fresh PDF, emails it as an attachment, and saves the same generated document.

  5. 5

    Track payment

    Toggle paid/unpaid manually. Marking paid stores the current timestamp; marking unpaid clears it. No payment is collected.

Everyday workflows

Documents

Documents lists invoices with a currently stored PDF, newest first. Each entry includes its invoice number, customer, total, creation time, and short-lived signed view/download links.

How to delete a PDF: choose Delete in Documents. This removes the object and clears the invoice’s PDF link; it does not delete the invoice. Generate again from the issued invoice when needed.

Signed links expire

Generated view and download URLs expire after one hour by default. Reload Documents to receive fresh links.

Teams & access

Team members

Only owners can open Team, invite people, change roles, remove members, or revoke pending invitations. Invitation links expire after one hour. Existing users accept and then sign in; new users create a password of at least 6 characters during acceptance.

  1. 1

    Invite

    Enter the person’s email and choose Read, Edit, or Owner. Avoid Owner unless they must administer access.

  2. 2

    Wait for acceptance

    The pending invitation remains visible to owners and can be revoked before acceptance.

  3. 3

    Adjust access

    Change a member’s role as responsibilities change, or remove the membership. Their account and other organizations remain intact.

Teams & access

Roles and permissions

CapabilityReadEditOwner
View companies, profiles, bank details, invoices, and documentsYesYesYes
Create or update operational recordsNoYesYes
Generate/send PDFs, change payment state, delete stored PDFsNoYesYes
View and administer members/invitationsNoNoYes
No audit-history feature

The database records creation times and invoice payment timestamps, but the product has no user-facing audit log of who changed what. If you require compliance-grade history, add it before relying on the app for that purpose.

Account

Sign-in and recovery

Email/password accounts require a password of at least 6 characters. Sessions use an HTTP-only sid cookie lasting 30 days, SameSite=Lax, and Secure only when NODE_ENV=production. Google sign-in appears only when a client ID is configured.

Password-reset responses do not disclose whether an email exists. Reset links expire after one hour and can be used once. Logging out deletes the server session and clears the cookie.

Reference

Integrations and failure behavior

IntegrationConfigurationPrecedence / failure behavior
MySQLDB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAMERequired at startup. Connection or schema initialization failure stops the server.
S3-compatible storageS3_ENDPOINT, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET_NAMERequired when uploading signatures or PDFs. Missing credentials fail that operation; signed URLs default to 1 hour.
Browserless / ChromiumPUPPETEER_BROWSER_URLRequired for PDF and send. An empty value returns “PUPPETEER_BROWSER_URL is not configured.”
ResendRESEND_API_KEY, EMAIL_FROM, EMAIL_REPLY_TO, CONTACT_EMAILWhen the API key is absent, mail is logged and the operation reports success; nothing is delivered. Invoice replies override the default reply-to with the selected sender email.
Google IdentityGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRETEmpty client ID hides the button. Invalid/missing credentials make Google sign-in fail without affecting password sign-in.
Reference

Troubleshooting

SymptomLikely causeConcrete fix
“Missing organization context”No active organization was selected or browser storage points to an unavailable one.Return to the organization picker and choose a workspace.
“Edit permission is required”The member has Read access.Ask an owner to assign Edit only if changes are needed.
PDF generation failsBrowser WebSocket missing/unreachable, S3 misconfigured, or Chromium failed.Verify PUPPETEER_BROWSER_URL from the app container, Browserless health/token, and S3 credentials/bucket permissions.
Invoice email never arrives but send says successRESEND_API_KEY is empty, so email is log-only.Configure Resend, verify EMAIL_FROM, then send again.
“Add an email address…”Customer or selected sender profile lacks email.Edit the corresponding saved record, then retry.
Cannot edit an invoiceIt is issued.The implementation intentionally allows edits only on drafts; create a new invoice for corrections.
Signature upload rejectedWrong extension/MIME, invalid PNG bytes, or file exceeds 5 MB.Export a genuine PNG named .png at 5 MB or less.
Old/stale document URLThe signed S3 URL expired after one hour.Reload Documents or regenerate the PDF.
Server will not startMySQL is unreachable or the user cannot create/use the database.Test network/DNS and grant access to DB_NAME; inspect container logs.
Invite/reset link rejectedThe link is expired or already used.Issue a new invitation or password-reset request; links last one hour.
Reference

Known limits and precise behavior

The current product has no invoice deletion, issued-invoice correction, recurring billing, payment gateway, automated reminders, per-line tax, discounts, multiple currencies, data import/export, workspace deletion, member activity audit, API-token system, or user-managed secret vault. These are intentionally not documented as available features.

Some database columns are more permissive than the UI: company phone exists server-side but has no current UI field; due date exists in storage but the current invoice form does not expose it; server-side tax and amount validation is limited. Operators should not treat database acceptance as a supported user workflow.

Naming convention

Frontend request bodies use camelCase such as accountName, personalInfoId, and gstRate. Database rows and most response properties use snake_case such as account_name, personal_info_id, and gst_rate.

Was this documentation helpful?