Seal for sellers
You sell something digital β license keys, paid PDFs, premium templates, one-shot data. You already have your own payment processor. Seal is the delivery layer that lets you hand the goods over with the file actually consumed on receipt and proof your platform never had a re-readable copy.
Selling software license keys
You sell a license key for desktop software. Customer pays, your backend generates the key, you want it delivered once β to them and only them β and removed from your servers afterward.
The flow
The key step (Python)
import os, base64, requests
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# 1. After Stripe webhook fires, generate the license
license_key = generate_my_license() # your function
# 2. Encrypt locally β server never sees plaintext
key = AESGCM.generate_key(bit_length=256)
nonce = os.urandom(12)
ciphertext = AESGCM(key).encrypt(nonce, license_key.encode(), None)
# 3. POST to Seal
r = requests.post(
"https://seal.ai-ministries.com/v1/seals",
headers={"Authorization": f"Bearer {SEAL_API_KEY}"},
json={
"ciphertext": base64.b64encode(nonce + ciphertext).decode(),
"ttl_seconds": 7 * 86400, # 7 days to open
"max_reads": 1, # burn after first open
"name": "license.txt",
"mime": "text/plain",
}
)
sid = r.json()["id"]
# 4. Build the share URL β the key goes in the fragment
key_b64url = base64.urlsafe_b64encode(key).rstrip(b"=").decode()
share_url = f"https://seal.ai-ministries.com/#/open/{sid}!{key_b64url}"
# 5. Email it
send_email(customer.email, subject="Your license", body=share_url)
When the customer opens the link, our server fires seal.opened back to your webhook URL so you can mark the order delivered.
Selling premium PDFs & templates
You sell a $19 paid guide or a Notion template. Buyer should be able to download it a few times within a window (in case they close the tab) but not forever.
The flow
What's different
- Set
"max_reads": 3instead of 1, so the buyer can come back to the email and re-download a couple times. - Set
"ttl_seconds": 604800(7 days). After that, the file deletes from our server permanently β even if they didn't open it. - Set
"name": "definitive-guide.pdf","mime": "application/pdf"so their browser knows to offer it as a download.
The key step (Node)
import { webcrypto } from 'crypto';
import fs from 'fs';
const pdf = fs.readFileSync('definitive-guide.pdf');
// Encrypt
const key = await webcrypto.subtle.generateKey({name:'AES-GCM',length:256}, true, ['encrypt','decrypt']);
const nonce = webcrypto.getRandomValues(new Uint8Array(12));
const ct = new Uint8Array(await webcrypto.subtle.encrypt({name:'AES-GCM',iv:nonce}, key, pdf));
const blob = new Uint8Array(nonce.length + ct.length);
blob.set(nonce, 0); blob.set(ct, nonce.length);
// Mint
const r = await fetch('https://seal.ai-ministries.com/v1/seals', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.SEAL_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
ciphertext: Buffer.from(blob).toString('base64'),
ttl_seconds: 7 * 86400,
max_reads: 3,
name: 'definitive-guide.pdf',
mime: 'application/pdf',
}),
});
const { id } = await r.json();
const rawKey = new Uint8Array(await webcrypto.subtle.exportKey('raw', key));
const shareUrl = `https://seal.ai-ministries.com/#/open/${id}!${Buffer.from(rawKey).toString('base64url')}`;
// Send to buyer
await sendEmail(buyer.email, shareUrl);
Anonymous tip / inbound submissions
You run a journalism shop, a security disclosure form, or a "send me a sensitive thing" inbox. You want submissions encrypted before they reach you and gone after you read them.
The flow
What's different
- Encryption happens in the submitter's browser, before anything reaches your backend. Even your own server only sees ciphertext + the key.
- You can mint the seal with no API key auth (anonymous mode) so it doesn't even appear in your dashboard. Same one-read, auto-burn behavior.
- The submitter never has an account. Their identity is whatever they choose to say in the message β we have only their HTTP-level metadata at submit time.
Threat model note: our server logs the IP that submitted, the same way any web service does. If you're using this for source protection where the IP itself is dangerous, advise submitters to use Tor or a public network.
Why use Seal as your delivery layer?
- Provable scarcity. Each sale is a separate one-read seal. We can't keep a copy. You can't accidentally re-deliver.
- Server can't read what you sold. Encryption is your responsibility (in your own backend or your buyer's browser). We hold ciphertext.
- Auto-cleanup. Anything not opened by the TTL is wiped from our disks. No stale customer files lingering.
- Webhooks. You know when a buyer actually opens β fire your "delivered" workflow then, not before.
- Free public beta. No card to start. 1,000 seals/month built in. Sign in for an API key.