Last reviewed 30 September 2026.
Postgres, authentication and file storage are in eu-west-1 (Ireland), read from the Supabase project on 2026-09-30. Edge functions run on Supabase's edge network in the region nearest the caller (not pinned).
The assistant's text models run on GreenPT, in this order of preference: deepseek-v4-flash-0731, then glm-5.2, then mistral-medium-3.5-128b. Other text also leaves: Groq classifies accounting lines when a consultant links an accounting connector and transcribes voice dictation; DeepSeek receives document titles, the first 2,000 characters and knowledge-base chunks for knowledge-base indexing; Hugging Face computes embeddings of knowledge text. Each is listed in the table below.
Every image sent to the assistant or attached to a data request, and every scanned page, is sent to Anthropic (claude-haiku-4-5) in the United States, under Anthropic's commercial terms and data processing agreement. This includes scanned documents uploaded by recipients through the data portal.
The assistant's model calls and the other /api routes run through Vercel serverless functions in iad1 (US) before reaching a model, even when the model is in the EU. Scanned pages go from the browser to a Supabase edge function and from there to Anthropic; connector classification and knowledge-base indexing run inside Supabase edge functions. The rate-limit counters for /api are kept in Upstash in us-east-1.
Postgres row-level security is enabled on every organisation table, so a signed-in user can only read or write data of organisations they belong to. This was closed out on 2026-09-04.
The model proxy has required authentication since 2026-09-03 and is rate limited to 90 requests per minute per user (since 2026-09-09).
The assistant's chat turns are written to an EU AI Act Article 12 log: model, token counts, hashes of the input, and the message text, the model's reply and the system prompt (truncated to 10,000, 20,000 and 15,000 characters), kept 180 days. Document extraction, scanned-page reading and edge-function model calls are not in this log. Consultant actions (approvals, corrections) are in a separate audit log that is not part of the 180-day deletion.
Traffic is encrypted in transit with TLS and HSTS. Data at rest is encrypted by the provider (Supabase managed Postgres and Storage).
Uploaded files are stored in Supabase Storage in eu-west-1, with access governed by storage policies.
Error monitoring uses Sentry (EU, de.sentry.io) and product analytics uses PostHog (EU). Browser events have e-mail addresses, tokens and secrets scrubbed, and recipient portal links redacted, before they are sent. Analytics autocapture is off. PostHog session recording is off. Session replay (Sentry) records only when an error occurs and never on recipient pages.
What Sentry receives, as recorded in the subprocessor list:
Sign-in uses a password with an optional TOTP second factor. Once a factor is enrolled, the app requires it at every sign-in (since 2026-10-01); the database policies do not yet require the second factor.
Account holders can export their data and delete their account from the Account security page, served by the gdpr-export and gdpr-delete functions.
As of the review date above:
Every third party that receives data from SOMA, as of 30 September 2026. Regions are stated as read; "Not verified" means we could not read it from our side.
| Name | Role | Region | Data sent | Terms |
|---|---|---|---|---|
| Supabase | Database, authentication, file storage and edge functions | eu-west-1 (Ireland), read from the Supabase management API on 2026-09-30 for both production projects | all customer data stored in the platform (emissions ledger, requests, contacts, reports); account credentials and session tokens; uploaded files | |
| Vercel | Web hosting, CDN and the /api serverless functions | Static files from Vercel's CDN; the /api functions run in iad1 (US East, N. Virginia), read from the x-vercel-id header of /api/health on 2026-09-30 | every request to /api/* (model-proxy prompts, uploads and exports pass through the function); request metadata (IP address, user agent) | |
| GreenPT | Text language models (the assistant, extraction, report drafting) | EU, per GreenPT's own statement (greenpt.com/privacy, read 2026-09-30): models self-hosted on Scaleway (France) and Verda (Finland). The same page says EU and US regions are now available; which region serves api.greenpt.ai for our key is not verified from the box | assistant prompts and the context built into them (figures, document text, question text); text only | |
| Anthropic | Image and scanned-page reading (claude-haiku-4-5) | United States (the api.anthropic.com endpoint); no regional endpoint is configured | every uploaded image and every scanned page (chat drop, portal recipient upload, extract-vision); any /api/ai request that carries an image, including the text of that request | |
| Groq | Voice-dictation transcription and accounting-line classification (llama-3.3-70b-versatile) | United States | audio recorded by the user for dictation; line description, account name, amount and currency of synced accounting lines | |
| DeepSeek | Reference-corpus indexing: one-to-two-sentence context written for each knowledge-base chunk | Not verified from the box (the api.deepseek.com endpoint); the provider is headquartered in China | document title, the first 2000 characters of the document and the chunk, for rows of the knowledge_base table and scraped enforcement pages | |
| Resend | Transactional e-mail (data requests, reminders, invitations, replies) | United States (Resend's default); the sending domain's region cannot be read with the send-only API key we hold (GET /domains answers 403, 2026-09-30) and is an owner item | recipient address, subject and body of each e-mail SOMA sends | |
| Cloudflare | DNS for somaai.earth and inbound e-mail routing (Email Routing and an Email Worker forward replies to the receive-email function) | Cloudflare's global network. It does not proxy the application hosts (app and esg resolve to Vercel, 2026-09-30) | DNS queries for the platform's hostnames; inbound reply e-mails (sender, subject, body, attachments) while they are routed to SOMA | |
| Upstash | Rate-limit counters for /api routes | us-east-1 (database soma-mvp-ratelimit, HISTORY #191) | sliding-window counters whose keys are SHA-256 hashes (first 32 hex characters) of the user id, portal token, partner API key id (api/v1/ai-factors.ts) or client IP address, never the raw value (no message content) | |
| Sentry | Error monitoring and on-error session replay | EU (Germany): the production DSN host is ingest.de.sentry.io, read 2026-09-30 | browser error events, scrubbed before transmission (e-mail addresses, JWTs, secrets, token URLs); server-side error events from the Vercel functions and the listed edge functions carry the error message (up to 8000 characters) and stack (up to 4000 characters) with e-mail addresses, JWTs, secrets and portal-token URLs redacted before sending; other text in the message is sent as written; on-error replay with all text, inputs and media masked (sampling: session replay 0, on-error 0.2) | |
| PostHog | Product analytics (autocapture disabled) | EU: VITE_POSTHOG_HOST is eu.i.posthog.com in both production environments, read 2026-09-30 | named product events and page views with personal data scrubbed; no session recordings | |
| Hugging Face | Text embeddings (BAAI/bge-large-en-v1.5 through router.huggingface.co) | Not verified from the box (provider-routed inference) | up to 2000 characters of text per call: reference-corpus chunks (knowledge_base rows) from the indexing functions, and the query text when generate-embedding is called | |
| Climatiq | Emission-factor lookup for a connected Climatiq account (only when a consultant connects one) | Not verified from the box | an activity identifier plus an amount and unit | |
| WRI Aqueduct | Physical water-risk lookup for a site | Not verified from the box | the latitude and longitude of the site being assessed | |
| VirusTotal | Uploaded-file reputation check | Not verified from the box | the SHA-256 hash of an uploaded file; the file itself is not sent | |
| CNaught | Carbon credit purchases (carbon edition only) | Not verified from the box | portfolio choice, tonnes and beneficiary name of a purchase the consultant confirms | |
| Xero | Accounting connector (only when a consultant connects a Xero organisation) | Not verified from the box | OAuth tokens; the accounting data SOMA reads back from the connected organisation | |
| Intuit QuickBooks | Accounting connector (only when a consultant connects a QuickBooks company) | Not verified from the box | OAuth tokens; the accounting data SOMA reads back from the connected company | |
| Sage | Accounting connector (only when a consultant connects a Sage business) | Not verified from the box | OAuth tokens; the accounting data SOMA reads back from the connected business | |
| Payhawk | Expense connector (only when a consultant connects a Payhawk account) | Not verified from the box | API credential; the expense data SOMA reads back from the connected account | |
| Holded | Accounting connector (only when a consultant connects a Holded account) | Not verified from the box | API credential; the accounting data SOMA reads back from the connected account | |
| Sign-in with Google for Drive export (the drive.file scope) when a consultant chooses to save a report to their own Drive | Not verified from the box | the report file the consultant chooses to upload to their own Google Drive; Google OAuth token held in the browser | ||
| Logo and favicon lookup (icon.horse, Google favicon service) | Company logo shown for a client | Not verified from the box | the domain name of the client's website, in the image URL |
Write to the address below with details. The machine-readable contact file is linked as well.