← Getting started

API reference

Everything is a plain HTTPS call with a bearer API key. Create a key in the dashboard. Machine-readable spec at /api/openapi.json. Agents should use the skill. In ChatGPT or Claude on the web, connect PTAL instead of pasting keys: ChatGPT guide, Claude and other apps. Wondering how PTAL differs from Claude artifacts or ChatGPT Space? See how PTAL compares.

Concepts

  • Page: an HTML or Markdown document at https://ptal.page/<id>. Ids are 14 random characters.
  • Version: every update creates one. /<id>/v/<n> is permanent. Restore any version.
  • Inbox: what readers send back: comments with the quoted text, replies, form submissions. Read, act, acknowledge.
  • Expiry: on the free plan, pages live 30 days after their last write, and any update or metadata change renews them. On Pro, pages do not expire unless you set a ttl (30d, 90d, 1y or never).
  • Visibility: who can open a page: anyone with the link, signed-in readers, or your organization, with an optional password. See Sharing.

Publish

# Markdown (raw body)
curl -X POST https://ptal.org/api/v1/pages -H "Authorization: Bearer $PTAL_API_KEY" \
  -H "Content-Type: text/markdown" --data-binary @report.md

# HTML (raw body) with a title and a password
curl -X POST https://ptal.org/api/v1/pages -H "Authorization: Bearer $PTAL_API_KEY" \
  -H "Content-Type: text/html" -H "X-PTAL-Title: Q3 numbers" -H "X-PTAL-Password: hunter2" \
  --data-binary @page.html

# Markdown that only your organization can open
curl -X POST https://ptal.org/api/v1/pages -H "Authorization: Bearer $PTAL_API_KEY" \
  -H "Content-Type: text/markdown" -H "X-PTAL-Visibility: organization" --data-binary @plan.md

# JSON
curl -X POST https://ptal.org/api/v1/pages -H "Authorization: Bearer $PTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markdown":"# Hello","comments_enabled":true}'

Response: { "id", "url", "dashboard_url", "version", "expires_at", … }. Update with PUT /pages/{id} using the same body forms. Change metadata with PATCH (title, ttl, visibility, password, comments_enabled, notify_muted). DELETE removes the page.

Sharing

A PTAL page is made to be sent to someone else: a client, a reviewer, a friend, a whole team. The reader needs no account and no particular app. You decide how open the link is when you publish, and you can change it at any time without changing the link.

Who can open the page

  • public: anyone with the link. This is the usual default. Links are 14 random characters, never listed anywhere, and served with noindex, so “public” means “anyone you send it to”, not “findable”.
  • signed_in: anyone with a PTAL account. Readers who are not signed in are sent to PTAL to sign in or create a free account, then straight back to the page. Use this when you want to know who read and commented.
  • organization: members of the publishing organization only. A forwarded link opens nothing for anyone else.

A password can be added on top of any visibility. Readers type it once per browser. Set it when publishing with X-PTAL-Password or the password field, or later with PATCH; send null to remove it.

# Change who can open a page, without changing its link
curl -X PATCH https://ptal.org/api/v1/pages/$ID -H "Authorization: Bearer $PTAL_API_KEY" \
  -H "Content-Type: application/json" -d '{"visibility":"signed_in","password":null}'

Who readers are

Signed-in readers comment by name, with their profile photo. Anonymous readers on public pages choose a display name when they first comment. A commenter's email is private unless they are in your organization or have chosen to share it in their profile. Comments can be turned off per page with comments_enabled; forms still work.

Sharing policy for organizations

On Pro, an organization admin can set rules that apply to every member's pages, under Sharing in the dashboard: which visibilities are allowed and which is the default, whether passwords may be set, and the default and maximum expiry. Publishing or changing a page against the policy fails with 403 forbidden and a message that says which rule applied. Agents can read the policy first:

curl https://ptal.org/api/v1/me/sharing -H "Authorization: Bearer $PTAL_API_KEY"
# {"visibilities":["signed_in","organization"],"default_visibility":"organization",
#  "passwords_allowed":true,"default_ttl":"90d","max_ttl":"1y"}

Sharing from an agent

Visibility is a parameter, so an agent, a script or a scheduled job can publish a page for a specific audience with nobody clicking a Share button. The skill accepts --visibility and --password; the connector exposes the same options to ChatGPT and Claude on the web.

Forms

Any form with a data-ptal-form attribute is captured, no backend needed:

<form data-ptal-form="q3-questions">
  <label>Q3 revenue <input name="q3_revenue"></label>
  <label>Notes <textarea name="notes"></textarea></label>
  <button type="submit">Send</button>
</form>

Read the inbox

# New events on one page, as Markdown an agent can read
curl "https://ptal.org/api/v1/pages/$ID/inbox?unacked=1" -H "Authorization: Bearer $PTAL_API_KEY" -H "Accept: text/markdown"

# Wait up to 60s for something new on that page
curl "https://ptal.org/api/v1/pages/$ID/inbox?unacked=1&wait=60" -H "Authorization: Bearer $PTAL_API_KEY"

# Acknowledge that page's events up to a cursor
curl -X POST https://ptal.org/api/v1/inbox/ack -H "Authorization: Bearer $PTAL_API_KEY" \
  -H "Content-Type: application/json" -d '{"through": 42, "page_id": "'$ID'"}'

# Everything unread across all pages
curl "https://ptal.org/api/v1/me/inbox?unacked=1" -H "Authorization: Bearer $PTAL_API_KEY" -H "Accept: text/markdown"

Pass page_id when you acknowledge after reading one page's inbox. Without it, every unread event up to the cursor is acknowledged, on every page.

Reply in a thread with POST /pages/{id}/comments {"body":"…","parent_id":"c_…"} and resolve with POST /pages/{id}/comments/{cid}/resolve.

Versions

curl https://ptal.org/api/v1/pages/$ID/versions -H "Authorization: Bearer $PTAL_API_KEY"
curl -X POST https://ptal.org/api/v1/pages/$ID/versions/3/restore -H "Authorization: Bearer $PTAL_API_KEY"

Limits and errors

FreePro
Members per organization120
Size per version5 MB25 MB
Active pages20010,000
Versions kept per page10100
Page expiry30 days after last writenever, unless ttl is set
Writes100 / hour per workspace1,000 / hour per workspace
Reader comments60 / hour per IP
Images in comments5 MB each, 4 per comment, 40 per page, 200 MB per workspace5 MB each, 4 per comment, 200 per page, 5 GB per workspace

Errors share one envelope: { "error": { "code", "message", "details"? } } with codes bad_request, unauthorized, forbidden, plan_required, not_found, payload_too_large, rate_limited (with Retry-After), quota_exceeded. plan_required errors also carry upgrade_url; they are returned for options outside the plan and for publishing from an organization with more members than its plan allows.

Serving details

  • Every page is served with X-Robots-Tag: noindex, nosniff and no-referrer. Pages never appear in search engines; crawlers are allowed to fetch so they see the header.
  • When comments are enabled, a small script is appended before </body>. Turn comments off to serve bytes exactly as uploaded.
  • Markdown pages also serve their source at /<id>/index.md or with Accept: text/markdown.
  • Content lives on a separate domain from your account for cookie and reputation isolation.