Security
What we actually do to protect your data and your API traffic.
Last updated: May 24, 2026
Transport Security
All traffic served over HTTPS. HSTS enabled in production with a one-year max-age and preload directive.
Authentication
Dashboard auth via Clerk (MFA/SSO available on Clerk plans). API auth via bearer tokens stored only as hashes.
API Keys
Keys stored as SHA-256 hashes. The full key is shown once at creation and never re-displayed by any listing endpoint.
Signed Webhooks
Every webhook delivery is signed with HMAC-SHA256 and verified using a constant-time comparison. Failed deliveries retry via a persistent queue.
1. Transport & Edge
The website is hosted on Cloudflare Pages and the API runs on Railway. Both serve TLS-terminated HTTPS only; cipher suites and negotiated TLS versions follow each provider's current defaults.
API responses include the following security headers in production:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadX-Content-Type-Options: nosniffX-Frame-Options: DENYContent-Security-Policy: default-src 'none'; frame-ancestors 'none'Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
2. Authentication
Dashboard
The dashboard at vettly.dev authenticates via Clerk. MFA, SSO, and session controls are available subject to your Clerk plan and configuration.
API
API requests authenticate using a bearer token in the Authorization header. We store only a SHA-256 hash of each key, indexed for lookup. The full key value is returned exactly once — at creation — and is never visible again through any list or retrieval endpoint.
The decision endpoint (/v1/check) also accepts Clerk JWTs and short-lived session tokens, so dashboard and SDK callers can authenticate without provisioning a long-lived API key.
3. Request Protections
Every authenticated request is rate-limited per API key using a Redis-backed sliding window. Limits depend on your plan:
| Plan | Per minute | Per hour |
|---|---|---|
| Free | 10 | 500 |
| Growth | 100 | 10,000 |
| Pro | 500 | 50,000 |
| Enterprise | 1,000 | 200,000 |
Responses include standard X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers so clients can back off cleanly before hitting a 429.
4. Webhook Delivery
Outbound webhooks are signed per-delivery with HMAC-SHA256 using the endpoint's shared secret. The signature is sent in a request header alongside the payload; verification on your side should use a constant-time comparison (such as Node's crypto.timingSafeEqual) — that's the same primitive we use when checking signatures we generate ourselves.
Delivery is backed by a persistent BullMQ queue. Failed deliveries are retried with backoff, so a momentarily unavailable receiver won't drop events.
5. Data Handling
Vettly stores data in a managed PostgreSQL database on Railway. At-rest encryption is provided by Railway's managed Postgres offering; we don't add an additional application-layer encryption envelope on top of it.
When evidence storage is enabled, payloads are written to object storage (Cloudflare R2 or AWS S3, depending on your deployment) with a configurable retention window — seven days by default.
What we store about your account and your traffic:
- Account: email, Clerk user ID, plan tier, preferences
- API keys: SHA-256 hashes plus metadata (name, last used)
- Decisions: result, provider, latency, content hashes, request metadata
- Webhook endpoints and delivery logs (status code, attempts, next retry)
What our logs do not capture: the value of Authorization headers, raw API keys, or the full body of content submitted for moderation. Logs are structured JSON (pino) and emit only the fields explicitly set on each log line.
6. Vulnerability Disclosure
If you believe you've found a security issue in Vettly, we'd like to hear from you. Email reports to [email protected]. This contact is also published in our machine-readable security.txt per RFC 9116.
What to include
- A clear description of the issue and its impact
- Reproduction steps — minimal working example or curl command if possible
- Relevant request/response logs, screenshots, or video
- Your preferred name or handle for credit, if any
Our commitment
We'll acknowledge your report within five business days, keep you posted as we investigate, and credit you (with your permission) once a fix is shipped. Good-faith research conducted under this policy will not result in legal action from Vettly.
Out of scope
- Denial-of-service testing, volumetric attacks, or rate-limit-busting
- Social engineering of Vettly employees or customers
- Physical attacks against any facility or person
- Issues in third-party services we depend on (Clerk, Railway, Cloudflare, Stripe, Polar, OpenAI, Anthropic) — please report those directly to the vendor
- Reports that consist solely of automated scanner output with no validated impact
7. What we don't claim
Vettly is a small team. We do not currently hold SOC 2, ISO 27001, or HIPAA certifications, and we don't run formal third-party penetration tests on a fixed cadence.
If you need a signed DPA, a security questionnaire completed, or have specific regulatory requirements, reach out to [email protected] and we'll tell you honestly what we can and can't provide today.