See the shape.Never the person.

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.

Your prompt, as the model receives it0 held back

Everything passes through. Nobody comes out.

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

09:12

Hi, I'm Maya Okafor. My order #A-4471 arrived broken. Please refund the card ending 4242.

Customer

Inbound · email

09:12

Hi, I'm PERSON_1. My order ORDER_1 arrived broken. Please refund the card ending CARD_1.

Agent note

Internal

09:14

Verified via maya.okafor@fastmail.com. Ship replacement to 22 Calder Street, Leeds.

Agent note

Internal

09:14

Verified via EMAIL_1. Ship replacement to ADDR_1.

identifiers in this thread
14
identifiers in this thread
unique tokens issued
7
unique tokens issued
added at p50
+3.8 ms
added at p50
names in the model's logs
0
names in the model's logs

Write the rule once.
Every model obeys it.

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.

mullion · acme-support / policies / v12published

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

Customer PERSON_1 (EMAIL_1, +44 •••• ••0461) says order #A-4471 arrived broken at •• •••••• Street, Leeds. Refund the card CARD_1 and write her an apology.
tokens
3
masked
2
passed raw
1

The model writes to PERSON_1.Maya reads her own name.

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

vault · eu-west-2 · session 7f3cre-hydrate 0.4 ms

← 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.

Values held in the vault
tokentypeexpires
PERSON_1Name14:52
ORDER_1Order ID14:52
CARD_1Card06:52
ADDR_1Address14:52

A receipt for every prompt.

added at p50, measured at the edge in eu-west-2
3.8ms
added at p50, measured at the edge in eu-west-2
entity types, across 31 languages
52
entity types, across 31 languages
raw identifiers written to any model provider's logs
0
raw identifiers written to any model provider's logs
audit · all appsstreaming
Recent requests through the gateway
timeapp → modelheldraw outadded
signed · ed25519 · exportable to your SIEMShare with auditor

One line puts the pane in.

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

  • OpenAI
  • Anthropic
  • Gemini
  • Mistral
  • Bedrock
  • Azure OpenAI
  • Ollama
  • vLLM
app/assist.ts+1 −1
1import OpenAI from "openai";
2
3const ai = new OpenAI({
4 apiKey: process.env.OPENAI_API_KEY,
5 baseURL: "https://api.openai.com/v1",
6
6});
7
8await ai.chat.completions.create({ model: "gpt-4.1", messages });
waiting for base URL

Said by people we don't name. Unless you ask.

“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.”
PRPERSON_1Head of Platform, ORG_1
“We swapped one base URL. Our evals didn't move, and our model logs stopped containing anybody.”
DAPERSON_2Staff Engineer, ORG_2
“The audit trail is the first thing our customers' security teams ask to see. Now it's a link.”
LVPERSON_3CISO, ORG_3

Priced by the glass.

Pick a grade, then slide to your monthly volume. You pay for requests that pass through, never for what we detect.

480k
10k100k1M10M100M
quote · tempered · monthly

For products in front of customers.

$178/ month

Included
50k requests
After that
$0.30 per 1k
Your volume
480k
  • Custom entity patterns
  • Reversible vault, 24h TTL
  • Policy versions and review
  • 1-year audit trail, exportable
Start a 14-day trial

Asked before every security review.

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

Put a pane between your customers and every model.

$ npx mullion init --region eu
Start free50,000 requests a month, no card.