Skip to main content
FixAdSpend — Stop wasting. Start growing. Back to FixAdSpend

Security

Plain-English summary of how FixAdSpend handles your credentials, your ad-account data, and incident response. Procurement folks: the full version of any section below is available on request to admin@fixadspend.ai.

Credentials

OAuth refresh tokens (Google Ads, Meta Ads, Shopify) are stored encrypted at rest with AES-256-GCM, keyed off a 32-byte TOKEN_ENCRYPTION_KEY that lives only in Vercel's encrypted environment variables and is never checked into git. Decryption only happens at the moment a sync request is fulfilled.

Stripe webhook events are verified with HMAC-SHA256 against the Stripe-supplied STRIPE_WEBHOOK_SECRETbefore any handler logic runs.

Passwords (when the user signs up with email/password rather than OAuth) are bcrypt-hashed at 12 rounds via bcryptjs.

OAuth scope minimization

We request the smallest possible OAuth scope per integration:

Data storage + tenant isolation

Production data lives in Neon Postgres (us-east-2). All tenant-scoped tables include a userId column; every API route filters by the authenticated user's id (via NextAuth session) before returning any row. No row-level policy bypass exists for staff or anyone else — staff access requires the same auth check plus a server-side role check against an explicit allowlist in lib/roles.ts.

We do not log full ad-account contents to application logs. Stack traces sent to our Sentinel (/status) are scrubbed of token-shaped strings before storage.

Third-party data sharing

Two third parties touch your data and only at request time:

  • Anthropic (Claude API). Campaign metrics (numbers + campaign names, no PII about your customers) are sent when an AI agent runs. We use Anthropic's zero-data-retention mode — they don't retain the data for training or any other purpose.
  • Stripe. Billing details only — your card, your billing address, your tax id. Stripe is the card-of-record processor. We never store the PAN, CVV, or full card number on our side; the only thing we hold is Stripe's customerId + their paymentFingerprint (used for abuse prevention).

We do not use your data for advertising, retargeting, or any kind of analytics resale. We do not train models on your data.

Data export + deletion

Under GDPR Art. 15 (data access) and Art. 17 (erasure), you can:

  • Export everything we have about your account as a single JSON file from Data & privacy settings.
  • Hard-delete your account. We soft-delete on click (reversible for 14 days to protect against accidental clicks), then a nightly cron permanently removes all records.

For users on a Meta-integrated account who use Meta's in-platform deletion request, /data-deletion handles the Meta-initiated callback automatically.

Incident response

Production build errors are captured by our Vercel Sentinel webhook into deduplicated BugTicket rows, with a daily digest email to admin@fixadspend.ai. Severity 1 incidents (data loss, auth bypass) trigger an immediate page to the on-call engineer's phone via Twilio.

If a user's data is potentially affected, we commit to email-notifying every affected user within 72 hours and publishing a public post-mortem on the blog within 14 days.

Procurement / vendor questionnaire? Email admin@fixadspend.ai — we'll turn it around within two business days.