Skip to main content

Your business runs on trust. So does ours.

We handle your customer list, your invoices, and the money your customers send you. That is not a responsibility we take lightly. This page tells you exactly how we protect your data, what we will never do with it, and who to contact if something looks off.

No marketing fluff. Just the facts.

TLS 1.2+

Every connection encrypted in transit. Same tech your bank uses.

Stripe & PayPal

PCI-DSS Level 1 processors handle card data — we never see it.

U.S. infrastructure

Railway, Vercel, Postmark — all operated from United States regions.

Not for sale

Your data isn't sold, shared, or used to train AI. Ever.

What we do

The controls actually protecting your data.

Every claim below maps to a specific piece of the codebase or a specific provider relationship. Jargon is explained the first time it appears.

Encryption in transit

Every connection to Invoice Link — from your phone, from the web dashboard, from the link your customer taps to pay — is protected with TLS 1.2 or newer. TLS is the same technology your bank uses. It scrambles the data while it moves across the internet so nobody sitting on the same coffee-shop Wi-Fi can read it.

Our API and web dashboard also send a browser instruction called HSTS (HTTP Strict Transport Security) with a one-year lifetime. Once your browser has visited us once over HTTPS, it refuses to ever connect over plain HTTP again — even if someone tries to trick it.

Encryption at rest

The database that stores your invoices, customers, and business details is a managed Postgres database hosted on Railway. Railway encrypts the underlying storage at rest using industry-standard disk encryption. If someone physically stole the hard drive, the data on it would be unreadable without the encryption keys, which Railway manages.

Authentication

The web dashboard uses httpOnly cookies to keep you signed in. "httpOnly" means the cookie is only sent back and forth between your browser and our server — JavaScript running in the page cannot read it. That closes off an entire class of attacks where a bad script tries to steal the cookie.

Mobile apps use short-lived access tokens with a paired refresh token stored in the device's secure keychain (iOS Keychain, Android Keystore).

Every refresh token is rotated on use. The old one is deleted and a new one issued inside a single database transaction. If an attacker somehow copied an old refresh token, the moment either of you used it, the other would be booted out. Refresh tokens expire after 7 days of inactivity.

Logins, refreshes, password changes, and password resets are rate-limited to 10 requests per 15 minutes per IP. Passwords are hashed with bcrypt at cost factor 12 — we never store the password itself. Forgot-password responses are timing-equalized with 200–400 ms jitter so attackers can't tell whether an email is registered by measuring response times.

Public link protection

When you text or email a pay link, you don't want a stranger who guesses or intercepts the invoice ID to be able to read your customer's name, address, line items, and total owed.

Every pay link is signed with an HMAC — think of it as a tamper-proof wax seal. The link looks like:

https://invoicelinkapp.com/pay/abc123…?t=<signature>&d=<day-issued>

The t= portion is a cryptographic signature we compute using a secret only our server knows. If anyone changes a single character of the URL, the signature no longer matches and the link is rejected with a 401. Guessing the signature is computationally infeasible.

Links expire after 60 days. If we ever suspected a secret had leaked, we could rotate it and instantly invalidate every outstanding pay link without touching the database.

Payment security — we never see card numbers

We do not see, store, or process credit card numbers. Ever.

When your customer pays, we hand them off to Stripe or PayPal — both of which are PCI-DSS Level 1 certified, the highest tier in the payments industry. The card number, CVV, expiration, and billing details are entered on their servers, not ours. We receive only the non-sensitive metadata back: payment ID, last-four digits, brand, amount, currency, success or failure.

Even in a worst-case breach scenario, there are no card numbers for attackers to steal from us. We cannot leak what we do not have.

Webhook security

When Stripe, PayPal, or our email provider wants to tell us that a payment succeeded or an email was opened, they send a webhook — a small POST request to our server. We verify every webhook before acting on it:

  • Stripe webhooks are signed with Stripe's signing secret and verified using Stripe's official library. A forged request is rejected with a 400.
  • PayPal webhooks are verified using PayPal's transmission signature.
  • Postmark webhooks (our email provider) use HTTP Basic Auth over HTTPS with credentials in our server's environment. The comparison uses a timing-safe algorithm so an attacker cannot learn the password by measuring response times.

If a webhook fails verification, we respond with 401 and log nothing to the database. No action is taken.

Race-condition safety

Imagine your customer taps "Pay" twice on a slow connection, or Stripe delivers the same webhook twice. Without careful design, either could become a double-charge.

We handle it with a database feature called SELECT ... FOR UPDATE. When a payment lands, we open a transaction, lock the invoice row, re-read the current paid amount, and only then decide whether to accept the payment. A second payment arriving at the same instant has to wait for the first to finish.

We also make marking an invoice as paid idempotent — calling it twice is a no-op, not a duplicate record. Scheduled jobs (overdue reminders, recurring invoice generation) use Postgres advisory locks so two server instances cannot both send the same reminder.

Infrastructure

We run on well-known cloud providers, not homebrew servers in someone's basement.

  • Railway hosts the application server and the Postgres database. U.S. region.
  • Vercel hosts the marketing site and web dashboard on its global CDN. HTTPS is terminated at the edge.
  • Postmark sends transactional email (invoices, receipts, reminders, password resets).
  • Stripe and PayPal process payments.

Each of these is a public company or well-funded private company with published security practices, SOC 2 reports, and a vested interest in not being the next breach headline.

Access control

We follow the principle of least privilege.

  • No engineer routinely accesses production data. Day-to-day debugging uses logs (which deliberately exclude sensitive fields) and anonymized staging data.
  • Production database access is gated behind individual cloud-provider accounts with two-factor authentication on every staff account.
  • API keys and secrets live in environment variables inside the hosting providers — never in source code, never in the Git repository.
  • Secrets are rotated when an engineer leaves or when there's any reason to suspect exposure.

Backups & monitoring

Railway takes daily automated backups of the Postgres database with 7-day retention. Backups are encrypted, isolated from the live database, and recoverable by our team in minutes. If a catastrophic data-loss event ever occurred, we could restore to any day within the last week.

Honest answer on monitoring: Sentry is wired into both mobile and server for crash + error tracking with PII scrubbed before transmission. Better Stack (Logtail) aggregates operational server logs with the same redaction guarantees. Railway's built-in log streaming and Vercel's request analytics give us a second view of real-time logs, status-code errors, and crash alerts. Our API also exposes a /health endpoint that returns database connectivity status for any future uptime monitor.

What we don't do

Shorter list. Equally important.

We don't sell your data

Not to ad networks, not to data brokers, not to anyone. Your customer list is yours.

We don't train AI on your data

Our AI features (on-device OCR, optional AI vision fallback for receipt fallback) process data for the single task you asked for. It is not used to improve anyone's model.

We don't share your customer list

Not with other Invoice Link users, not with advertisers, not with anyone. Each business only sees its own data.

We don't keep full card numbers

Stripe and PayPal handle card data. We see only last-four digits, brand, and a reference ID we can never turn back into a card.

We don't email-market to your customers

The only emails we send your customers are the ones you explicitly trigger: invoices, receipts, reminders, review requests you enabled.

Compliance

Honest about where we are.

We would rather tell you where we are than pretend we are somewhere we are not.

SOC 2

Not yet certified

Not certified. SOC 2 is a third-party audit that costs six figures and 12+ months. We plan to pursue it as we scale. This page describes the controls SOC 2 would audit — we already have most of them.

HIPAA

Not applicable

Not compliant. Invoicing a plumber's work isn't covered by HIPAA. If a customer notes health information in an invoice, don't use this app for that — use a HIPAA-covered system.

CCPA

Honored

We honor California Consumer Privacy Act rights. California residents can request a copy of their data, request deletion, and opt out of any sale (we don't sell it either way).

GDPR

Best-effort

Invoice Link is intended for U.S. users. For EU/UK signups we honor GDPR rights on a best-effort basis: access, portability, correction, deletion, restriction, objection. Data is hosted in the U.S.

PCI DSS

Honored

Not a merchant in the PCI sense — we never touch card data. Stripe (PCI DSS Level 1) and PayPal handle that boundary for us.

Third-party processors

Everyone we hand data to. What they do with it.

Stripe

Credit card, Apple Pay, Google Pay, Link, ACH, and ACH payments.

PCI DSS Level 1 certified.
Privacy & security docs

PayPal

Alternate payment method. Processes PayPal account payments.

PCI DSS Level 1 certified.
Privacy & security docs

Postmark

Transactional email — invoices, receipts, reminders, review requests, password resets.

Does not use your data for marketing.
Privacy & security docs

Railway

Application server and Postgres database hosting. U.S. region.

Encryption at rest, daily backups, SOC 2 Type II.
Privacy & security docs

Vercel

Hosts the marketing site and web dashboard on a global CDN.

HTTPS at edge. Does not see the database.
Privacy & security docs

Google

Address autocomplete (Google Places) and optional Street View on customer profiles.

Standard Google Maps Platform terms.
Privacy & security docs

Rentcast

Optional property data lookups (sq ft, bed/bath, year built).

Capped at 40 lookups per business per month.
Privacy & security docs

Responsible disclosure

Found something? Please tell us.

Email us

support@invoicelinkapp.com

Initial acknowledgment within 2 business days. Confirmed issues are triaged and patched promptly.

No public bug bounty yet, but we read every report, credit you by name (or keep you anonymous — your call) once the fix ships, and treat coordinated disclosure as a professional courtesy.

PGP key available on request.

What counts

  • Authentication or authorization bypass
  • Injection or remote code execution
  • Signed pay-link verification bypass
  • Viewing/modifying another user's data
  • XSS, CSRF, or clickjacking on the web app
  • Leaked secrets in code or Git history
  • Charging a card the attacker doesn't own

Security changelog

An ongoing practice, not a one-time check.

We publish this so you can see security is a habit, not a headline.

Full security audit + hardening pass

  • Payment writes now take SELECT FOR UPDATE on the invoice row before applying — double-click and webhook-retry races closed.
  • Mark-paid made idempotent: calling it twice is a no-op, not a duplicate record.
  • Refresh and change-password endpoints rate-limited to 10 requests per 15 min.
  • Logout verifies refresh-token signature and ownership before revoking — stolen tokens can no longer log victims out.
  • Changing your password revokes every session on every device.
  • Forgot-password responses timing-equalized (200–400 ms jitter).
  • Postmark webhooks now require HTTP Basic Auth with timing-safe comparison.
  • HMAC pay/estimate link expiry tightened from 180 days to 60 days — shrinks the replay window on screenshot leaks and log scrapes.

HMAC pay URL signing shipped

  • Every pay link now carries a 24-character HMAC signature. A bare invoice ID is no longer enough to read an invoice.
  • Pay link tokens embed the issue day and expire after 180 days.
  • Server startup refuses to boot in production with a weak or missing JWT secret.
  • Apple App Store Connect API key rotated as a precaution; Git history scrubbed of credential files.

httpOnly cookies for the web dashboard

  • Web dashboard migrated from localStorage JWTs to httpOnly cookies — tokens can no longer be read by any script running on the page.
  • Refresh token lifetime tightened from 30 days to 7 days.
  • Refresh rotation made atomic: old session deleted and new one created in a single transaction.

Advisory locks on cron jobs

  • Postgres advisory locks now wrap every scheduled job (overdue reminders, recurring invoice generation).
  • Two server instances can no longer send the same reminder or generate duplicate recurring invoices.
  • Migrated from Resend to Postmark with delivery, open, click, bounce, and spam-complaint tracking.
  • All email sends retry up to 3× on transient failures with exponential backoff.

Frequently asked

Short answers to fair questions.

Can an Invoice Link employee read my invoices?

In principle, yes — anyone with production database access can query any row. We keep that access tightly scoped: it's used for support (when a customer emails us with explicit permission to look) or for debugging real outages. It is not used to browse customer data for fun or for internal analytics.

Practically, our team is small and we have no internal tool that surfaces invoice contents in a dashboard. Every read is a deliberate Prisma query by a specific engineer for a specific reason.

What happens if I close my account?

Close it from Settings → Subscription → Cancel and request deletion by emailing support@invoicelinkapp.com. We delete the data associated with your account. Some records are retained for tax and legal purposes (payment records we're required to keep for audit), but identifying information is stripped from anything we don't legally need.

Closing your account also severs any signed pay links — your customers can no longer open them.

Where is my data physically located?

In the United States. Railway hosts our Postgres database in a U.S. region. Postmark, Stripe, and PayPal each maintain U.S. infrastructure and are contractually bound to their own privacy commitments. Vercel serves static files from the edge node nearest your visitor — the files are the marketing site and the web dashboard bundle, not your invoice data.

What would you do if you had a breach?

Three things, in order:

  1. Contain it. Rotate the compromised secret, revoke sessions, patch the hole.
  2. Understand it. Review logs, figure out what was accessed, for how long, by whom.
  3. Tell you. Email affected users within the window required by law (72h under GDPR, 30–60 days under most U.S. state laws), plain-English, no corporate hedge.

We haven't had a breach. If we ever do, we'll be straight with you about it.

What if my phone is stolen?

Sign in to the web dashboard from any browser and change your password at Settings → Change Password. Changing your password revokes every session on every device, which forces the thief's copy of the app to log out the next time it calls the server.

Do you send my data to OpenAI?

Only for specific features you opt into, and only the minimum data needed:

  • Receipt OCR fallback: if on-device ML Kit OCR fails, we call our AI vision fallback with the receipt image. Not retained for training under the provider's API terms.
  • AI invoice assistance: we send only what you typed (e.g., "3 hours labor, kitchen sink install"). We do not send your customer list or business history.

No AI feature automatically runs in the background on your data. You trigger each call yourself.

I'm a developer — where can I see your security implementation?

Most of the security-relevant code lives in a few files:

  • server/src/utils/signedLinks.ts — HMAC-signed pay URLs
  • server/src/routes/auth.ts — httpOnly cookies, token rotation, bcrypt, rate limits
  • server/src/routes/webhooks.ts — Postmark HTTP Basic Auth
  • server/src/services/cronJobs.ts — Postgres advisory locks
  • server/src/routes/payments.ts — SELECT FOR UPDATE on invoice rows

The repo isn't open-source today, but if you're a security researcher and want to verify a claim, email us and we'll share the relevant snippet.

Have a question we didn't answer?

Real people, real answers. Usually within a business day.

support@invoicelinkapp.com

Our mission

Every tradesperson deserves to get paid the day the job is done.