Security and trust
Last reviewed 2026-09-23. Every claim on this page describes the software as it is shipped today.
You are about to give an AI agent access to the accounts that spend your money. That is a reasonable thing to be careful about, so here is exactly what we store, how it is protected, what the agent is and is not allowed to do on its own, and how to get all of it back or delete it. The last section is the one most vendors leave out: what we do not have yet.
What we store
Your account. Name, email address, and a password stored only as an Argon2id hash — we cannot read it and cannot tell you what it is. Sessions are HTTP-only, SameSite cookies, marked Secure in production, with a fifteen-minute access token and a rotating refresh token. Settings → Profile lists every device you are signed in on, and signs any of them — or all but this one — out.
Your business context. What you tell the Business Brain: your positioning, offers, audiences, economics, and anything you upload to the knowledge base.
A copy of your advertising data. When you connect a channel we mirror its campaigns, ad sets, ads, budgets, statuses and daily metrics so reporting and the agent can work without hammering the platform’s API.
Credentials for what you connect. OAuth access and refresh tokens, and provider API keys, encrypted at rest — see below.
A record of what happened. Every tool call an agent, a person or an MCP client made, every approval requested and decided, and every change to who has access. That record is what the audit-log export hands back to you.
Encryption
In transit: HTTPS everywhere. The app, the API and the MCP endpoint are served over TLS and nothing about the product works over plain HTTP.
At rest: every platform credential — Meta, Google, Google Ads, TikTok, YouTube, Instagram, Shopify, Local Falcon, and any model-provider key you add — is encrypted with AES-256-GCM before it is written, and decrypted only in the moment a request needs it. The encryption key is held in the environment, never in the database beside the ciphertext.
Passwords are Argon2id hashes. API keys are stored as a SHA-256 hash plus a twelve-character display prefix: the full key is shown once, when it is created, and cannot be recovered afterwards — only replaced.
Who can do what
Access is two layers, and the second is the one agencies care about. Organization-wide, a person is an owner, an admin or a member. A member reaches nothing by default; they reach a specific project only through a grant on it, as an admin, manager, analyst or client.
Those roles resolve onto one ordered permission ladder — read → draft → operate → manage business → manage organization — and every route in the API declares what it costs rather than which role may call it. Two consequences worth stating: a client login is read-only on its own project and can reach nothing else, and a route nobody remembered to annotate costs operate by default rather than being open. Every request to an organization’s data is checked against that membership before the handler runs.
API keys and MCP. A key can be read-only or read-write, and can be confined to a single project — an agency can hand a client’s automation a key that physically cannot see another client. A key acts as the person who created it and stops working the moment they lose membership. Revoking is instant.
Two-factor authentication. Anyone can add an authenticator app (time-based one-time codes) to their account; after that, every sign-in — password or Google — asks for a code, and ten single-use recovery codes cover a lost phone. We keep the authenticator secret encrypted and the recovery codes only as hashes. An organization’s owner can require it of every member: anyone without it is sent to set it up before they can open anything in that organization. There is no SMS option, on purpose.
What the agent is allowed to do
Every action an AI can take — from the Terminal, from a scheduled operator run, or from an MCP client like Claude or ChatGPT — goes through one registry, and each tool in it carries a risk tier. A read runs immediately. A low-risk write runs immediately. A high-risk write — anything that spends money, launches, or changes a live campaign — never runs on its own: it is staged into your approvals inbox and waits for a person, or for a standing grant you set deliberately.
Underneath that sit guardrails: daily and monthly spend ceilings, ROAS floors, geographies and creative angles you have ruled out. A guardrail can only ever refuse — it can never widen what a tier allows — so raising a ceiling cannot quietly promote an agent past the approval gate.
Everything the registry runs is logged, including the calls it refused, and the decision log shows the timeline of every change to a campaign, ad set or ad, with who or what made it. Changes that captured their previous state can be reverted in one click.
Logging and error monitoring
The API emits structured JSON logs with a request id on every line. Credentials, tokens, cookies, authorization headers and API keys are stripped by a redaction pass before anything is written — and the same redaction runs over every error report before it leaves the server, because an error report is a log that leaves the building. Error monitoring is Sentry and it is optional: with no DSN configured, nothing is sent anywhere.
The audit log, exported
An owner or admin can download a CSV of everything that happened in their organization over any date range, from Settings → Organization. It contains agent and human tool calls with their outcome, approvals requested and decided, API keys created and revoked, members added, promoted, granted, revoked and removed, and integrations connected and disconnected. It is your record, not ours — it is a download you can take to whoever is asking you for it.
How long we keep things
A nightly job enforces these windows; they are not a policy we promise and never check.
- Raw daily ad metrics: 730 days. They are re-syncable from the platform they came from, and no report we draw reaches back further.
- Social post insight readings: 730 days. The views and engagement counters we read off your published posts. The score they feed is kept on the asset.
- AI usage records: 400 days. One row per AI call with its tokens and cost — a full year of usage history, plus some slack.
- Tracking health checks: 365 days. The pixel, Conversions API and UTM checks behind the measurement health page.
- Instant-form leads: 730 days. The name, email and phone number someone typed into one of your Meta lead forms, stored encrypted and counted from when the form was submitted.
- Product activation events: 730 days. A short list of milestones — signed up, connected a channel, approved a first action, switched on autopilot — that tells us where new accounts get stuck. They name the step and, at most, the channel or plan; never anything you typed. The same step names are passed to our Google Tag Manager container from the dashboard, so our own marketing reports can count them.
- Outbound webhook delivery log: 30 days. The record of what we sent to your webhook endpoints and how they answered. The alert itself stays in your notifications.
- Everything else — conversations, operator runs, audit records — is kept for the life of the organization by default, because deleting somebody’s history without being asked is not a feature. Shorter windows can be configured on a deployment, and a self-hosted operator sets their own.
- When you disconnect an integration we stop syncing and revoke or delete the stored credential. The data already synced stays until you delete the project or the organization.
Backups and recovery
- The database is snapshotted daily and weekly by our host. Daily snapshots are kept for 6 days and weekly ones for 27 days. In the worst case, a total loss of the database costs up to 24 hours of data. That is our recovery point objective.
- We aim to be back within 1 hour, our recovery time objective. We last rehearsed a full restore on 23 September 2026. We copied the production database into a fresh server, ran migrations, signed in and loaded an ads account. It took under 4 minutes, and every row was accounted for.
- The rehearsal restored a copy, not one of the host’s snapshots. The host can restore a snapshot only over the live database, so that path has not been rehearsed yet.
- Uploaded files are not backed up apart from the storage they live in. Neither is the job queue: scheduled work is rebuilt from the database, but a job that was waiting to run at the moment of a loss has to be started again.
Getting your data out, and deleting it
Export everything. An owner or admin can export the whole organization from Settings → Organization: one JSON file per table the organization owns — every project, its metrics, campaigns, reports, knowledge, conversations and settings — in a zip, emailed as a link that works for 24 hours before the file is deleted. Credentials are left out: access tokens, API-key hashes and the like never leave the database.
Export one table. The audit log downloads as CSV, and so does every metrics table in the app: campaigns, ad sets and ads, daily metrics per ad channel, creatives, AI visibility results and the client roll-up. Client reports download as PDF. Ads, metrics and creative are also readable through the API and the MCP endpoint with your own key.
Delete a project or an integration from the app at any time; the connected credential goes with it.
Delete your own account. Settings → Profile deletes your account after you re-enter your password (or, if you only sign in with Google, sign in with Google again). Immediately: your account, your sessions and the API keys you created are deleted. An organization where you are the only member is deleted with you, everything in it included. An organization you share stays with its other members; if you owned it, ownership passes to its longest-standing admin.
Delete the whole organization. Settings → Organization has a delete that removes the organization, every project under it, every connected account and token, every metric, report, asset, conversation and audit record, and the uploaded files behind them. It is the owner’s alone, it asks you to type the organization’s name back, and it cannot be undone. An organization on a paid plan has to cancel the plan first, so nobody is billed for a workspace that no longer exists.
What is kept after a deletion, and why. In an organization that continues without you, its audit log keeps one entry recording that you left, with your email address, for as long as that organization keeps its audit log; the actions you took there stay in its history with the link to your account removed. Invoices and the billing customer record stay with Stripe, our payment processor, because tax law requires them to be kept. A Meta data deletion request keeps its confirmation code and your Meta user id, so the status page keeps answering.
Connected platforms. Deleting an organization revokes our grants at Meta, Google, TikTok and Shopify as well as deleting the stored tokens, and disconnecting Google, TikTok or Shopify revokes that grant at the platform too — unless another connection still uses the same login or store, since one revoke ends the grant everywhere it is used. Revocation is best effort: if a platform is unreachable we still delete, so removing our app in that platform’s own settings is the sure way to end a grant on their side.
Meta’s data deletion request is wired to Meta’s official callback: removing our app from your Facebook settings purges the connections, mirrored ad accounts, metric rows, recommendation snapshots, and the Pages and Instagram accounts connected for publishing under that authorization, and returns a confirmation code you can check.
Or just ask — we delete on request, and answer within 30 days: contact@keyescode.com. See the Privacy Policy for the legal version.
Who else touches your data
These are our subprocessors. The ones marked optional are off unless configured, and the platform integrations only ever see what you connected them for.
| Provider | What they do | What they see |
|---|---|---|
| Railway | Hosting, managed Postgres, Redis and object storage | Everything the product stores. This is where the database lives. |
| Anthropic, OpenAI and any model provider you connect | The models behind recommendations, the Terminal, the operator and generated creative | The prompt for a given task: your brand profile, the campaign or metrics in question, and your instructions. Not your password, not a connected platform token. |
| Stripe | Subscription billing | Your billing email and subscription state. Card details go to Stripe directly and never reach us. |
| Resend | Transactional email | Recipient address and message body — verification links, invitations, alerts and client reports. |
| Sentry | Error monitoring (optional; off without a DSN) | Stack traces and request context, passed through the same redaction as our logs. |
| Cloudflare | Turnstile bot challenge on signup (optional) | A challenge token and the IP that solved it. |
| Rewardful | The affiliate program (optional) | A referral identifier and the Stripe customer it maps to. |
| Local Falcon | AI search visibility and local rank scans | The business name, location and keywords you ask it to scan for. |
| Meta, Google, TikTok, Shopify | The platforms you choose to connect | Whatever the connection is for — reading your campaigns, publishing a post, listing your products. You pick which, and you can disconnect any of them. |
What we do not have yet
We are a small team and we would rather you learn this here than in a questionnaire.
- No SOC 2 attestation. Not Type I, not Type II, not “in progress” with an auditor engaged. We maintain a written readiness assessment that maps the Trust Services Criteria to what actually exists and names every gap — ask and we will send it.
- No third-party penetration test and no bug bounty.
- No SSO, SAML or SCIM. Sign-in is email and password, or Google, with optional (or organization-required) two-factor authentication on top. No hardware security keys or passkeys yet. If SSO is a requirement for you, say so — it moves up the list.
- No customer-managed encryption keys and no single-tenant or regional hosting option. Everything runs in one Railway environment in the United States.
- No HIPAA BAA, and the product is not built for protected health information or payment card data. Do not put either in it.
- No formal advance notice of subprocessor changes. This page is the list; it changes when the software does.
Reporting something
Found a vulnerability, or need answers for a security review? Email contact@keyescode.com with “security” in the subject. We will acknowledge within two business days. Please give us a reasonable window to fix something before disclosing it, and we will not pursue anyone acting in good faith.