Privacy policy

Last updated 25 July 2026
In plain language
We store two kinds of data. There is the small amount we need to run your account, which is your name, your work email, an optional phone number and a hashed password. Then there is everything you put into the product: your compliance records and the documents you upload, including documents about your employees and your vendors. That second kind is yours, we hold it to run the service for you, and three companies help us do it: Cloudflare hosts the app and stores the files, Stripe takes payments, and Resend delivers reminder emails. We do not sell any of it, we do not advertise, and there is no analytics or tracking code in the product.
Needs a lawyer's review. This policy is a draft written from the code, not a vetted legal document. It is accurate about what the software does. It has not been reviewed by a lawyer, and the blanks marked in red have to be filled in before it is published.

1. Who we are

RenewalOps is operated by TODO: legal entity name, at TODO: registered contact address. In this policy "we" means that company and "you" means the organization that holds a RenewalOps account, along with the people in it who sign in.

2. Two kinds of data, two different roles

The distinction runs through the rest of this policy, so it comes first.

  • Your account data. The names, work emails and passwords of the people in your organization, plus your organization's own details and its billing state. We decide what to collect here, because it is what signing in and getting billed requires.
  • Your compliance data. The records you track, the documents you upload, and the people and companies those documents are about. You decide what goes in. We hold it and process it on your instruction, which makes you the controller of it and us your processor. If one of your employees or vendors asks us about their own data, we will point them at you, and tell you they asked.

3. What we store

This list is the database schema in plain English, walked table by table. If a field is not named here, the product does not have a column for it. There are sixteen tables, and two things are said once here rather than sixteen times. Both have an exception, and the exception is the interesting part in each case.

  • Fifteen of the sixteen tables give every row a number the database picks. The sixteenth is the session table, which is keyed on the random token in the cookie described further down, and the app generates that token rather than the database. Some rows also carry a second, human-readable identifier the app builds: a record's reference like RN-0042 is one, and it is the label you see in the interface.
  • Thirteen of the sixteen carry the organization column described in section 7. The three that do not are the organization table itself, the session table, and the cron-run table at the end of this section. Section 7 names the same three and says what stands in for the column in each case.

People and organizations

  • For each person who can sign in: name, email address, an optional phone number, their role, an optional job title, a hashed password, whether the account is active, when the account was created, and the time they last signed in.
  • For your organization: its name, a short lowercase handle made from that name when you sign up, the industry you picked at setup, your time zone, your plan, your billing state, your workspace settings, and when the row was created and last changed. The handle is unique across our database, it is what an admin edits in the field labelled Slug under Settings, and it is not part of any address in the app.
  • Teammate accounts are created by an admin inside the app. The app generates a password and shows it once to the admin who created the account, so they can pass it on. We do not email an invitation, and that generated password is never written to the audit trail.

Your compliance records

  • Each record: its name and category, a description, the issue, effective and expiration dates, its status and priority, which of the people, vendors, assets or locations below it is attached to and which of your locations it sits at, who owns it and an optional second owner, whether it needs a document attached, a record number, the issuing authority, your notes, tags, any custom fields you add, the reference the app assigns it (RN-0001 upwards, numbered inside your organization), when a reminder for it last went out, when it was created and last changed, and whether it has been archived.
  • The people, vendors, assets and locations you attach records to. For each of those: what kind of thing it is, its name, an identifier of your own if you give it one, which location it belongs to, whether it is active, when it was added, and a details field holding whatever else you put in, which in practice can be a licence number, a certification, or an internal identifier. For a location: its name, what kind of site it is, the address you enter, its time zone, who manages it, held both as a link to that person's account and as a shortened form of their name for the list, whether it is active, and whether it is your head office.
  • Notes people write on a record, stored with the name and the account of who wrote them and when.

Documents you upload

  • The file itself, stored in a private Cloudflare R2 bucket under a key we keep alongside the row. Nothing in the bucket is publicly readable. Downloads go through the app, which checks that you are signed in and that the document belongs to your organization.
  • Alongside the file: its name, its type, its size, a SHA-256 hash of its contents, its version number, which record it belongs to, who uploaded it, when, whether it has been approved, and whether it has been archived. The uploader is stored as a name, plus a link to their account when it was one of your own people. A file that arrives through a vendor upload link has no account to link to, so it is stored as the vendor's name followed by the words vendor link.
  • Uploads inside the app accept PDF, JPG, PNG, CSV, XLSX and DOCX files up to 25 MB each, 25 files at a time. The vendor upload link accepts PDF, JPG and PNG only.
  • When a file lands, the app tries to pre-fill a record from the file name. It does not read the contents of the document, and no third party is sent the file to read it either.
  • That pre-fill result is stored with the document rather than used and thrown away, so it is data we hold: a list of labelled values, a confidence score on each, and a flag for whether someone has since corrected it. Because the guess comes from the file name, a file called cert-jimenez.pdf is stored with the value Jimenez under the label Person. If your file names contain people's names, those names are held as extracted fields as well as inside the file name.

Reminders

  • For each reminder: which record it belongs to, how many days before expiry it was due, when it was scheduled, when it went out, which channel and which address it went to, whether delivery succeeded, the error the email provider gave back when it did not, and which rung of the escalation ladder it was.
  • A reminder email names the person and the record, because a reminder that hides which certificate expired is useless to the person who has to renew it. If that matters for your data, it is worth knowing before you turn reminders on.

In-app notifications

  • The bell in the app writes a row per notice: which of your people it is for, how urgent it is, the sentence shown, the link it points at, whether it has been read, and when it arrived. Marking one read sets a flag. Nothing in the app deletes these rows, so they stay for as long as the account does.
  • The sentence itself can name a third party, because naming them is what makes it useful. A vendor submitting through an upload link produces text like Acme Plumbing submitted a Certificate of Insurance via secure upload link, and that sentence is stored, not just displayed.

Automation rules and what they did

  • For each rule you build: its name, the trigger, condition, action and escalation you chose, the recipients you named, the rule's settings, whether it is on, who created it, when, and when it last ran.
  • Every time a rule fires we keep a row saying which rule it was, which record it was about, a key naming the thing it has already done, the outcome, a short detail line, and the time. That ledger is what stops an hourly job from sending the same notice 24 times, so it is not something the product can do without.

Vendor upload links

  • For each link you send a vendor: which vendor and which record it is for, the kind of document you asked for, the random token that forms the URL, its status, who requested it, when it was created, when it expires, and when it was submitted. The token is the only credential involved, which is why it is single-use and expires. There is no vendor account and no vendor password.

Saved views

  • A saved filter on the records list keeps its name, whose it is, its position in the list, whether it is one of the views the app ships with, and the filter values themselves. Those values include anything you typed into the search box when you saved it, so a search for a person's name is stored with the view.

Audit trail

  • For each logged action: who did it, stored as a label and, when a signed-in person did it, a link to their account as well, what they did, which record or entity it touched, a description, the values before and after where the action changed something, the IP address the request arrived from, the browser's user-agent string truncated to 400 characters, and the time.
  • The IP address is read from the X-Forwarded-For header, so behind a proxy it is the first hop, which is normally your user.
  • Not every entry has a person behind it, and those say so rather than borrowing a name. An entry the scheduled jobs wrote is labelled System, one written from a Stripe payment event is labelled Stripe, and one written when a vendor uses an upload link is labelled Vendor link. None of the three links to one of your accounts, and the first two carry no IP address and no user-agent. System means no person is recorded against the entry, not that no person was involved: the hourly jobs write those entries, and so does the reminder work when somebody starts it by hand from the Automations screen. The Vendor link entries do carry an IP address and a user-agent, and they are the vendor's, which is worth knowing before you send an upload link.

Billing

  • Card details never reach our servers. Payment happens on a checkout page hosted by Stripe, and Stripe collects and holds the card.
  • What we store is what Stripe tells us afterwards: your Stripe customer and subscription identifiers, the price you are on, the subscription status in Stripe's own words, and the date your paid period ends.

Sessions and cookies

  • Signing in sets one cookie, ro_session. It holds a random token, nothing about you. It is marked HttpOnly and SameSite=Lax, it is served over HTTPS only in production, and it lasts 14 days. The row behind it holds that token, which account it belongs to, and when it was created and expires. Signing out deletes both the cookie and the row.
  • That is the only cookie the product sets. There is no analytics cookie, no advertising pixel, no session recording, and no third-party script in the pages. Fonts are served from our own domain.

The background jobs, and the one table that holds nothing of yours

Two scheduled jobs run every hour. One recalculates statuses, sends the reminders that are due, and finishes any send that was left queued. The other, twenty minutes later, runs your automation rules. Each invocation writes one row, and that row holds: which of the two schedules it was, when it started, when it finished, whether it succeeded, the error message if it threw, and eight counters that are totals across every customer rather than any one of them, being statuses changed, reminders sent, deliveries that succeeded, deliveries that failed, escalations, the reminders left over when a run hit its per-run cap, queued sends finished off, and automation rules fired. It has no organization column and nothing in it is about you or your people. It is described here because this section claims to name every table and every column, and because an operator needs to be able to prove the jobs ran.

4. What we use it for

  • Running the product: showing your records, storing your documents, letting you sign in.
  • Sending the reminders and escalations you configure, to the people you name as recipients.
  • Keeping the audit trail, because the reason to keep a compliance system is being able to show later who did what and when.
  • Billing you for the plan you chose, through Stripe.
  • Answering your support requests and fixing faults. That can mean a person on our side looking at your data to reproduce a problem you report.

We do not sell your data. We do not share it with advertisers. We do not use your documents or records to train a model.

5. Where it is stored

The app runs on Cloudflare Workers. Records go in Cloudflare D1, which is a SQL database, and uploaded files go in Cloudflare R2, which is object storage. Both are private to the app and reached through bindings rather than over the public internet.

The production database was created in Cloudflare's Western North America region. R2 storage is not pinned to a region by our configuration. Neither of those is a residency guarantee, and we are not offering one: Cloudflare can move or replicate data within its own network, and we have no contractual term with you that restricts where it sits. If your procurement process needs a residency commitment, ask us before you buy, because the honest answer today is that we cannot give one.

6. Who else touches it

Three companies process data on our behalf. Each one, what it does, and exactly which data reaches it, is on the subprocessor page. That page is the list, and it is kept current with the code rather than written once.

Beyond those three, we share data only when you ask us to, or when we are legally required to. If a subpoena or equivalent order asks for your data, we will tell you before we hand anything over unless the order forbids it.

7. Security, and what we do not have

The useful half of a security section is the second half, so both halves are here.

What the software actually does

  • Passwords are hashed with scrypt, using a fresh 16-byte random salt per password and a 64-byte derived key. The plaintext is never stored and never logged. Comparison is constant-time.
  • The sign-in path does the same scrypt work whether or not the email exists, so response time does not reveal who has an account.
  • Thirteen of the sixteen tables this product creates carry an organization column. The three that do not are the three named in section 3, in the same order, and each has a different reason. The organization table is the organization, so its own row identifier is what the other thirteen point at. The session table is keyed on the account that signed in, which reaches your organization through that account, so it holds something about one of your people without naming your organization. The cron-run table described at the end of section 3 is the only one of the sixteen that holds nothing about you or your people at all, which is why it is the only one of the three that needs no substitute for the column.
  • How that column gets applied is worth being exact about, because it is not the same in every statement. A list is fetched with your organization named in the query. A single record's page is not: it fetches the record by id and organization together, stops if nothing comes back, and then loads that record's documents, reminders, notes and history keyed on the record id it has just confirmed is yours. Writes have the same shape. A statement that edits one row is keyed on that row's own id, and what makes the row yours is the lookup immediately in front of it. Bulk actions load the selected rows for your organization first, then write only to the ids that lookup returned. So the boundary is an ownership check before the access rather than an organization named in every statement, and that check is the property the test suite spends most of its effort on.
  • Uploaded files go to a private bucket under a storage key the server derives. A client never chooses where its bytes land, so one customer's upload cannot overwrite another's.
  • Document downloads require a live session belonging to the organization that owns the document.
  • A vendor upload link is a single-use random token that expires after 30 days. It gives access to one upload and no view of your workspace.
  • The Stripe webhook verifies Stripe's signature over the raw request body, with a five minute timestamp window, and rejects anything unsigned. Without that, anyone who found the URL could mark any organization as paid.
  • Cloudflare encrypts data in transit and at rest on the platform. That is Cloudflare's doing, not a control we implemented, and we describe it that way on purpose.

What we do not have

  • No SOC 2 report, no ISO 27001 certificate, and no third-party penetration test. If a questionnaire asks, the answer is no rather than "in progress".
  • No single sign-on, no SAML, and no two-factor authentication. Sign-in is a password and a session cookie.
  • No malware or virus scanning of uploaded files. We check the extension and the file size, and we store the canonical type for the extension rather than trusting what the browser claimed. We do not inspect contents.
  • The audit trail is append-only by convention, not by mechanism. The app only ever inserts rows into it and never edits or deletes them. It is an ordinary database table underneath, so it is not a tamper-proof ledger and we will not describe it as immutable.
  • We are not set up to handle protected health information under HIPAA, and we will not sign a business associate agreement.
  • Nobody can promise a system is never breached. If yours is affected, we will tell you what we know, when we know it.

8. How long we keep it

Plainly: until you ask us to delete it. Nothing you put into the product is deleted on a schedule, and this section describes what the code does rather than a policy we intend to write later. The one thing the scheduled jobs delete is their own history: the run rows from section 3 are trimmed to the last 30 days, and those rows are about the jobs, not about you.

  • Archiving a record or a document sets a flag. The row stays in the database and the file stays in storage, which is deliberate, because the reason to archive a lapsed certificate is to be able to produce it during an audit.
  • Nothing in the app ever deletes an uploaded file from storage. Replacing a document adds a new version and keeps the old one.
  • Audit events are never deleted or trimmed. There is no retention window on them at all.
  • Sessions are the exception. Signing out deletes the session, and an expired session is deleted the next time it is presented. An admin resetting someone's password or deactivating their account also deletes that person's sessions, which is what signs them out everywhere.
  • If you close your account and ask us to delete your data, we will delete your records, your documents and your uploaded files. Tell us in writing at TODO: privacy contact email and we will confirm when it is done. Data held by Stripe for payment records is subject to their own retention, which we do not control.

9. Seeing, correcting and getting your data out

If you are signed in, most of this is self-service. You can read and correct any record, entity or person in the app. Reports export as CSV, and the audit trail exports as CSV. Documents download individually.

For anything the app does not do, including a full copy of your data or deletion, write to TODO: privacy contact email. If you are an employee or vendor whose documents are in someone else's RenewalOps account, we cannot act on your request directly. Ask the organization that holds the account. Contact us and we will tell you who to ask, and tell them you asked.

Needs a lawyer's review. Data subject rights differ by jurisdiction, and the response deadlines that come with them are legal obligations rather than a service level we get to choose. This section says what we can do today. It does not attempt to enumerate rights under any particular law, and it needs review against the ones that apply to your customers.

10. Data processing addendum

This section covers the processor relationship for the compliance data you put into RenewalOps. It is here so a buyer with a procurement process has something concrete to read, and it is written to match what the software actually does.

  • Roles. You are the controller of your compliance data. We are your processor. Where the data concerns your employees, your contractors or your vendors' staff, you are the one with the relationship to them and the lawful basis for holding it.
  • Subject matter and duration. We process your data to provide RenewalOps, for as long as your account is open, and afterwards only until you ask us to delete it.
  • Nature of the processing. Storage, retrieval, display, indexing for search, status calculation from dates you enter, sending the reminder emails you configure, and recording an audit trail of changes.
  • Categories of data. Names, work contact details, job titles, and the contents of the compliance documents you upload. Those documents commonly contain licence and certification numbers, insurance policy details, and expiry dates tied to a named individual.
  • Categories of data subjects. Your staff who use the app, your employees and contractors whose credentials you track, and contacts at your vendors.
  • Our obligations. We process only to provide the service and on your instructions. We keep your data confidential and limit access on our side to people who need it to operate or support the product. We help you respond to a data subject request as far as the software allows. We tell you about a personal data breach affecting your data without undue delay. We delete your data when you ask.
  • Subprocessors. The current list is the subprocessor page. We will publish a change there before a new subprocessor starts handling your data.
  • Audit and information. We can answer questions about how the system works and point you at the platform certifications our subprocessors publish. We have no audit report of our own to give you, and we will not imply otherwise.
Needs a lawyer's review. This is a summary of the processor relationship, not an executed data processing agreement. It has no transfer mechanism in it, which matters for customers outside the United States: standard contractual clauses, a transfer impact assessment and the liability and indemnity terms all still need drafting. A buyer who requires a signed DPA should be given a real one. Do not represent this section as one.

11. Changes to this policy

When this policy changes, the date at the top changes with it. If a change alters what we collect or who we share it with, we will email the account owner rather than leave it for you to notice.

12. Contact

Privacy questions go to TODO: privacy contact email. Post reaches us at TODO: registered contact address. Our terms of service cover the commercial side of the same relationship.

Back to renewalops.com
TermsPrivacySubprocessors