Every build eventually needs something the client has to type in themselves: a WordPress admin login, an FTP or hosting password, a DNS registrar login, a Stripe secret key. There is no good place to put that today.
The usual paths are all bad the same way. The client emails the password in plain text, and it sits in an inbox forever, copied into every backup that inbox has. Or it lands in a Slack DM, searchable by anyone later added to the workspace. Or, worst of all, it gets pasted into a chat with an AI agent, becoming part of a transcript that may be logged or retained by a third party you never agreed to trust with it.
None of these expire. None of them get deleted. None make it obvious, months later, who actually saw the value.
Credentials are not just another piece of client content. A logo or a paragraph of copy is fine sitting in a database in plaintext. A password is not, and it needs handling that is different by design.
secret item to the intake. Alongside the logo and the copy, your agent asks for wp_admin with type: "secret" — a masked field, distinct from every text or file item.required: false and the intake still completes without it — useful for a credential that genuinely doesn't exist yet or that the client wants to hand over by another channel.get_intake_results returns the decrypted value on the first call. After that, the value is gone from the API for good — a second call gets secret_unavailable and a timestamp, not the password again.
Your agent defines the intake with a mix of ordinary items and one secret — the shape of the call doesn't change, only the type does:
{
"project_name": "Site migration — Hillcrest Dental",
"client": {
"name": "Dr. Patel",
"email": "[email protected]"
},
"items": [
{
"key": "wp_admin",
"type": "secret",
"label": "Current WordPress admin login",
"help": "Username and password for wp-admin. Shown to your developer once, then discarded.",
"required": false
},
{
"key": "domain_registrar",
"type": "secret",
"label": "Domain registrar login",
"help": "So we can update DNS once the new site is ready."
}
]
}get_intake_results returns each ordinary item as a plain value — text as a string, a logo as a signed URL. A secret item is different: on the one call that reveals it, wp_admin comes back with the plaintext value and first_reveal: true; every call after that returns null with a reason instead. Store the value in your own secrets manager the moment you see it — there is no second chance.
You stop asking the client to paste a password into a chat window or an email you'll have to remember to delete. The credential moves once, gets used, and disappears from the system that handled it — with a record of exactly when and by whom. When a credential isn't ready yet, the intake doesn't stall waiting for it.
To be precise about what this is: it is not zero-knowledge, and the value is not encrypted in the client's browser — it travels over HTTPS and is sealed the moment it reaches the server. What it buys you is that a database dump yields ciphertext, not credentials, and that no one — including you — can pull the value a second time after it's been revealed.
Start with a free account, no card required; secret items are part of the Solo plan and up, everything else in the intake works on Free.
Free tier, no card required.