Examples

Each example needs an API key. They read it from an environment variable, so it never ends up in your code:

export TROVEMARKS_KEY=tm_…

A tiny shell function. Put it in your ~/.zshrc or ~/.bashrc, then run save https://example.com/article reading.

save() {
  url="$1"; shift
  tags=$(printf '"%s",' "$@"); tags="[${tags%,}]"
  curl -s https://trovemarks.com/api/v1/bookmarks \
    -H "Authorization: Bearer $TROVEMARKS_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"url\": \"$url\", \"tags\": $tags}" | jq -r '.bookmark.title'
}

Turn a collection into a newsletter section

Many curators collect links all week, then write them up. This script prints the last week’s links from one collection as Markdown, with your notes, ready to paste into your newsletter.

// weekly.mjs: node weekly.mjs "Weekly picks"
const API = 'https://trovemarks.com/api/v1'
const headers = { Authorization: `Bearer ${process.env.TROVEMARKS_KEY}` }
const get = async (path) => {
  const res = await fetch(`${API}${path}`, { headers })
  if (!res.ok) throw new Error((await res.json()).error.message)
  return res.json()
}

const name = process.argv[2] ?? 'Weekly picks'
const { data: collections } = await get('/collections?limit=500')
const collection = collections.find((c) => c.title.toLowerCase() === name.toLowerCase())
if (!collection) throw new Error(`No collection called ${name}`)

const since = new Date(Date.now() - 7 * 864e5).toISOString()
let cursor = ''
const links = []
do {
  const page = await get(
    `/bookmarks?collection=${collection.id}&saved_after=${since}&limit=100${cursor && `&cursor=${cursor}`}`,
  )
  links.push(...page.data)
  cursor = page.next_cursor
} while (cursor)

for (const link of links.reverse()) {
  console.log(`- [${link.title}](${link.url})${link.note ? ` — ${link.note}` : ''}`)
}

Prefer not to write code? Every public collection has an RSS feed, and most newsletter tools can turn a feed into a section of your email.

Save every link in a text file, one per line, into a collection. Python, with nothing to install:

# save_all.py: python3 save_all.py links.txt "Research"
import json, os, sys, time, urllib.request

API = "https://trovemarks.com/api/v1/bookmarks"
KEY = os.environ["TROVEMARKS_KEY"]
path, collection = sys.argv[1], sys.argv[2]

for line in open(path):
    url = line.strip()
    if not url:
        continue
    body = json.dumps({"url": url, "collection_names": [collection]}).encode()
    request = urllib.request.Request(API, data=body, headers={
        "Authorization": f"Bearer {KEY}",
        "Content-Type": "application/json",
    })
    with urllib.request.urlopen(request) as response:
        print(response.status, url)  # 201 saved, 200 already there
    time.sleep(0.25)  # well inside the rate limit

For thousands of links, an import file is faster.

One request can change up to 10,000 links that match a filter. This makes every link from one site public:

curl https://trovemarks.com/api/v1/bookmarks/bulk \
  -H "Authorization: Bearer $TROVEMARKS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filter": {"domain": "example.com"}, "action": {"type": "visibility", "private": false}}'

Check what a filter matches first with POST /bookmarks/bulk/summary, which takes the same body without action.

Zapier, Make and n8n

Use their HTTP or webhook step to call the API. For example, to save every link you star in your feed reader, or every link posted in a Slack channel:

Field Value
Method POST
URL https://trovemarks.com/api/v1/bookmarks
Headers Authorization: Bearer tm_… and Content-Type: application/json
Body {"url": "<the link from the trigger>", "tags": ["slack"]}

To go the other way, from Trovemarks into another tool, use a public collection’s RSS feed as the trigger.

Apple Shortcuts

The iPhone shortcut is a good starting point for your own: it’s a single Get Contents of URL action that posts to /api/v1/bookmarks with your key. Duplicate it and change the body to add tags, a collection or a note.