Legal
Data handling
What we store, where it lives, who else touches it, how long we keep it, and how to get it back or get rid of it — in plain English, with the limitations left in.
- EFFECTIVE
- July 28, 2026
- APPLIES TO
- PostSignoff
- PROVIDED BY
- [LEGAL ENTITY NAME], LLC
1. What this page is
This is the page to hand a compliance officer, a carrier's vendor-review questionnaire, or your own counsel. It describes how PostSignoff handles data today, in the words we would use out loud.
It is not the legal instrument. Our Privacy Policy is the binding statement of how we collect and use personal information, and the Terms of Service is the contract between us. Where this page and the Privacy Policy differ, the Privacy Policy governs. Read this one for detail, those two for obligation.
Everything below describes current practice as of July 28, 2026. The product changes, so this page changes with it — including the subprocessor list in section 5. We would rather revise a paragraph than leave a stale promise standing.
2. The short version
- Everything runs in the United States, on Google Cloud, in a single region.
- No analytics, no tracking scripts, no advertising pixels, no third-party fonts or CDNs — not on this website and not in the application.
- We do not sell or share personal information, and we do not train AI models on your content.
- Drafts are sent to OpenAI for generation and compliance review. No end-user names or email addresses go with them.
- Customers are separated by PostgreSQL row-level security, forced by the database itself rather than checked by application code.
- Connected-platform tokens are encrypted at rest with AES-256-GCM. Multi-factor authentication is not offered today.
- Deleting a post retires it rather than erasing it. Purging media deletes the file and leaves a tombstone record so the lineage survives.
- There is no one-click export and no self-service account deletion. Both are manual requests, answered within 30 days.
3. What we store
Your account. Email address, name, an optional avatar URL, account status, and a password hash. Sessions live server-side in our database and record the IP address and user agent they were created from. If you sign in with Google, Facebook, or X, the tokens that provider issues are stored alongside your account. Verification and password-reset tokens are stored with an expiry.
Your content and media. Post drafts and edited text, sign-offs, topics, notes, published text, platform post IDs and URLs, approval identity and timestamps, and errors from failed publishes. Media records hold the storage key, URL, thumbnails, MIME type, size, dimensions, alt text, edit state, source, and lifecycle status. Compliance reviews are stored as immutable rows — one per distinct version of the content — carrying the findings, the acknowledgment identity and timestamp, and a fingerprint of the exact text reviewed.
Your brand and connected accounts. Brand name and description, voice and tone configuration, logo and website URLs, branding and compliance settings, and a public token for your capture form. For each connected social account: the account name, the platform's account ID, and the OAuth tokens, encrypted.
The people you capture. Two things, both third-party personal information that you are the controller of. Capture-form contacts hold name, email, phone, consent timestamp, a snapshot of the consent text shown, IP address, user agent, and submission counts. Medicare Permission-to-Contact records hold more: name and postal address, phone and phone type, email, agent name and NPN, contact reasons and methods, the TCPA consent flag with a verbatim clause snapshot and hash, per-recipient data-sharing consents, the disclosures rendered, a typed signature and attestation, signed and expiry dates, IP address, user agent, input method, locale, channel, and time on form. Date of birth, Social Security number, Medicare number, and health status are deliberately excluded — there is no field for them. That form ships disabled behind a non-dismissible banner saying it has not been reviewed by counsel or approved by your carriers.
Billing identifiers. Stripe customer, subscription, and subscription-item IDs, plus the raw Stripe event payloads we receive, which can contain a billing name, email, or address. Card numbers never reach our servers — payment happens entirely on Stripe-hosted pages.
Operational logs. Method, path, status, duration, and external-call records (integration, operation, sanitized host and path, outcome). Access logs record no IP address, no user agent, and no request body. An administrative audit log separately records every mutating admin request with the actor, email, path, IP address, status code, and a redacted body. Logs redact email, name, and phone in request bodies; they do not redact post content, which is why we hold log access tightly rather than calling logs anonymous.
4. Where it lives
In the United States. The application runs on Google Cloud Platform in region us-central1: a container on Cloud Run, images in Artifact Registry, and a PostgreSQL 16 database. Media objects live in a private Google Cloud Storage bucket in the same region with public-access prevention enabled — there is no public object URL to guess or leak, and reads go through the application or a short-lived signed URL.
This marketing website is a separate static site, also served from Cloud Run in the same region. Its web server has access logging turned off.
Honest limit: the production database is pinned to the same region as everything else, but we do not yet offer a contractual data-residency commitment. Everything we can determine from our own infrastructure is US-only and we have no plan to change that. If you need residency as a contract term rather than a description of practice, ask, and we will put it in writing.
5. Who else touches it
The vendors that can see customer data, what each does, and what actually reaches it. Some are always in the path; others apply only if you connect an integration or we enable a configuration for you. The last column says which.
| Provider | What it does | What reaches it | When it applies |
|---|---|---|---|
| OpenAI | Text generation, image generation, AI compliance review, image-prompt suggestions | Post drafts and edited text, brand name and voice configuration, topic and context text, sign-off and branding settings, target platform names, image prompts and brand colours, and for review: the rule pack, your custom rules, and the full post content. No end-user names or email addresses. | Always, for any AI feature |
| Google Cloud Platform (Google LLC) | Hosting and infrastructure: compute, the PostgreSQL database, media object storage, container registry, Secret Manager, and signing | Everything the service stores, because this is the infrastructure it runs on. Secret Manager and the signing APIs receive no customer data — only secret resource names and short-lived credentials. | Always |
| Stripe | Subscriptions, checkout, customer billing portal, add-on billing | Your email address, your tenant ID in customer metadata, plan and price IDs, quantities, return URLs. Card details go directly from your browser to Stripe. | Always — the service does not run without billing configured |
| Resend | Transactional email: verification, password reset, welcome, contact-form notifications, plan-expiry notices | Recipient email address and name, subject line, and the full rendered message body — which for a contact-form notification includes the submitter's name, email, company, and message. | When an email provider is configured. Without one, mail falls back to a console provider and nothing leaves. |
| Social platforms: X (Twitter), LinkedIn, Facebook, Instagram, Reddit, TikTok | Publishing, account connection, and account or profile lookup | Post text (body, hashtags, sign-off), image or video bytes or URLs, the destination account, page, or subreddit ID, and the OAuth token for that account. LinkedIn also receives a profile lookup to resolve your member identifier. | Only for the platforms you personally connect |
| Zernio | Alternative posting provider that brokers publishing and account connection | Post content, media as time-limited signed URLs it fetches from our bucket (not raw bytes), platform and account IDs, schedule time and timezone, a per-brand profile, connection redirect URLs, and analytics sync. In this mode Zernio holds your social tokens instead of us. | Only when the service is configured for this provider. It is mutually exclusive with direct publishing, which is the default. |
| Pexels | Stock photo and video search and download | Your free-text search query, paging and colour filters, and the IDs of assets you select. | Only when stock search is configured |
| Cloudflare Turnstile | Bot protection on the public capture form and the Permission-to-Contact form | From our server: the challenge token and the visitor's IP address. From the visitor's browser: loading the widget exposes their IP address, user agent, and Cloudflare cookies. It is the only third-party script embedded in any page we serve. | Only when configured, and only on those two public forms |
| Sentry (Functional Software, Inc.) | Error tracking and optional performance tracing, server and browser | Exception messages and stack traces, breadcrumbs for instrumented external calls (integration, operation, sanitized host and path, model, tenant ID, post ID, email subject line), and a user context consisting of a user ID and tenant ID. From the browser: error-boundary reports and the page URL. | Only when an error-tracking key is configured |
| WhatsApp approval relay | Sends pending-approval digests and receives your approve or reject replies | The content of up to ten pending posts — text, platform, and topic — plus the destination phone number. | Off unless we enable the relay for you; otherwise skipped entirely |
One more egress worth naming: pulling in a stock photo or an AI-generated image makes our server fetch that URL, and the URL is the only thing sent. We will post changes to this list here — added or removed, a vendor shows up in this table.
6. What we deliberately do not do
- No advertising. We run no ad network, no pixels, no retargeting.
- No selling or sharing of personal information. Not for money, not for cross-context behavioural advertising, not for anything else.
- No analytics or tracking scripts. No Google Analytics, Tag Manager, Segment, Mixpanel, PostHog, Plausible, Hotjar, or equivalent, anywhere on this site or in the application. This website sets no cookies at all; the only thing it stores in your browser is your light or dark theme preference.
- No third-party fonts or CDNs. Fonts are self-hosted and every asset comes from our own origin, so loading a page here does not hand your IP address to a third party.
- No training of AI models on your content. We do not train, fine-tune, or build models on customer content, and we license it to no one who does.
- No reading of your content except to operate and support the service. We access customer content when it is necessary to run the platform, investigate an error, or answer a support request you raised. Not to browse.
- No protected health information. We are not a HIPAA business associate and the product has no field designed to hold clinical data. See section 13.
7. Your content and AI
Drafting and compliance review both call OpenAI's API. The request carries what the model needs: the post content and any edits, your brand name and voice configuration, the topic or context you supplied, your sign-off and branding settings, the target platform names, and — for a review — the rule pack plus any custom rules you added.
What does not go: no end-user names, no email addresses, no user identifiers. Your captured contacts and consent records are not part of any AI request. As the compliance page already says: drafts are processed through OpenAI's API for generation and review, and under OpenAI's API policy, API content is not used to train their models by default.
Model output can be wrong, and you have to read it. The review is built to fail toward caution: required disclaimers are checked by deterministic string matching that runs even when the AI leg fails entirely, every AI finding must quote your post verbatim or it is discarded server-side, citations come from the rule pack rather than the model, and a finding blocks approval until you fix the text or acknowledge the finding. None of that makes the output correct. It assists supervision; it does not certify or guarantee regulatory compliance.
8. How long we keep things
| What | How long | What happens then |
|---|---|---|
| Media in trash | 30 days | A background job deletes the file itself. The database row remains as a tombstone marked deleted, keeping the storage key, URL, alt text, and dimensions so the lineage of a published post survives. |
| Archived media | Until you act on it | Never automatically purged. |
| Temporary uploads | 24 hours | Fully deleted — file and row both. Swept hourly. |
| Posts | Kept | Never hard-deleted. Deleting a post is a status change, not an erasure. A pending post that misses its scheduled time moves to an expired status rather than being removed. |
| Sessions | 30 days | The session expires and stops working. We do not currently sweep expired session rows out of the database. |
| Permission-to-Contact consent records | Long-term, by design | Append-only. Consent validity is 12 months from the signature date; the record itself is deliberately retained past that so you can evidence what a beneficiary agreed to, when, and against which version of the form. Corrections create a new record rather than editing an old one. |
| Captured lead contacts | Until deleted | Deletable on request, and the deletion removes the row outright. |
| Logs, audit records, contact-form submissions, billing webhook events | No fixed period is defined yet | We keep these as long as needed for the purposes described on this page, and we have not yet set a published retention schedule or built an automatic purge for them. That is a gap, we know it is a gap, and it is under review. We would rather say so than publish a number we do not enforce. |
9. Getting your data out
Three exports exist today. That is the honest list:
- Captured contacts — CSV export of your capture-form contacts.
- Permission-to-Contact consent records — CSV. Never gated by plan tier; it stays available even if the feature limit is zero.
- Posts and their compliance history — through the API: post content, approval identity and timestamps, published text with platform post IDs and URLs, and the compliance-review chain for each version of the content, with findings and who acknowledged what and when.
There is no one-click "download everything" archive yet, and no automated data-subject-request endpoint. If you want a complete copy of your data, ask us using the route in section 15; we will assemble it by hand and come back to you within 30 days.
10. Deleting your data
Deletion is not uniform here, so here is exactly how each kind behaves.
- Lead contacts can be deleted outright. The row is removed — a deliberate exception, because captured contacts are somebody else's personal information and have to be removable.
- Media can be trashed and purged. Trash it and it goes after 30 days, or empty the trash and it goes now. Either way the file is deleted and a tombstone row remains.
- Posts are retired, not erased. Deleting a post sets its status. The record stays, because the compliance history attached to it is what makes it a record.
- Account and full-tenant deletion is a manual request, handled by us. There is no self-service delete button. The built-in path disables the account, records the deletion time, and ends every session — it does not by itself remove your rows or content. Anything beyond that we do by hand and confirm in writing.
- Permission-to-Contact consent records are deliberately retained as compliance evidence unless you instruct us otherwise. They are append-only and are not wired into the contact-deletion path. Revocation and correction run through your own process today: a correction produces a new record rather than editing one in place.
Send deletion requests through the route in section 15. We will acknowledge and act on them within 30 days, and tell you plainly if part of a request is something we are keeping, and why.
The 30 days above — and the same commitment on exports in section 9 — is our operational commitment to you as our customer. A statutory privacy-rights request, whether yours or one from a consumer whose information you collected, runs on the deadlines set out in the Privacy Policy instead.
11. Keeping tenants apart
Separation between customers is enforced by PostgreSQL row-level security, both enabled and forced. Each request runs inside a transaction that sets the current tenant, and the policy on every protected table compares that value against the row's own tenant before the row is visible. The database role the application runs as cannot bypass row-level security; a separate migration role that can exists only to apply schema changes. A missing filter in application code therefore cannot leak another customer's row — the database refuses first.
That boundary covers brands, campaigns, posts, groups, media, templates, platform accounts, engagement and analytics data, compliance reviews, subscriptions and usage, capture forms and contacts, and every Permission-to-Contact table.
Some tables sit outside it, and here is why. Identity tables — users, sessions, login accounts, verification tokens, and the tenant list itself — must be readable before a tenant is known, or nobody could sign in. The administrative audit log is global on purpose: a record a tenant could scope away is not an audit record. Billing webhook events, the plan catalog, and application settings are platform-level. Contact-form submissions from this website are global too — they come from members of the public who have no tenant.
12. Security controls
- Connected-platform tokens are encrypted at rest with AES-256-GCM, using a key derived with scrypt and a fresh random initialisation vector per value. In production the server refuses to start without the key rather than storing tokens in the clear. One caveat: tokens issued by the providers you sign in with (Google, Facebook, X) are held by our authentication library and are not covered by that application-level encryption.
- Passwords are hashed with scrypt. Email verification is required at sign-up.
- TLS in transit, terminated by the platform with managed certificates.
- Private storage buckets with public-access prevention, and 15-minute signed URLs minted only when media has to be handed to a posting provider.
- A content security policy and hardened security headers, plus a CORS allowlist rather than an open origin policy.
- Per-route rate limiting: authentication routes at 10 per 15 minutes per IP, generation at 30 per hour, public form submissions at 20 per 15 minutes, contact at 5 per hour, webhooks at 100 per minute. The limiter counts in memory, so it is exact at a single instance.
- Webhook signature verification against raw request bodies for every inbound webhook we accept.
- Secrets in Google Secret Manager, media signing done keylessly through service-account impersonation, and CI authenticated by workload identity federation, so no cloud service-account key is stored in CI.
- Bot protection on the public forms that fails closed — if the verifier cannot be reached, the submission is refused, not waved through.
Multi-factor authentication is not offered today. Your account is protected by a password, or by whichever social login provider you chose, and nothing more. If MFA is a hard requirement for you, it is not something we can meet right now.
13. What we ask of you
- Do not upload protected health information, Medicare numbers, or Social Security numbers. There is no field designed to hold them. Our consent form deliberately omits date of birth, Social Security number, Medicare number, and health status — please do not defeat that by typing them into a free-text box.
- Keep your credentials secure. There is no MFA, sessions last 30 days, and an account today is a single user with no seats or roles — so sharing a login is sharing the account, and everything done with it is recorded as you.
- Use your own carrier-approved, counsel-reviewed consent forms. The Permission-to-Contact feature stays disabled until you complete your own carrier approval and legal review. Nothing in the software substitutes for either, and nothing in it prevents you from activating a form you have not cleared.
- Read every draft before you approve it. You are the licensed professional. Approval is a human act performed by you, and the record says so.
14. Incidents
If we identify a security incident affecting your data, we will investigate and contain it, and notify affected customers without undue delay — with what we know, what we do not yet know, what we are doing, and what we recommend. We will support your own notification obligations to carriers, regulators, and affected individuals, including giving you the records you need to make those notifications.
We are not going to publish an hour count we cannot yet prove we can meet. If your carrier or your own compliance program requires a fixed notification window, tell us and we will negotiate it as a contract term. If you believe you have found a vulnerability, report it using the route below and give us a reasonable chance to fix it before disclosing it publicly.
15. Questions and requests
Data questions, export requests, deletion requests, security reports, and vendor-review questionnaires all go to the same place: the contact form. Written notices can be sent to [LEGAL ENTITY NAME], LLC at [STREET ADDRESS], [CITY], North Carolina [ZIP].
For the binding versions of what is summarised here, read the Privacy Policy and the Terms of Service. For how the compliance review itself works, read the compliance page.