Privacy policy
What we collect, why, how long we keep it, and how to see or delete it. This page is built from the list of fields our database really stores.
The short version
- We collect your email address, what you will use the API for, and where you will use it. After the confirmation email is sent, we keep only a one-way hash of the email address, not the address.
- We keep hashes of the IP addresses your requests come from, for 30 days, and request counts, to enforce limits and spot misuse.
- We never store VINs, request bodies, your key in readable form, or your IP address in readable form.
- We do not sell or share your information. We use Cloudflare to run the service.
- You can delete your key and its data yourself at Manage my key, or write to support@recalldb.app.
What we collect, and when
At signup. Your email address (used once, to send the confirmation link, then replaced by a hash), your answer to "What will you use it for?", your answer to "Where will you use it?" (a website, an app, or a short description), an optional one-line note, and a hash of your IP address. We also store a number showing whether the answers looked like placeholders.
When you use the API. Which key made a request, how many requests per month and per day, when the key was last used, hashes of the IP address and network that the request came from, a hash of each record asked for, the last record number asked for, and counters used to notice record numbers requested in order or at machine speed. If a fair-use rule triggers, we store which rule and a short description with counts.
When you use "Manage my key". The email address you type is used to find your key (by its hash) and to send an email, then it is discarded. We always send an email, so the page and your inbox behave the same for every address: the manage link if the address has a key, or a short note saying no key is linked. We store hashes and the time of the request.
When you join the Pro or Business waitlist. The plan, your email address (kept in plain text, because its only use is to write to you once when the plan opens), the optional line about what you are building, a hash of your IP address (to limit sign-ups per network), and the time. It is deleted when you ask, and 90 days after the plan opens.
Search words. We count anonymous search terms (no IP addresses or identifiers) to improve results. VINs, barcodes, recall numbers and lot codes are never recorded. For a search on this site or in the API we count only the words searched, whether the search found nothing, and whether a spelling was corrected. API searches are counted the same way and are not tied to your key. A search that looks like a VIN, barcode, recall number, lot or model code, email address or phone number is not counted at all, and neither is a query longer than 60 characters. The counts are kept by Cloudflare for about three months. Popular searches, and the spelling fixes of short plain-letter searches, are also kept ready for 15 minutes so repeats are faster; nothing about you or your key is kept with them. Cloudflare time-stamps each count; we only read the counts per day, and a word appears in reports only after at least 5 searches.
What we do not collect. No names. No VINs (POST /v1/vin, POST /v1/vins/batch, the docs playground and the fleet check at /fleet-check use VINs in memory only, send them only to NHTSA's VIN decoder, and never store or log them; the fleet check's report and CSV are built in the page we send you and kept nowhere). No plain-text email addresses (except on the waitlist, as above), IP addresses or API keys in our database or logs. No advertising or tracking.
Every stored field
This is the complete list. A hash is a one-way scramble: we can check whether something matches, but we cannot turn it back into the original.
A signup or sign-in request signups
To send and check the one-time link, limit signups per network, and review what the API is used for. Kept: 30 days, then deleted.
| Field | What it holds |
|---|---|
id | Random id |
email_hash | One-way hash of your email address (never the address itself) |
ip_hash | One-way hash of your IP address |
created_at | When the request was made |
token_hash | One-way hash of the link token |
expires_at | When the link stops working |
used_at | When the link was opened |
use_case | What you said you will use the API for |
where_use | Where you said you will use it (a website, app or short description) |
note | Your optional one-line note |
junk_score | A number from 0 up showing how much the answers looked like placeholders |
Your API key record api_keys
To check your key, apply limits, and enforce fair use. Kept: While your key exists. Deleted when you delete your key.
| Field | What it holds |
|---|---|
id | The public key id (the 8 characters after "rdb_") |
key_hash | One-way hash of the secret part of your key (we cannot read your key) |
email_hash | One-way hash of your email address, so one email gets one free key |
status | active, throttled, suspended or revoked |
level | How far fair-use warnings have gone (0 to 3) |
created_at | When the key was made |
status_reason | Why the status last changed |
status_at | When the status last changed |
last_used_at | When the key last made a request |
use_case | Copied from your signup |
where_use | Copied from your signup |
note | Copied from your signup |
junk_score | Copied from your signup |
Requests per key per month usage_month
To enforce the monthly limit and show /v1/usage. Kept: While your key exists.
| Field | What it holds |
|---|---|
key_id | Your key id |
month | The month |
requests | How many requests |
Requests per key per day key_day
To detect spikes. Kept: 90 days.
| Field | What it holds |
|---|---|
key_id | Your key id |
day | The day |
requests | How many requests |
The last request of each key key_state
To notice record numbers requested in order and machine-speed bursts. Kept: While your key exists.
| Field | What it holds |
|---|---|
key_id | Your key id |
last_ts | When the last request was made |
last_id | The last record number requested (never a VIN) |
seq_run | A counter of neighbouring record numbers in a row |
fast_run | A counter of requests close together |
Which records a key asked for today key_seen
To notice a key touching a very large number of different records in a day. Kept: 30 days.
| Field | What it holds |
|---|---|
key_id | Your key id |
day | The day |
resource_hash | One-way hash of the record asked for (never a VIN) |
The networks a key was used from key_net
To notice several keys used together from one place. Kept: 30 days.
| Field | What it holds |
|---|---|
key_id | Your key id |
kind | ip or asn (the network operator) |
h | One-way hash of the IP address or network number |
day | The day |
requests | How many requests that day |
Fair-use flags abuse_flags
To record why a key was warned, slowed or suspended. Kept: While your key exists.
| Field | What it holds |
|---|---|
id | Row number |
key_id | Your key id |
rule | Which rule triggered |
detail | A short description with counts, never personal data |
at | When |
Status changes of a key key_actions
To keep a log of every warning, slowdown, suspension, revocation and reinstatement. Kept: While your key exists.
| Field | What it holds |
|---|---|
id | Row number |
key_id | Your key id |
from_status | Status before |
to_status | Status after |
reason | Why |
actor | auto or admin |
at | When |
Which alerts were already sent alerts_sent
To send at most one alert per key per day. Kept: 30 days.
| Field | What it holds |
|---|---|
alert_key | A label made of the alert type, key id and day |
at | When |
A "Manage my key" request manage_tokens
To send and check the one-time link for rotating or deleting a key. Kept: 30 days, then deleted.
| Field | What it holds |
|---|---|
id | Random id |
email_hash | One-way hash of your email address |
token_hash | One-way hash of the link token |
ip_hash | One-way hash of your IP address |
created_at | When the request was made |
expires_at | When the link stops working |
used_at | When the link was used |
Results of our own status checks status_checks
To show uptime and response times on the status page. These are checks we run on ourselves, every 5 minutes, with no key and no visitor data. Kept: 90 days.
| Field | What it holds |
|---|---|
run | The time slot of the check |
name | Which check (health, recall, search, edge, db) |
ok | Passed or failed |
ms | How long it took in milliseconds |
Status page incidents status_incidents
To show when the service had a problem and what we said about it. No visitor data. Kept: Kept for the history shown on the status page.
| Field | What it holds |
|---|---|
id | Row number |
started_at | When it started |
resolved_at | When it ended |
severity | degraded or down |
title | A short public title |
notes | Public updates we wrote |
A watchlist you created watchlists
To find recalls that match it and send them to your webhook. Kept: Until you delete it or your key.
| Field | What it holds |
|---|---|
id | Random id |
key_id | Your key id |
name | The name you gave it |
webhook_id | The webhook it sends to |
created_at | When you created it |
The values on a watchlist watch_terms
The makes, models, brands, categories and barcodes you asked to watch. Kept: Until you delete the watchlist or your key.
| Field | What it holds |
|---|---|
watchlist_id | The watchlist |
kind | make, model, brand, category or upc |
value_norm | The value in the form we match on |
value_raw | The value as you sent it |
A webhook address you registered webhooks
To send you messages about matching recalls. The signing secret is not stored: it is worked out from a server secret when needed. Kept: Until you delete it or your key.
| Field | What it holds |
|---|---|
id | Random id |
key_id | Your key id |
url | The https address you gave us |
nonce | A random value used to work out the signing secret |
status | active or disabled |
consecutive_failures | How many deliveries failed in a row |
disabled_reason | Why it was switched off |
created_at | When you created it |
The delivery log of a webhook webhook_deliveries
To send each message, retry failures and show you what happened. Kept: 30 days, then deleted (pending messages are kept until sent). The message body is blanked after 7 days; until then it can be redelivered from Manage my key.
| Field | What it holds |
|---|---|
id | Random id |
webhook_id | The webhook |
event_id | The event, so a message is sent once |
event | recall.added, recall.changed or test |
payload | The message body (public recall data and which of your watchlists matched), kept 7 days |
state | pending, delivered or failed |
attempts | How many times we tried |
next_attempt_at | When we will try again |
last_status | The last response status from your server |
last_error | A short code for the last failure |
created_at | When the message was queued |
delivered_at | When it was delivered |
When each new recall reached the webhook job pipeline_timing
To measure how fast new recalls reach subscribers. About recalls only: no key, address or subscriber. Kept: 90 days, then deleted.
| Field | What it holds |
|---|---|
slug | The recall |
agency | The agency |
agency_at | The agency's publish time or date |
seen_at | When our data service first saw it |
queued_at | When the webhook job picked it up |
sent_at | The first successful delivery to any webhook |
Your place on the Pro or Business waitlist waitlist
To write to you once when the plan opens. Nothing is sold and nothing else is sent. Kept: Until you ask us to delete it, and 90 days after the plan opens.
| Field | What it holds |
|---|---|
id | Random id |
plan | pro or business |
email | Your email address (in plain text: its only use is that one email) |
email_hash | One-way hash of your email address, so you are listed once per plan |
use_note | Your optional line about what you are building |
ip_hash | One-way hash of your IP address, to limit sign-ups per network |
created_at | When you joined |
Calls from the docs playground ("Try it") demo_usage
To limit the no-signup playground to 20 calls a day per network. The calls themselves (and any VIN you try) are not stored. Kept: 2 days, then deleted.
| Field | What it holds |
|---|---|
ip_hash | One-way hash of your IP address |
day | The day |
calls | How many playground calls that day |
Which pages were announced to search engines indexnow_sent
To tell search engines once when a page of this site is new or changed. These are our own page addresses, with no visitor data. Kept: Kept.
| Field | What it holds |
|---|---|
path | The page address |
lastmod | The content date that was announced |
sent_at | When it was announced |
Where the search-engine announcement job waits indexnow_state
So a refused announcement is retried later instead of every run. No visitor data. Kept: Kept.
| Field | What it holds |
|---|---|
key | The name of the value |
value | The value (a time and a count) |
Log of announcements to search engines indexnow_log
To record what was announced and what each search engine answered. No visitor data. Kept: 30 days, then deleted.
| Field | What it holds |
|---|---|
id | Row number |
at | When |
level | info or warn |
message | What was announced and the status each search engine answered |
Where the webhook job stopped webhook_state
So each recall change is checked once. Kept: Kept.
| Field | What it holds |
|---|---|
key | The name of the value |
value | The value (a time) |
Why we use it
To let you in with a key, to enforce the limits, to find and stop bulk copying and abuse, to answer your questions, and to show you your usage. We do not use it for anything else, and we do not build profiles.
How long we keep it
The retention for each field is in the lists above. Signup and "Manage my key" records and network hashes are deleted after 30 days; daily counts after 90 days; the key record and its monthly counts and fair-use log stay while your key exists and are deleted when you delete it.
Who else handles it
We do not sell or share your information. We use Cloudflare as our processor: it hosts the service and the database, runs Turnstile (the human check on our forms, which receives the check token and your IP address and may store data in your browser to run the check), and sends our confirmation emails. Cloudflare handles requests under its own privacy terms.
Cookies
recalldb.app sets one short-lived cookie after you ask for an email: rdb_pending (from the signup form, sent only to /signup) or rdb_manage (from Manage my key, sent only to /manage). It holds your email address, encrypted, for 30 minutes (HttpOnly, Secure), so the "Resend" button works without showing your address on the page. It is not used for anything else and there are no analytics or advertising cookies. The Turnstile check on the signup and "Manage my key" pages is run by Cloudflare and may use browser storage to do its job.
Your rights
Wherever you live, you can ask us to tell you what we hold about you, to correct it, or to delete it. In plain terms:
- California (CCPA/CPRA): you can know what we collect and why, ask for a copy, ask us to delete it, and ask us not to sell or share it. We do not sell or share personal information, and we do not discriminate against anyone who uses these rights.
- European Economic Area and UK (GDPR): you can ask for access, correction, deletion, restriction, a portable copy, or object to our use, and you can complain to your local data protection authority. We use your information because it is needed to run the service you asked for (a key) and for our legitimate interest in keeping the service safe from abuse.
How to use them. To delete: Manage my key sends a one-time link to your email and lets you delete your key and its data yourself. For anything else, write to support@recalldb.app from the address you signed up with. Because we only keep a hash of your email, we need your address to find your records; we compute its hash to look it up. We reply within 30 days.
One exception: if a key was suspended or revoked for misuse, we keep the minimum needed to stop the same person coming back (the key record and its fair-use log), and tell you so.
Children
The API is for developers and is not meant for people under 16.
Changes
We list every change to this page in the changelog with its date.