Connect Other Services

Optional. An API token or a feed link lets something outside the app read your tallies, add counts, or manage them. Here is what that means, and how to use it.

What a Connection Is

A connection is something you create in the app, under Settings, Connections, so that another service can use tallies you choose: a spreadsheet that shows your totals, an automation service that adds a count when something happens, a home automation hub, or your own script. You do not need one. Until you create one, nothing on this page applies to your account.

There are two kinds.

Each connection covers either everything that is not private, including what you add later, or a list of tallies and folders that you choose. A folder covers what is in it, including what you put there later. An account can have up to 25 connections.

What the Service Does When a Connection Is Used

Your tallies are stored encrypted, and for tallies that are not private the service holds the key. With no connection, nothing in the service opens your tallies.

When a request arrives with a connection's token or link, the service checks it, opens your account's key for that one request, decrypts the tallies and folders that connection covers, and sends them in readable form to whoever made the request. The reply is encrypted in transit, like all traffic to the service. A token with more access can also write: the service encrypts the new count or the new name the same way the app does, and your devices pick it up like any other change.

Private Items Are Never Included

A tally or folder you mark private is locked with your private passphrase, which never leaves your devices, so the service has nothing that opens it. A connection cannot list a private item, count it or learn that it exists, even a connection that covers everything. Private items do not appear in the list when you choose what a connection covers, and a tally you make private later drops out of every connection.

Treat a Token or Link Like a Password

How to Revoke

In the app, open Settings, then Connections. Each connection is listed with its name, its access, what it covers, when it was created and the last day it was used. Choose Revoke beside the one you want to stop. It stops working right away for whatever was using it, and it is not possible to undo: to connect that service again, create a new connection.

Revoke a connection when you stop using the service it was for, when you are not sure where its token or link has been, or when the last day it was used is one you did not expect. The app shows the last day of use, not each request.

Changes a connection makes are signed by a Connections device, listed under Settings, Devices. Revoking that device stops every change through every connection of your account; reading goes on. To stop a connection completely, revoke the connection itself.

Example: Totals in a Spreadsheet

Create a feed link that covers the tallies you want, and copy its CSV address. In a spreadsheet that can import data from an address, put this in a cell, with your own link in place of the sample:

=IMPORTDATA("https://api.tallyvaultpro.app/v1/feed/tvf_YOUR_LINK_CODE/tallies.csv")

The sheet fills with one row for each tally:

id,name,emoji,total,unit,folder,tags,archived,updated_at
0199c2f1-7a3e-7c11-9d42-5b1e0c6a2f10,Coffees,☕,7,cups,Habits,morning,false,2026-10-11T08:14:02.000Z
0199c2f1-9b10-7e55-8a01-3c7d4e9f6b22,Laps,🏊,42,,Sport,,false,2026-10-10T17:40:51.000Z

The link is now stored in that spreadsheet, and anyone who can see the formula there has it. A tally name that begins with an equals sign, a plus, a minus or an at sign arrives marked as text, so the spreadsheet does not run it as a formula.

API Reference

All addresses begin with https://api.tallyvaultpro.app. Requests and replies are JSON, except the CSV feed. Totals and amounts are text, such as "2.5", so nothing is lost to rounding. Every reply asks not to be cached.

Authentication

Send the token in a header with every request. A token begins with tvp_. In the examples on this page, $TOKEN stands for yours.

Authorization: Bearer $TOKEN

A feed link needs no header: its code, which begins with tvf_, is part of the address. Call the API from a server, a script or an automation service. A script in a web page on another site can send a request but the browser will not let it see the reply.

Routes

RequestNeedsWhat It Does
GET /v1/connectReadWhat this token may do, and whether it covers everything or a chosen list.
GET /v1/connect/talliesReadThe tallies it covers: name, emoji, unit, step, tags, note, total, and a cursor for asking what changed. Add ?totals=false to leave the totals out, which is faster.
GET /v1/connect/tallies/:idReadOne tally.
GET /v1/connect/tallies/:id/eventsReadIts history, oldest first, in pages (?after and ?limit, up to 1,000 a page).
GET /v1/connect/foldersReadThe folders it covers.
GET /v1/connect/changesReadWhat changed or was deleted since a cursor (?after and ?limit): identifiers only.
POST /v1/connect/tallies/:id/eventsCountAdd a count: increment, decrement, correct, set or undo.
POST /v1/connect/talliesFullCreate a tally.
PATCH /v1/connect/tallies/:idFullRename, edit, archive, pin or move a tally.
DELETE /v1/connect/tallies/:idFullDelete a tally, as deleting it in the app does.
POST /v1/connect/foldersFullCreate a folder.
PATCH /v1/connect/folders/:idFullRename or move a folder.
DELETE /v1/connect/folders/:idFullDelete a folder, only when it is empty.
GET /v1/feed/LINK_CODE/tallies.csvFeed LinkThe covered tallies and totals as CSV. No header needed: the code is in the address.
GET /v1/feed/LINK_CODE/tallies.jsonFeed LinkThe same rows as JSON.

Read And Count includes Read, and Full Control includes both. A new tally or folder with no parent goes to the top of your library, which only a connection that covers everything may add to; a connection with a chosen list creates inside a folder it covers.

Example: List Tallies

curl -H "Authorization: Bearer $TOKEN" \
  https://api.tallyvaultpro.app/v1/connect/tallies
{
  "tallies": [
    {
      "id": "0199c2f1-7a3e-7c11-9d42-5b1e0c6a2f10",
      "name": "Coffees",
      "emoji": "☕",
      "unit": "cups",
      "step": "1",
      "tags": ["morning"],
      "note": null,
      "archived": false,
      "pinned": false,
      "folder_id": "0199c2f0-11aa-7b02-a6c3-9e2d1f4b7c33",
      "total": "7",
      "events": 9,
      "sequence": 9,
      "version": 2,
      "created_at": "2026-09-30T07:02:11.000Z",
      "updated_at": "2026-10-11T08:14:02.000Z"
    }
  ],
  "cursor": 418
}

Some fields are left out of the samples on this page. A total is empty (null) for a tally with more than 20,000 entries. A calculated tally's total here is the sum of its own entries.

Example: Add a Count

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: coffee-2026-10-11-0814" \
  -d '{"action":"increment"}' \
  https://api.tallyvaultpro.app/v1/connect/tallies/0199c2f1-7a3e-7c11-9d42-5b1e0c6a2f10/events
{
  "event": {
    "id": "0199c9a4-51c0-7d3e-b1f2-6a7c8d9e0f11",
    "sequence": 10,
    "kind": "increment",
    "amount": "1",
    "undone": false,
    "origin": "widget",
    "occurred_at": "2026-10-11T08:14:02.000Z"
  },
  "tally": { "id": "0199c2f1-7a3e-7c11-9d42-5b1e0c6a2f10", "total": "8", "events": 10, "sequence": 10 },
  "replayed": false
}

The body is one of these. Leave amount out of an increment or a decrement and the tally's own step is used.

{ "action": "increment", "amount": "1" }
{ "action": "decrement", "amount": "2.5" }
{ "action": "correct", "amount": "-3" }
{ "action": "set", "to": "40" }
{ "action": "undo", "undoes": "EVENT_ID" }

Send an Idempotency-Key header that is different for each thing you count. If the same request arrives again with the same key within a day, the count is recorded once and the second reply says "replayed": true. Without a key, sending twice counts twice.

Staying in Sync

The service does not call you when something changes. Ask instead:

  1. List the tallies once, and keep the cursor from the reply.
  2. Every minute or so, ask for changes after that cursor.
  3. For each change, fetch that tally again, or drop it if it says deleted or the fetch answers 404.
  4. Keep next_after as your new cursor. If has_more is true, ask again at once.
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.tallyvaultpro.app/v1/connect/changes?after=418"
{
  "changes": [
    { "seq": 421, "type": "tally", "id": "0199c2f1-7a3e-7c11-9d42-5b1e0c6a2f10", "change": "changed", "at": "2026-10-11T08:14:02.000Z" },
    { "seq": 425, "type": "tally", "id": "0199c2f1-9b10-7e55-8a01-3c7d4e9f6b22", "change": "deleted", "at": "2026-10-11T09:30:40.000Z" }
  ],
  "next_after": 425,
  "has_more": false
}

A tally that leaves a connection's reach, because it was made private or moved out of a covered folder, is not listed as a change: it stops appearing. Listing everything again now and then catches that.

Webhooks, where the service would notify yours, are planned and not available yet.

Rate Limits

Past the limit the reply is 429, with a Retry-After header that says how many seconds to wait.

Errors

An error is a status and a small JSON body with a fixed code and message, never anything from your tallies.

{
  "code": "RATE_LIMITED",
  "message": "Too many requests. Try again shortly.",
  "request_id": "REQUEST_ID",
  "retryable": true
}
StatusWhat It Means
400The request does not parse. The reply names the field.
401The token or link is missing, wrong or revoked. One answer for all three.
403The token is real but may not do this: its access level is too low, the place is outside what it covers, or the Connections device was revoked. The reply gives a reason.
404No such tally or folder, or it is not covered by this connection, or it is private. One answer for all three.
409The tally or folder changed since the version you named, or the folder is not empty.
422The tally has more than 20,000 entries, so it has no total here and takes no counts through a connection.
429Too many requests. Wait the number of seconds in the Retry-After header.
503A fault on our side. Safe to try again.

What a Connection Cannot Do

Open the App Read the Security Model