Customer
Inbound · email
New card is 5555 0100 3321 8810, same address, 22 Calder Street, Leeds.
Mullion sits between your product and every model. Names, emails, cards and addresses become tokens before a prompt leaves your network, and turn back into themselves only when the answer reaches your customer.
One gateway reads every prompt your apps send. Each identifier is found, typed and swapped for a token that stays consistent for the whole conversation.
Customer
Inbound · email
Hi, I'm Maya Okafor. My order #A-4471 arrived broken. Please refund the card ending 4242.
Customer
Inbound · email
Hi, I'm PERSON_1. My order ORDER_1 arrived broken. Please refund the card ending CARD_1.
Agent note
Internal
Verified via maya.okafor@fastmail.com. Ship replacement to 22 Calder Street, Leeds.
Agent note
Internal
Verified via EMAIL_1. Ship replacement to ADDR_1.
Policies are versioned like code. Decide per identifier whether it passes, is partly masked, or becomes a token, and every app and every model behind the gateway follows the same rule from the next request on.
Identifiers
6 of 52 shown
Person names
31 languages, nicknames, initials
Email addresses
Including plus-addressing
Phone numbers
E.164 and local formats
Card numbers
Luhn-checked PANs
Street addresses
Keeps the city if you allow it
Order IDs
Your own pattern: #A-0000
Live preview
what gpt-4.1 receives
Real values wait in an encrypted vault for as long as your policy allows, then they're gone. Replies are re-hydrated at the edge, inside your network, on the way back. The model never holds the key.
AES-256-GCM
per-request key
15 min
default time to live
Your KMS
on Laminated
Streams
re-hydrated live
← from gpt-4.1
Hi PERSON_1, I'm sorry order ORDER_1 arrived damaged. A refund is on its way to the card ending CARD_1, and a replacement ships to ADDR_1 tomorrow.
→ delivered to the customer
Hi PERSON_1, I'm sorry order ORDER_1 arrived damaged. A refund is on its way to the card ending CARD_1, and a replacement ships to ADDR_1 tomorrow.
| token | type | sealed with | expires |
|---|---|---|---|
| PERSON_1 | Name | kms/acme-eu · v4 | 14:52 |
| ORDER_1 | Order ID | kms/acme-eu · v4 | 14:52 |
| CARD_1 | Card | kms/acme-eu · v4 | 06:52 |
| ADDR_1 | Address | kms/acme-eu · v4 | 14:52 |
Keep your SDK, your prompts and your provider keys. Point the base URL at your gateway and every request is covered, streaming included. Nothing else in your code changes.
Speaks the native API of
1import OpenAI from "openai";23const ai = new OpenAI({4apiKey: process.env.OPENAI_API_KEY,5baseURL: "https://api.openai.com/v1",66});78await ai.chat.completions.create({ model: "gpt-4.1", messages });
“Legal had blocked every AI project for eleven months. Mullion went in on a Tuesday, the DPIA was signed on Friday, and the support copilot shipped the week after.”
“We swapped one base URL. Our evals didn't move, and our model logs stopped containing anybody.”
“The audit trail is the first thing our customers' security teams ask to see. Now it's a link.”
Pick a grade, then slide to your monthly volume. You pay for requests that pass through, never for what we detect.
For products in front of customers.
$178/ month
01 / 05
Does the model get worse when it can't see names?
Rarely, and you can measure it. Tokens keep their type and stay consistent across a conversation, so PERSON_1 is still the same person three turns later and the model can reason about them. Across our customers' eval suites the median change is under half a point. Policies are versioned, so you can run your evals against a draft before you publish it.
Ask a security engineer$ npx mullion init --region eu