RootBound

For developers

RootBound Tree API

Show a family’s published tree on another website. Paste one tag, or read the tree as JSON.

What it is

A family’s Recordkeeper can publish the family tree. They do it in RootBound, under Settings, then Publishing. They can publish the whole family. Or they can publish one person’s branch, with a chosen number of generations above and below.

Other websites can then show that tree. A memorial page is a common example. The tree stays up to date. Changes appear within about a minute.

What gets published

These rules are enforced in the database. No key or setting gets around them.

  • Only people visible to the whole family are published.
  • People hidden in the family are never published.
  • Contact details are never published.
  • People who have died show their name, dates with their certainty status, a portrait and a short bio.
  • Living people show their name, a portrait, their birth year and a short bio. Never the full birth date.
  • A living person can choose “limited”. Then only a first or preferred name and a portrait are shown.
  • Under-18s are “limited” until someone chooses otherwise.
  • A person who has claimed their profile makes this choice for themselves.

Keys

Keys are made in Settings, then Publishing. Each key is shown once, so copy it somewhere safe.

rb_pk_...

A website key. It works only on the websites listed for it. It is safe to put in a page.

rb_sk_...

A server key. It must stay on a server. Never put it in a page or an app.

Quick start: embed

Paste this where the tree should appear. Use your publication id and a website key.

<script src="https://rootbound.aristhegf.workers.dev/embed.js" async></script>
<rootbound-tree publication="YOUR_PUBLICATION_ID" key="rb_pk_YOUR_WEBSITE_KEY" theme="auto" height="560"></rootbound-tree>

The <rootbound-tree> tag takes these attributes.

publication
The publication id. Required.
key
Your website key. Required.
theme
light, dark or auto. The default is auto.
accent
A hex colour without the #, for example 7a1f1f.
focus
A person id to open on. Useful when the tree is large.
height
The height in pixels. The default is 560.
title
A title for the tree.

The tree checks for changes once a minute while the page is visible. When the family changes something, it reloads. It lives in Shadow DOM, so your page’s styles don’t touch it, and its styles don’t touch your page.

Site builders

Some site builders strip scripts. Wix and Squarespace are two. On those, use a frame instead.

<iframe src="https://rootbound.aristhegf.workers.dev/embed/YOUR_PUBLICATION_ID?key=rb_pk_YOUR_WEBSITE_KEY&theme=auto" width="100%" height="560" style="border:0" referrerpolicy="strict-origin" loading="lazy" title="Family tree"></iframe>

Keep referrerpolicy="strict-origin". The tree uses it to check which website it is on.

Add the exact address the frame runs on to the key’s list of websites. Some builders host custom HTML on their own domain. If yours does, list that domain.

JSON API

Every path below starts from https://rootbound.aristhegf.workers.dev/api/v1.

GET/trees/{publicationId}

The published tree, with its people and links.

GET/trees/{publicationId}/version

Just { version, changed_at }. The cheap way to poll.

GET/trees/{publicationId}/people/{personId}

One person, with their parents, partners, children and siblings.

GET/media/{publicationId}/{personId}

A published portrait. No key is needed. It works only while the tree is published and photos are on. The photo URLs point here.

The tree comes back in this shape.

{
  "publication": {
    "id", "title", "scope", "root_person_id",
    "version", "changed_at"
  },
  "people": [ ... ],
  "parent_child": [
    { "parent_id", "child_id", "type", "certainty" }
  ],
  "partnerships": [
    { "partner_a", "partner_b", "type", "status", "certainty" }
  ]
}

One person comes back in this shape.

{ "publication", "person", "parents", "partners", "children", "siblings" }

People and links

A person takes one of three shapes.

Someone who has died

{
  "id", "name", "preferred_name", "gender",
  "living": false,
  "profile": "full",
  "birth": { "date", "precision", "status" } | null,
  "death": { "date", "precision", "status" },
  "bio"?,
  "photo"
}

A living person, full profile

{
  "id", "name", "preferred_name", "gender",
  "living": true,
  "profile": "full",
  "birth": { "year", "status" } | null,
  "bio"?,
  "photo"
}

A living person, limited profile

{
  "id", "name",
  "living": true,
  "profile": "limited",
  "photo"
}

photo is a URL or null.

Uncertainty is part of the data. Every certainty and status is one of confirmed, unconfirmed, estimated, disputed, family_tradition or unknown. Please show it. Don’t present an unconfirmed date as fact.

Authentication

From a server. Send the server key as a bearer token.

Authorization: Bearer rb_sk_YOUR_SERVER_KEY

From a browser. Add the website key to the URL as ?key=rb_pk_.... The request must come from a listed website. We check the Origin header, and answer with CORS for that website only.

Caching and freshness

  • The ETag is the tree’s version. Send it back as If-None-Match. If nothing changed, you get 304 Not Modified.
  • Answers to a website key can be cached publicly for 60 seconds.
  • Answers to a server key are private.
curl -i https://rootbound.aristhegf.workers.dev/api/v1/trees/YOUR_PUBLICATION_ID \
  -H "Authorization: Bearer rb_sk_YOUR_SERVER_KEY" \
  -H 'If-None-Match: "THE_ETAG_YOU_HAVE"'

There are no webhooks yet. To keep a copy fresh, poll /version once a minute. Fetch the tree again only when the version changes.

Errors

Every error has the same shape.

{ "error": { "code": "invalid_key", "message": "..." } }
CodeStatusMeaning
bad_request400The request was not well formed.
missing_key401No key was sent.
invalid_key401The key is wrong, revoked, or for another tree.
origin_not_allowed403This website is not on the key’s list.
not_published404The tree is not published.
not_found404No such person or path.
quota_exceeded429The family’s monthly request allowance is used up.
server_error500Something failed on our side.
media_unavailable503The portrait could not be served right now.

Limits

The free plan is the only plan today. It allows:

  • 3 publications per family
  • 100,000 requests a month
  • 5 websites per key

Every request counts, including 304 answers.

Examples

Fetch the tree with curl

curl https://rootbound.aristhegf.workers.dev/api/v1/trees/YOUR_PUBLICATION_ID \
  -H "Authorization: Bearer rb_sk_YOUR_SERVER_KEY"

Keep a copy fresh in Node

This checks /version once a minute. It fetches the whole tree only when something changed.

// Node 18 or later. Keep the server key on the server.
const BASE = 'https://rootbound.aristhegf.workers.dev/api/v1'
const PUB = 'YOUR_PUBLICATION_ID'
const headers = { Authorization: 'Bearer ' + process.env.ROOTBOUND_SERVER_KEY }

let version = null
let tree = null

async function refresh() {
  const res = await fetch(`${BASE}/trees/${PUB}/version`, { headers })
  if (!res.ok) {
    const { error } = await res.json()
    console.error(error.code, error.message)
    return
  }
  const latest = await res.json()
  if (latest.version === version) return

  const treeRes = await fetch(`${BASE}/trees/${PUB}`, { headers })
  if (!treeRes.ok) return
  tree = await treeRes.json()
  version = tree.publication.version
  console.log('Tree updated', latest.changed_at, tree.people.length, 'people')
}

refresh()
setInterval(refresh, 60_000)