For platforms with members who need to stay tax-compliant
One API call opens a Tally space for your member.
Tally helps side hustlers stay on top of tax. Partner with us and every one of your members gets a branded Tally account created with a single request — they receive a magic-link email from you and land in a space that tracks their earnings and shows exactly what to set aside. It stays free for life. When they upgrade to Pro for personal spaces, docs and automated tax buffers, you earn 35% for life.
https://tally.ac/api/public/partner/v1Version: v1 (stable)Auth: Bearer API keyFree to integrateQuickstart
Provision your first member in five minutes
- 1Sign in to the partner portalHead to the portal, fill in your company details, and accept the partner agreement. Verify your domain (TXT record), create a space template, mint an API key. All of this is guided inline — no separate docs to follow.
- 2Provision a test memberRun the cURL below with your own email. You'll receive the magic-link welcome.
curl -X POST https://tally.ac/api/public/partner/v1/users \
-H 'Authorization: Bearer tp_<YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"email": "you@example.com",
"external_user_id": "cust_test_1",
"space_template": "default"
}'Response contains user_id, space_id, connection_id, and (only on first mint) a connection_secret you'll use to bulk-push entries on their behalf.
Reference
POST /users — provision a member
Given an email + your stable identifier + a template slug, we ensure a Tally user exists, provision a branded space owned by them, and return the ids you'll need if you later want to push entries.
Request body
| Field | Type | Description |
|---|---|---|
| string (email) | The member's email. We create or match their Tally account by this address. | |
| external_user_id | string, ≤ 200 | Your stable id for them. Used as the idempotency key — repeat calls with the same value return the same space. |
| space_template | string (slug) | The template you defined in the portal. Omit to fall back to the seeded default template. |
Successful response (201)
{
"user_id": "d34a…",
"user_was_new": true,
"space_id": "9f2c…",
"space_was_new": true,
"space_template": "default",
"connection_id": "b12e…",
"connection_secret": "tc_… (only on first mint — store it)"
}Full error envelope in the error reference.
Reference
POST /entries/bulk — push spends and earns
Optional. Enrich the member's ledger with data your platform already has: payouts, order totals, subscription charges, refunds. Send up to 500 entries per call. Each entry dedupes on (connection_id, external_id), so retries are safe and duplicates come back as results[].status = "duplicate" inside a 200 response.
curl -X POST https://tally.ac/api/public/partner/v1/entries/bulk \
-H 'Authorization: Bearer tp_<YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"connection_id": "b12e…",
"connection_secret": "tc_…",
"entries": [
{
"kind": "earn",
"amount_cents": 4200,
"occurred_on": "2026-07-09",
"note": "July payout",
"external_id": "acme:payout:2026-07:abc123"
}
]
}'Historical occurred_on dates are accepted — backfill your member's history freely.
Reference
GET /health — unauthenticated liveness check
Returns { "ok": true, "ts": "…" }. Use it from your status page or uptime monitor. No auth required.
Reference
Authentication
Every write request to /api/public/partner/v1/* requires your partner API key in the Authorization header. Never send the key from a browser — it is a server-to-server credential.
Authorization: Bearer tp_<64 hex chars> Content-Type: application/json
Reference
Errors
Every non-2xx response uses the same envelope with a stable error.code, human message, recommended fix, and a request_id. The full catalog, retry rules, and response shape live in the error reference.
Reference
Rate limits
Bulk-entry writes are limited to 60 requests/minute per partner (each request may carry up to 500 entries). Provisioning has its own per-partner limit — contact support to raise it for bursty onboardings. Over the limit you get a 429 with retry_after_seconds in the error envelope.
Lifecycle
Re-provisioning is safe
POST /users is idempotent on (partner_id, external_user_id). Call it every time your member signs in if that's simpler than tracking lifecycle state on your side — we'll return the same space_id and connection_id and won't spam them with duplicate welcome emails. The connection_secret is only populated on the first call; if you lose it, revoke and re-provision from the portal — we only store the hash.
Lifecycle
Revoking a connection
When a member leaves your platform, revoke the connection from the portal. This stops future entry writes but keeps the member's data inside their Tally space — the account is theirs. Revoking does not revoke your revenue-share attribution. Once earned, always earned.
Lifecycle
Handling churned members
We recommend keeping the connection active and simply stopping your entry writes when a member churns — they might reactivate, or you might launch a re-engagement flow. Leaving a connection dormant costs nothing.
Operations
Versioning
The API is versioned in the URL (/v1/). Breaking changes ship as /v2/ alongside a minimum 6-month deprecation window for v1. Additive changes (new optional fields, new endpoints) can land in v1 without a version bump. Renamed or removed fields never do.
Operations
Status & support
We commit to 99.5% best-effort uptime on partner endpoints. Incidents are posted at status.tally.ac. For anything else, email partners@tally.ac — include your partner slug and, if relevant, the request_id from a failing response. We reply within one business day.
Legal