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.
- API Token. A long code that the other service sends with each request. You choose what it may do: Read Only, Read And Count, or Full Control, which also creates, renames, moves and deletes tallies and folders.
- Feed Link. A web address with the code inside it, which returns your tallies and totals as CSV or JSON. It is always read-only. It is for a spreadsheet, a dashboard, or anything that can only fetch an address.
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.
- It opens only what the connection covers, and only while it answers. Nothing is kept open between requests.
- Nothing a connection reads or writes is written to the service's logs. A log line holds the kind of request, whether it worked and a request number.
- The service you connected receives readable data. What it does with it is up to that service, and outside this product.
- There is still no administrator function that decrypts content. A connection is yours: the people who run the service do not create or use one.
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
- It is shown once, when you create it. The service keeps only a one-way fingerprint of it and is not able to show it again.
- Whoever has it can do what the connection allows, until you revoke it. A connection has no expiry.
- A feed link carries its code in the address, so it is kept by whatever you put it into, and by anyone who can see it there. That is why a feed link can only read.
- Give each service its own connection, with the least access it needs and only the tallies it needs.
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
| Request | Needs | What It Does |
|---|---|---|
GET /v1/connect | Read | What this token may do, and whether it covers everything or a chosen list. |
GET /v1/connect/tallies | Read | The 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/:id | Read | One tally. |
GET /v1/connect/tallies/:id/events | Read | Its history, oldest first, in pages (?after and ?limit, up to 1,000 a page). |
GET /v1/connect/folders | Read | The folders it covers. |
GET /v1/connect/changes | Read | What changed or was deleted since a cursor (?after and ?limit): identifiers only. |
POST /v1/connect/tallies/:id/events | Count | Add a count: increment, decrement, correct, set or undo. |
POST /v1/connect/tallies | Full | Create a tally. |
PATCH /v1/connect/tallies/:id | Full | Rename, edit, archive, pin or move a tally. |
DELETE /v1/connect/tallies/:id | Full | Delete a tally, as deleting it in the app does. |
POST /v1/connect/folders | Full | Create a folder. |
PATCH /v1/connect/folders/:id | Full | Rename or move a folder. |
DELETE /v1/connect/folders/:id | Full | Delete a folder, only when it is empty. |
GET /v1/feed/LINK_CODE/tallies.csv | Feed Link | The covered tallies and totals as CSV. No header needed: the code is in the address. |
GET /v1/feed/LINK_CODE/tallies.json | Feed Link | The 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:
- List the tallies once, and keep the
cursorfrom the reply. - Every minute or so, ask for changes after that cursor.
- For each change, fetch that tally again, or drop it if it says
deletedor the fetch answers 404. - Keep
next_afteras your new cursor. Ifhas_moreis 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
- An API token: 120 requests a minute.
- A feed link: 20 requests a minute.
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
}
| Status | What It Means |
|---|---|
| 400 | The request does not parse. The reply names the field. |
| 401 | The token or link is missing, wrong or revoked. One answer for all three. |
| 403 | The 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. |
| 404 | No such tally or folder, or it is not covered by this connection, or it is private. One answer for all three. |
| 409 | The tally or folder changed since the version you named, or the folder is not empty. |
| 422 | The tally has more than 20,000 entries, so it has no total here and takes no counts through a connection. |
| 429 | Too many requests. Wait the number of seconds in the Retry-After header. |
| 503 | A fault on our side. Safe to try again. |
What a Connection Cannot Do
- See or change anything private.
- See your display name, your themes, your account details or another account's tallies.
- Change a tally's goal, schedule, timer, calculation or color, make something private, or bring back something deleted.