Menu
View as Markdown

Entries

Entries are what viewers save from a page: votes, RSVPs, sign-ups, answers, comments. Page data is written by you; entries are written by the people viewing the page.

Viewersigned in to DocPinclicksYour page codedocpin.shared.put()asksDocPin pageadds the sign-insavesEntriesvalue + author's emailname only (sam)full emailOther viewersvia list() on the pageYour workspaceData tab · API · MCP
A viewer's entry goes from your page through the DocPin page, which adds who they are. Other viewers see only the name before the @; your workspace sees the email.

At a glance

Off by defaultTurn on per page: Data → Let viewers save entries in the app, PATCH /v1/pages/{id} with {"entries": "viewers"}, or the MCP tool set_page_entries
Two kindsShared collections everyone can read (docpin.shared), and each person's private object (docpin.mine)
Who can saveViewers signed in to DocPin who can open the page. One email is one person
Who can readAnyone who can open the page reads shared entries, with authors' names (the part of the email before the @)
EmailsOnly your workspace sees them, in the app, the API and MCP
RemovingViewers delete their own entries, or everything they saved with Remove my entries in the DocPin panel. Your workspace can delete any entry

Who can save

Page accessRead shared entriesSave entries
teamMembersMembers
peopleMembers and listed peopleMembers and listed people
passwordAnyone with the passwordPeople signed in to DocPin on that site. The password screen offers your team a sign-in
publicAnyoneOnly people already signed in to DocPin on that site
A secret-link (unlisted) public or password page, at its docpin.it short linkAnyoneNobody: viewers stay anonymous there

Use them in the page

Read first, then save when the person does something, such as pressing a button. Saving can fail (they may not be signed in), so catch it and say why.

<button id="going">I'm going</button>
<p id="status"></p>
<ul id="rsvps"></ul>
<script type="module">
  const status = document.querySelector("#status");
  const show = async () => {
    const { entries } = await docpin.shared.list("rsvps");
    const list = document.querySelector("#rsvps");
    list.replaceChildren();
    for (const e of entries) {
      const li = document.createElement("li");
      li.textContent = e.author.name;
      list.append(li);
    }
  };
  document.querySelector("#going").onclick = async () => {
    try {
      await docpin.shared.put("rsvps", { going: true });
      await show();
    } catch (e) {
      status.textContent = e.message;
    }
  };
  show().catch((e) => (status.textContent = e.message));
</script>

Always show entries as text, never as HTML. Use textContent or createTextNode, not innerHTML. An entry is whatever a viewer typed; inserting it as HTML would let one viewer run code in other viewers' browsers.

Page API

docpin.viewer(): Promise<{ signedIn: true; name: string } | { signedIn: false }>

docpin.mine.get(): Promise<object>                    // {} until something's saved
docpin.mine.set(changes: object): Promise<object>     // merges; a null value removes that key

docpin.shared.list(collection: string, options?: { cursor?: string }):
  Promise<{ entries: Entry[]; count: number; cursor: string | null }>
docpin.shared.put(collection: string, value: unknown): Promise<Entry>
docpin.shared.add(collection: string, value: unknown): Promise<Entry>
docpin.shared.remove(id: string): Promise<{ removed: true; id: string }>

type Entry = {
  id: string;
  collection: string;
  author: { name: string; you: boolean };   // name: the part of the email before the @
  value: unknown;
  createdAt: string;
  updatedAt: string;
};
CallWhat it does
viewer()Whether the person is signed in, and their name. Pages never get a viewer's full email
mine.get() / mine.set(changes)This person's private object on this page. Only they read it through the page. Up to 64 KB
shared.list(collection, { cursor })Up to 500 entries, oldest first. When cursor isn't null, pass it back for the next 500
shared.put(collection, value)This person's one entry in the collection, created or replaced. For votes, RSVPs and scores: nobody can vote twice
shared.add(collection, value)A new entry every time. For comments and logs
shared.remove(id)Deletes one of this person's own entries

Rules:

Errors

A failed call rejects with an Error whose code is:

codeMeaning
offEntries aren't on, the page is a draft or archived, or it isn't open at its DocPin link (a version preview, or a file opened on its own)
signinThe person needs to be signed in to DocPin to save
forbiddenThey can't open the page, or it isn't their entry
not_foundThat entry doesn't exist any more
limitA limit was reached
rateToo many calls. Wait a moment
invalidSomething about the call is wrong; the message says what
busyDocPin was busy. Try again
timeoutNo answer within 15 seconds. The save may still have worked: read before saving again
networkThe browser couldn't reach DocPin
errorSomething went wrong on DocPin's side

Limits

FreePro
All entries on a page1 MB, 2,000 entries10 MB, 50,000 entries
Shared entries one person can have on a page100, 100 KB1,000, 1 MB
One entry16 KB16 KB
Private object per person per page64 KB64 KB
Saving30 a minute per person, 300 per pageSame
Reading (viewer, mine.get, list)300 a minute per person on a page (per network address if not signed in), and 3,000 a minute per page in totalSame

Making an entry smaller always works, even over a limit.

For your workspace

Everyone in the workspace can see entries with each author's email: in the app on the page's Data tab (with CSV and JSON export), or with the REST API and MCP.

PATCH/v1/pages/{id}

Body { "entries": "viewers" } turns entries on; { "entries": "off" } closes the page to new ones, keeping what's there. Returns { "entries": "viewers" | "off" }. You can also pass entries to POST /v1/pages; it's ignored for drafts.

GET/v1/pages/{id}/entries

Query: collection (a name, or empty for everyone's private objects; leave it out for all), offset. Returns the newest 500 entries, newest first:

{
  "setting": "viewers",
  "usage": { "bytes": 2140, "entries": 12, "maxBytes": 1000000, "maxEntries": 2000 },
  "collections": [{ "name": "rsvps", "mine": false, "count": 9 }, { "name": "", "mine": true, "count": 3 }],
  "entries": [{ "id": "…", "kind": "put", "collection": "rsvps", "author": "sam@acme.com", "value": { "going": true }, "createdAt": "…", "updatedAt": "…" }],
  "count": 12,
  "next": null
}

kind is put, add, or mine for a private object (whose collection is null). When next isn't null, pass it as offset.

DELETE/v1/pages/{id}/entries

Deletes a collection (?collection=rsvps), everyone's private objects (?collection= with nothing after it), or every entry (no collection). Returns { "removed": 9 }.

DELETE/v1/pages/{id}/entries/{entryId}

Deletes one entry. Returns { "removed": 1 }, or 404.

MCP

ToolWhat it does
set_page_entrieson: true or false for a page
get_page_entriesTotals, collections and the newest entries with emails. Optional collection

Deleting the page, or deleting its board along with the board's pages, deletes its entries. Renaming or moving it, or publishing a new version, keeps them. When someone deletes their DocPin account, their entries are deleted.