OpenTree DashboardSign in

$ set_password

Put a password in front of an HTML page

One call, no rebuild, no account for the reader. The passcode is checked before a single byte of the page is served, and you can add or clear it long after the link has gone out.

Set one

set_password({ site_id: "…", password: "hunter2" })

Or at publish time, so the page is never briefly ungated:

curl -X POST https://read.botook.ai/sites \
  -H "Authorization: Bearer otr_live_YOUR_KEY" \
  -F file=@report.html -F password=hunter2

Clear one

curl -X PATCH https://read.botook.ai/sites/SITE_ID \
  -H "Authorization: Bearer otr_live_YOUR_KEY" \
  -H "content-type: application/json" -d '{"password": null}'

Adding, changing and clearing all work on a page you already shared — the link never changes.

What the reader sees

A single field. They type the passcode, the page loads, and a cookie keeps them in for the rest of the session. No account, no email, no download — which matters, because the person on the other end is usually a client who did not ask to join anything.

How it is checked

It is not stored in plaintext

Only a hash is kept. A lost passcode is replaced, never recovered — which is also why the dashboard can never show it back to you.

Password versus the other gates

GateReader doesRight when
Unguessable linkClicksThe link itself is the secret and the audience is small.
PasswordTypes a passcode you already gave themYou have a side channel: a call, a contract, an existing thread.
Email-domain gateConfirms a work addressThe audience is a company, not a person.
Burn after readOpens onceHanding over a credential or a one-time report.

Stack it with expiry

A passcode and a deadline answer different questions. Both at once is normal:

set_password({ site_id: "…", password: "hunter2" })
set_expiry({ site_id: "…", expires_in_hours: 72 })

Send the passcode separately

A link and its passcode in the same email is one gate, not two. Send the link by mail and the passcode by whatever channel you already use with that client.

Artifacts and drafts

A Claude artifact you already published publicly cannot be un-published retroactively — you can only stop sharing it going forward. Re-publishing the same HTML here, with a passcode, gives you a link whose access you actually control: how that works.

When a password is the wrong tool

If the material should not be readable by this deployment at all, a passcode does not do that — it gates access, it does not hide the bytes from the host. Publish with end-to-end encryption instead: the key rides in the URL fragment and never reaches the server.

Rotating it

Set a new one. Existing sessions are not portable to a new reader, and the old passcode stops working immediately:

set_password({ site_id: "…", password: "a-different-one" })

From the dashboard

Everything above is a control in the dashboard too: pick the page, set the passcode, done. The API exists for agents; the dashboard exists because sometimes it is 9pm and you are on a phone.

Questions

Can everyone share one passcode?

Yes, and for a client review that is usually right. Mint separate share tokens when you need to revoke one audience alone.

Does the passcode expire?

Not on its own. Pair it with set_expiry if it should.

Can an agent set it?

That is exactly what set_password is for.

Keep reading