Security & trust

How we protect clinic and patient data.

Healthcare data demands a higher standard than typical SaaS workloads. This page describes the technical and operational measures Leadly Egypt LLC has in place to protect clinic and patient information.

Last reviewed: May 14, 2026 · Questions: security@leadly-egypt.com

Architecture

Where your data lives

Leadly is built on specialist infrastructure providers — each one certified for the workload it handles. We don't run our own servers, and we don't store patient data on the compute layer.

⚙️

Compute layer — Render

Our application code runs on Render's managed container platform. Render terminates TLS at the edge, auto-renews certificates, and provides DDoS protection.

  • SOC 2 Type II certified, ISO 27001 certified
  • Filesystem is ephemeral — patient data is never persisted on the compute layer
  • TLS 1.2+ enforced on every inbound connection
  • Application secrets injected via environment variables, never committed to source
🗄️

Database — Upstash Redis (Europe)

Patient records, appointments, sessions, conversation history, and clinic configuration live here. Hosted in Europe, on AWS-backed infrastructure with block-storage encryption applied at the platform layer.

  • Encrypted at rest (AWS-managed keys) and in transit (TLS)
  • Hosted in the EU — data residency matters under GDPR and Egypt's PDPL
  • Daily automated backups, 7-day retention
  • noeviction policy — your data is never silently dropped to make room
  • Upstash is SOC 2 Type II at the platform level
🖼️

Media storage — Cloudinary

Patient-uploaded images (receipts, photos sent to the bot) and voice notes are stored here, separately from the database, with signed-URL access.

  • SOC 2 Type II certified, ISO 27001 certified, GDPR-compliant
  • Signed URLs prevent unauthenticated access to assets
  • Per-tenant folder isolation
💳

Payments — Stripe

Subscription billing and payment processing for the clinic itself runs entirely through Stripe. Leadly never sees or stores card numbers — payment fields render directly inside Stripe's iframe, scoped out of our application.

  • Stripe is PCI-DSS Level 1 certified — the highest tier
  • Leadly carries zero PCI scope
  • Webhook signatures verified on every billing event
🤖

AI processing — Anthropic, OpenAI, ElevenLabs

Message content passes through these providers for natural-language understanding, voice transcription, and text-to-speech. All three operate under enterprise data processing agreements.

  • Zero training on customer data (contractually guaranteed)
  • 30-day retention windows, then automatic deletion
  • Data in transit always over TLS
📱

WhatsApp verification — Meta Cloud API

For phone-number verification, we receive a single short code message from each patient's WhatsApp. We don't store WhatsApp messages — the code is matched against the pending verification in memory and discarded.

  • Click-to-WhatsApp self-verification — the patient's WhatsApp account proves phone ownership
  • Sender phone is cross-checked against the typed phone to prevent impersonation
  • 5-minute code TTL, single-use, rate-limited
Access control

Who can see what

Three layers of access control, each enforced independently. A failure in one doesn't bypass the others.

🔒

Per-clinic data isolation

Every database key is prefixed with the tenant identifier (t:<clinic-id>:customer:<phone>). Application code enforces this on every query — no shared tables, no joins across clinics, no "global patient search". One clinic literally cannot see another clinic's data, even if our access control had a bug, because the keys they could request don't exist in their tenant scope.

👥

Role-based access within a clinic

Inside a clinic, four roles: owner (full access), doctor (sees their own patients and schedule), receptionist (booking, deposits, calendar), and the AI receptionist itself (most narrowly scoped — only the tools needed for the patient request). Sensitive actions require elevated permissions.

📲

Patient identity verification

Patients prove phone ownership via WhatsApp before any of their data is revealed. Typing a phone number is never enough — the patient must send a one-time code from their own WhatsApp. This prevents the "type someone else's number, see their appointments" attack that plagues simpler systems.

🍪

Cryptographically-signed sessions

Patient session cookies are signed with HMAC-SHA256. Even if a session ID leaked, an attacker can't forge a valid signature without our signing secret. Sessions expire after 30 days of inactivity. Staff sessions follow the same pattern with shorter lifetimes.

Data integrity

Backup, recovery, and durability

What happens to your data if something goes wrong.

💾

Daily backups, 7-day retention

Upstash takes daily snapshots of every database, retained for 7 days. If the worst happens — accidental delete, ransomware, our own bad deploy — we can restore from the most recent snapshot.

🚫

noeviction memory policy

Many Redis deployments evict data when memory is tight. We use noeviction: if memory fills up, writes fail loudly. We'd rather see a write error and fix the capacity problem than silently lose patient records.

🔁

Idempotent operations

Critical operations like booking, deposit confirmation, and Stripe events are designed to be idempotent — retried automatically without duplication. Network blips during a booking don't create ghost appointments or double-charged deposits.

📋

Operational logging

Logins, admin actions, booking changes, billing events, and security-relevant events are logged with timestamps and retained on our compute provider's logging infrastructure. Logs are queryable for investigation. We are working toward a first-class queryable audit log with structured actor/target/timestamp records.

Application defenses

In-application protections

Beyond infrastructure, the application layer enforces specific defenses against the categories of attack that target AI receptionist platforms: cost abuse, cross-tenant data leakage, and AI hallucination of unverified facts.

🚦

Rate limiting

Every inbound patient message — whether from the web chat, WhatsApp, or Instagram/Facebook — passes through three concentric rate limits.

  • Per-session: 10 messages per minute, the tightest ring
  • Per-phone: 60 messages per hour, catches attackers rotating cookies
  • Per-tenant: 200 messages per minute, bounds cost-attack worst case
  • Real patients never hit these — 10 per minute is one every six seconds
  • Over-limit messages are dropped with a polite Arabic apology; we don't disconnect
🛡️

Webhook signature verification

Inbound WhatsApp and payment webhooks are HMAC-verified using the platform's App Secret before any processing happens.

  • Meta WhatsApp webhooks: SHA-256 HMAC on the raw request body, compared in constant time
  • Stripe billing webhooks: signature verified via Stripe's own SDK; rejected events never touch our database
  • Fawry payment webhooks: signature + tenant binding cross-checked
  • Forged payloads return 401 without touching the database or AI pipeline
🧩

Tenant isolation instrumentation

Every database read and write must run inside a tenant-context wrapper. The application layer logs and (in strict mode) refuses any data access that lacks an explicit tenant scope.

  • Every Redis key is tenant-prefixed at the function level, not at the call site
  • Cross-tenant operations (founder dashboard, cron sweeps) explicitly mark themselves with a dedicated wrapper — they cannot happen by accident
  • Production runs in audit-log mode; staging runs in strict-throw mode
🎯

AI hallucination guardrail

Before any AI-generated reply reaches the patient, a post-processing pass checks the message against the session's captured data and the clinic's verified catalog.

  • Names, phone numbers, and dates that the model asserts are cross-referenced against the patient's session, the clinic's doctor and branch records, and the most recent slot lookup
  • Unverified facts trigger either a log entry (during tuning) or a replacement with a clarifying response (in production)
  • Reduces the risk of a patient receiving wrong doctor names, mistyped deposit numbers, or invented appointment dates
🧪

Phantom-confirmation blocking

The AI is prevented from producing booking-confirmation messages unless an actual booking tool call was executed and a corresponding calendar event was created.

  • Pattern detection on the final reply checks for "booking confirmed"-shaped language
  • If detected without a backing tool call, the reply is replaced with a request for explicit confirmation
  • Prevents the "patient shows up for an appointment that was never actually booked" failure mode
💉

Medical-advice guardrail

The AI is explicitly prevented from issuing medical opinions or diagnoses. Replies that match medical-advice patterns are intercepted and replaced with an escalation to a licensed clinician.

  • Patterns include diagnosis language ("that sounds like X"), prescription suggestions ("take Y"), and treatment recommendations
  • The patient is told the clinician will assess in person; the case is flagged for staff review
Staff access

How clinic staff accounts work

Three role types per clinic, all administered by the clinic owner. Each role sees only what it needs to do its job.

🧑‍💼

Owner

Full access to the clinic's dashboard, billing, staff management, and AI configuration. Invites doctors and receptionists via time-limited invite tokens. Sees everything the doctor and receptionist roles see, plus settings and analytics.

🩺

Doctor

Sees today's appointments, patient intake summaries, allergies, and clinical notes. Cannot issue admin commands (broadcast, takeover, billing actions) — the dashboard chat is read-only for administrative operations and is intended for clinical questions to the AI copilot.

📞

Receptionist

Sees the live patient activity feed, the outbox queue (messages waiting for human review), and can run administrative commands like marking deposits as received, taking over a conversation, or generating a magic link for a returning patient. Cannot manage billing, staff, or AI configuration.

🔐

Authentication

Email and password, with passwords hashed using scrypt (N=16384). Sessions live in Redis with role-specific TTLs (10 hours for clinic staff, 24 hours for platform operators). Cookies are HMAC-signed and Secure+HttpOnly+SameSite=Lax. Onboarding uses single-use invite tokens that expire after 7 days.

Sub-processors

Who else touches your data

Every third-party service that processes Customer data, with its purpose, region, and certifications. We notify Customers of changes per the Customer Agreement.

Sub-processor Purpose Region Compliance
Render Application compute & TLS termination (no data storage) EU (Frankfurt) SOC 2 Type II, ISO 27001
Upstash Primary database (Redis) — patient records, appointments, sessions EU SOC 2 Type II (platform level), AWS-backed encryption at rest
Cloudinary Uploaded media — patient images, voice notes, receipts EU & US SOC 2 Type II, ISO 27001, GDPR-compliant
Stripe Subscription billing & payment processing EU & US PCI-DSS Level 1, SOC 2 Type II
Anthropic AI message understanding (Claude models) US SOC 2 Type II; zero training on customer data; 30-day retention
OpenAI Voice transcription (Whisper / gpt-4o-transcribe) US SOC 2 Type II; zero training on API data; 30-day retention
ElevenLabs Text-to-speech for the voice channel US SOC 2 Type II
Meta Platforms WhatsApp Cloud API — phone verification messages only US & EU SOC 2 Type II; encrypted by WhatsApp end-to-end before reaching us
Responsible disclosure

Reporting a security issue

If you believe you've discovered a security vulnerability in Leadly, please email us at security@leadly-egypt.com. We will acknowledge your report within two business days and work with you toward a coordinated disclosure timeline.

We do not pursue legal action against good-faith security researchers who follow responsible disclosure: no public disclosure before we patch, no access beyond what's needed to demonstrate the issue, no destruction or exfiltration of patient data.

For PGP, append your public key in the first email and we'll respond encrypted.