Account Terms
Revision 2026-09-07 (terms-pack v1.3). Effective on publication. Supersedes revision 2026-08-31.
These terms cover the Terakota Portal at app.terakota.io — including the control panel it serves to entitled members and the control-plane API at app.terakota.io/api/v1 that the terakota binary calls after terakota login (from terakota v1.8.0) — and the connect service at oauth.terakota.io, operated by Bilans Solutions LLC ("we", "us"). They govern your account, your use of the Portal and the control panel, and any vendor connection you make through the connect service. Questions: contact@bilans.io.
The terakota and verify-receipts binaries are governed by their own agreement, the terakota End User License Agreement at terakota.io/terms. That agreement governs the Software; these terms govern your account, the connect service, and the control panel. Where a claim concerns the account, the connect service, or the control panel, these terms control.
1. Accounts
1.1 Signing up is free and open: you create your own account at app.terakota.io. Having an account is not the same as having access — what you can see and do inside the Portal is set by operator-granted entitlements (Section 2), and a new account starts with none.
1.2 Authentication runs through Auth0. Auth0 holds your email and credentials. We do not store your password. Our own store keeps your account email, your Auth0 subject identifier, digests of session tokens (never the raw tokens), your workspace memberships and entitlements (including whether the control panel is switched on for your account — an operator-set flag; setting or clearing it is an audited grant event), the version of these terms you accepted and when you accepted it, and an append-only audit log of account, grant, and login events.
1.3 If you connect a production vendor account through the connect service (Section 4), we additionally store a connection record and, while a connection attempt is in flight, a short-lived attempt row.
Connection record — the complete list. For a production QuickBooks connection made through our connect service, we store exactly these eleven fields and nothing else:
- portal account id
- connection id
- provider (which vendor the connection is for)
- device-key thumbprint
- client id
- keyed HMAC of the normalized realm id
- status
- scope
- created, last-refresh and revocation timestamps
- token-generation HMAC
- revocation reason
Three things are deliberately absent: no raw realm id, no company name, no token material. This is a closed set, not a starting point — adding a field requires amending the architecture decision that fixes it, and the published notices change first.
1.4 Connection attempts ("flights") are single-use rows that expire on a short timer (10 minutes by default). They record which vendor the attempt is for, the state of the attempt, a verifier encrypted at rest, the two public keys your install registered for that one attempt, and the loopback address on your machine the result returns to. A flight never holds an authorization code and never holds a token. Minting one requires a signed-in session.
1.5 Acceptance of these terms is recorded per account, with the version accepted, when your account is created or at your next sign-in. Your account is subject to the current version of these terms.
1.6 Keep your login credentials secure. Tell us at contact@bilans.io if you suspect unauthorized access; we can revoke sessions.
2. Entitlements
2.1 What you can see and do in the Portal is set by operator-granted entitlements. We grant, change, or remove them. You do not self-provision access to workspaces or data.
2.2 The control panel (Section 4a) is such an entitlement: an operator switches it on per account, for members of a hosted tenant. It is not switched on for anyone but the operator's own account until we open it to other accounts (Section 4a.6). Removing it closes the panel and the binary's control-plane commands to you; it does not undo routing changes you already made.
3. Data custody
3.1 Terakota does not hold your business data. Your business data lives in your own database (bring-your-own-database). We connect read-only, per your grant, and keep only delivery state and receipts metadata.
3.2 For connect-service connections we hold connection metadata only — the closed set in Section 1.3 — and never your vendor tokens. Token material transits the connect service and is delivered to your machine sealed to a key only that machine holds; it then lives on your machine, not ours. There is no plaintext vendor token and no token we could decrypt at rest anywhere in our systems.
3.3 The accurate way to state this: your data at rest stays in your database; payloads transit our compute as service-provider processing. We do not claim data "never leaves your environment," because during processing it passes through our compute.
3.4 Receipts we produce are tamper-evident — built so later changes are detectable. They are not "court-ready," "guaranteed," or "tamper-proof."
3.5 The control panel shows and changes a tenant's delivery routing — which topics exist, which subscriptions route them and to which named destination, queue counts, held and dead-lettered deliveries, and an index of delivered events (sequence, topic, entity id, event id, times). None of that is an event's content: the index has no payload column, a held delivery's body never reaches the panel (a replay you request is performed by our delivery daemon itself, on the same path a live delivery takes), and dead-letter error text is shown with destination addresses masked. Every change is recorded in an append-only audit row — your account id, the tenant, the action, and digests of the routing before and after — and other members of the tenant can see on the panel that a member account made it (the action, the time and the digest — not which account).
3.6 Deliveries to our own event index produce no receipt of yours. The index is ours, not a destination of yours; receipts on a tenant's chain record deliveries to the destinations you configured.
4. The connect service
4.1 What it is. The connect service lets you authorize a production vendor account — QuickBooks Online first — for use by the terakota binary on your own machine, from terakota v1.4.0. It exists because production OAuth at these vendors requires an HTTPS callback and a client secret that a downloadable binary cannot carry.
4.2 How a connection works. The Portal mints a single-use, short-lived flight; your browser goes to the vendor's consent screen, which shows our registered application; the vendor returns to our broker at oauth.terakota.io; the broker performs the code-for-token exchange server-side with our client secret; and the tokens come back to your machine as a capsule encrypted to a key only that install holds, signed by us and bound to that one attempt. During the connect ceremony your install registers a per-install device key. That device key is then required, together with the current rotated refresh token, for every token renewal and for revocation.
4.3 It is not a data plane. Your vendor business data never traverses the connect service. Reads run from your machine to the vendor directly. The service never proxies a vendor data API, never accepts customer-authored logic, and is not an agent or MCP transport.
4.4 It is a runtime dependency, and here is what that means. Data already cached on your machine stays usable offline, and an unexpired access token keeps working without us. But the initial authorization, every token renewal, and revocation require the service. Renewal runs automatically during normal use — the access token and its expiry are stored sealed in your install's local keystore beside the refresh token, and the software renews when the token nears expiry. (Intuit's access tokens last about an hour, so in active use renewal is roughly hourly.) If the service is unavailable, fresh production reads stall once the access token expires; if it is unavailable for longer than the refresh token's lifetime, you have to re-consent. AppFolio and all local operation are unaffected.
4.5 We may cut refresh. For abuse of our shared vendor application, for a security reason, on account suspension, or under an emergency service-wide disable, we may stop issuing token renewals for a connection or an account, and we may attempt an upstream revocation with the vendor. Cutting refresh is our abuse control, and it is effective within one access-token lifetime. An access token already issued to you remains usable until it expires — a cut is fast, not instantaneous. We aim to give notice where practical, but may act first where security requires it.
4.6 An account is required only for connections that traverse our registered vendor application. AppFolio, local reconciliation, receipts, verify-receipts, and sandbox connections made under your own registered vendor application need no account and are not governed by this section. Extending an account requirement to any of those surfaces would be a change to these terms, published first.
4.7 The connect route is not open to third parties today. It is enabled per account, and only after two things are done: the independent adversarial review recorded in the terakota Security Advisory & Support Policy §5, and — before we serve the first real customer — counsel brief questions Q2 and Q4 answered in writing together with the Fly.io and Auth0/Okta data-processing posture confirmed in writing.
4a. The control panel
4a.1 What it is. For a hosted tenant we operate, a member whose account an operator has switched on can see and change that tenant's delivery routing: in the browser, on the Portal's platform pages; and, from terakota v1.8.0, read it through the terakota binary on their own machine — and change it from the release that ships the binary's change commands — after terakota login (sign-in through our sign-in host, in your browser) and terakota link (one local company bound to one hosted tenant, after a live check that you are a member).
4a.2 What you can do. Add or remove a subscription (a topic routed to a named destination on a queue or handler binding — a queue named for the first time is created for the tenant by that subscription), request that a held delivery be replayed, and run a catch-all replay. What you cannot do here: create a tenant, mint or rotate an ingest token, register a webhook destination, or set or read a destination's address or secret — those stay with the operator. Registering or deleting a topic is operator-only for now; the page says so.
4a.3 What the binary sends and receives. A control-plane call carries your sign-in token, the linked tenant, the command, and that command's own inputs — never a vendor credential, a query, a result, a receipt, or your local company id. It receives our delivery metadata for the tenant and never an event's content. events-tail polls the delivery-event index every few seconds for as long as you leave it running; each poll is one call and is recorded like one. The Software's own agreement (the EULA, Section 4) lists every command by name.
The control panel — what we record (from portal revision 2026-09-07; from terakota v1.8.0 for the binary). Every change made to a tenant's delivery routing through the panel (and, from the release that ships the binary's change commands, through the binary) — a subscription added or removed, a held delivery replayed, a catch-all replay, and — by an operator, for now — a topic registered or deleted — writes one append-only row in our engine store: when it happened, which account (your account id — an internal identifier, not your email), which tenant, which action, a digest of the routing before and after, and the database login the change ran under. No event content, no inputs beyond the action itself, and — for the binary — never the --intent text you typed. From terakota v1.8.0, each control-plane read and each events-tail poll is recorded too, but separately and more briefly: one line in a read log in our control store — your account id, the tenant, which read, and the time, with no inputs and no results — and nothing at all for the command that only asks who you are signed in as. If a read's line cannot be written, the read still completes and the failure is noted in our application log with the tenant, the command and the kind of failure — never your account id. Like every request to the Portal and its API, a control-plane call also leaves one line in that application log — the route, the outcome, the timing and your account id, with no inputs and no bodies — which lives with our host, Fly, for a bounded period. While a tail runs that is one line every few seconds, which is a record of when your machine was polling. We delete read-log lines older than 90 days, and closing your account deletes yours in the same step that clears your email and display name. The change rows above are different: they are append-only and have no automatic expiry today. For each event delivered on a tenant's hosted spine we also keep one index row — its sequence, topic, entity id, event id, the delivery's message id, and when it was received and delivered; the table has no payload column, so it cannot hold an event's content, and rows older than 90 days are removed on the operator's retention run. Neither the panel nor the binary can see an ingest token, a quarantined delivery's body or signature, a dead letter's payload, or a destination's address or secret; dead-letter error text is shown with addresses masked. Other members of the same tenant can see, on the panel's audit view, that a member account made a change — the action, the time and the digest, not which account.
4a.4 Your sign-in tokens. terakota login obtains an access token that expires within an hour and a refresh token that rotates on every use, both stored only on your machine; we store neither and mint no session for the binary. terakota logout deletes both and asks our sign-in host to revoke the refresh token (if that host cannot be reached, the local deletion still happens and the refresh token runs out on its own clock). Presenting an already-rotated refresh token again — outside a ten-second window that absorbs a retried request — revokes the whole family; a refresh token also expires 90 days after sign-in or after 30 days unused. Keep them as you keep any credential: with them, someone can see the routing of the tenants you belong to — and change it from the release that ships the binary's change commands.
4a.5 If we switch the panel off, or the control plane is down. Removing the entitlement, suspending the account, or a terms change you have not yet accepted closes the panel and refuses the binary's control-plane commands with a typed error; the binary sends you to the browser where a new acceptance is needed. Routing you already set stays as it is until an operator or another member changes it — closing the panel never re-routes a tenant's deliveries. If the control plane cannot be reached, the control-plane commands fail and nothing else in the binary is affected.
4a.6 Not open to third parties today. The control panel is switched on for the operator's own account only, until we open it to other accounts. It is not a data plane: it carries routing and delivery metadata for tenants whose events are, today, synthetic (Section 5); a real customer source on a hosted tenant is governed by a separate decision and agreement, never by this section.
5. Synthetic demo data
5.1 Workspace data in the Portal is synthetic demo data. It is not real customer business data. Do not enter real personal, financial, or confidential data into the demo workspaces.
5.2 The connect service in Section 4 is the exception, and it is not demo. Connections made through it are real: a real account, a real vendor authorization, a real realm identifier held as a keyed HMAC, and real production token material in transit. Treat a production connection as production, because it is one.
5.3 The control panel is not demo either: the routing you see and change there is the real routing of the hosted tenant you are a member of, even while every event flowing through it is synthetic. The panel takes only names of things that already exist (topics, destinations) and ids of held deliveries; it has no field for anything else, and the rule in 5.1 stands for whatever you might type.
6. The pilot path (real business data)
6.1 Real customer business data enters the Portal only under a future per-pilot arrangement: a signed pilot agreement, a data-access mandate, and a data processing agreement (DPA). No real business data is connected before those are in place.
6.2 Connecting a production vendor account through the connect service is not "real business data entering the Portal" and does not require the pilot documents. Credential material transits; business data does not, and reads run machine-to-vendor directly (Section 4.3). The pilot fence in 6.1 is about business data, and it is unchanged.
6.3 Those pilot documents are separate from these terms and are not drafted here. Until they exist and are signed, treat Portal workspaces as demo-only.
7. Acceptable use
7.1 Use the Portal only for its intended purpose and only within your granted entitlements. Do not probe, overload, or reverse-engineer it, and do not use it to break any law or any third party's rights.
7.2 Connect only vendor accounts you are authorized to connect, and only for your own use. Do not use the connect service to obtain credentials for anyone else's vendor account.
8. Suspension and termination
8.1 We may suspend or terminate an account for breach of these terms, for security reasons, or when a business relationship ends. We aim to give notice where practical, but may act first where security requires it.
8.2 Suspension takes effect immediately on new connection attempts and on token renewals: no new flight is minted and no refresh is issued. If a suspended connection later presents a token to us, we attempt an upstream revocation with the vendor before rejecting it. As in Section 4.5, an access token already issued remains usable until it expires. Suspension also closes the control panel and refuses the binary's control-plane calls on the next request; routing you already set stays in place (Section 4a.5).
8.3 You may ask us to close your account at any time by emailing contact@bilans.io. There is no self-serve close button: closure is a sequence an operator runs (Section 9).
9. Offboarding and erasure
9.1 Closure runs on the operator offboarding path, and it completes in two steps. When you ask, we cut your access first — your memberships and active sessions go, and a control-plane access token already issued to the binary opens nothing from that moment, because every control-plane call checks your membership live (it stays a valid token until it expires, within an hour) — and the same day we clear your identifying data: your Auth0 user and your sign-in identity are deleted, and your email address, display name, accepted-terms record and verified-email flag are cleared from your Portal control-store record and the connect and control-panel entitlements are withdrawn. From that day the record is de-identified and closed: no one can sign in to it, and it cannot be granted access or a connect entitlement again. The record itself is removed in a second step, once the 90-day window in Section 9.3 has closed and the connection records and spent flight rows it keeps have been erased — the record cannot be removed while those still reference it, which makes that window a floor on its removal rather than a target. We give you the date it becomes removable when we confirm the first step. Both steps flow into the next operator backup rotation. See the privacy notice and DSAR procedure.
9.2 Revoking the grant at the vendor is a separate step, and one we perform on request: running terakota qbo disconnect --company <id> on your machine asks the broker to revoke with the vendor, and an operator can revoke a connection on our side — after which the next token that connection presents triggers the upstream revocation attempt in 8.2. Closure does not fire that upstream revocation on its own; it stops renewals, which ends the connection within one access-token lifetime. As above, an access token already issued remains usable until it expires.
9.3 Records of connections that have been revoked are retained for 90 days after revocation — that window is what allows abuse on our shared vendor application to be attributed — and are then erased.
9.4 The audit log is append-only for integrity. Where full deletion of an audit row would break that integrity, we pseudonymize it (replace identifiers with a tombstone) rather than delete the row. Audit entries are retained for 365 days.
9.5 Control-plane audit rows (Section 3.5) live in our engine store, are append-only, and carry your account id rather than your email; closure does not rewrite them.
10. Liability and governing law
10.1 Liability. The Portal, the control panel, and the connect service are provided "as is" and "as available", without warranty of any kind. We do not warrant that the connect service will be available or uninterrupted. To the maximum extent permitted by law, neither we nor our suppliers are liable for indirect, incidental, special, consequential, or punitive damages, or for lost profits, lost data, business interruption, or the cost of substitute services, under any theory. Also to the maximum extent permitted by law, our total aggregate liability for all claims relating to your account, the Portal, the control panel, or the connect service will not exceed the greater of the amounts you paid us for the service in the twelve months before the claim or one hundred U.S. dollars (US $100) — the EULA caps Software claims at a flat US $100, and the two caps are deliberately different because the connect service is the tier that can be paid for. Nothing here limits liability that cannot be limited under applicable law.
10.2 Governing law and venue. These terms are governed by the laws of Wyoming, excluding conflict-of-law rules; exclusive venue is Sheridan County, Wyoming. The responsible entity is Bilans Solutions LLC, a Wyoming limited liability company.
10.3 We may update these terms. When we publish a new version, we record your acceptance of that version per account at your next sign-in before you continue using the Portal.
Change log
Revision 2026-09-07 (terms-pack v1.3) — the control panel is covered for the first time: the scope names it and the control-plane API (preamble); Section 1.2 names the control-panel entitlement; new Section 2.2 records that it is operator-set and, today, switched on for the operator's own account only; new Sections 3.5 and 3.6 state what the panel holds (routing and delivery metadata, never an event's content), that every change is audited, that other members can see that a member changed what, and that deliveries to our own index produce no receipt of yours; new Section 4a states what the panel is, what you can and cannot do, what the binary sends and receives, what we record about each call and for how long, the sign-in tokens, what happens when the panel is closed or the control plane is down, and that it is not open to third parties today; Section 5.3 says the panel is real routing over synthetic events; Section 8.2 adds the panel to suspension; Section 9 adds the entitlement withdrawal and the engine-store audit rows that closure does not rewrite; Section 10.1 names the panel. Re-acceptance at your next sign-in follows from the version bump per Section 10.3.
Revision 2026-08-31 (terms-pack v1.1) — no change to these terms. The pack revision records the Privacy Notice's withdrawal of the anonymous Seam Check surface at check.terakota.io, which these terms never covered; every section, obligation, and retention window here is unchanged. Re-acceptance at your next sign-in follows from the version bump per Section 10.3, not from any change to what you agreed.
Revision 2026-08-28 (terms-pack v1.1) — the published erasure wording now matches what erasure does. Closure and an erasure request complete in two steps, not one: the day we act on a verified request the identifying data goes (the Auth0 user, the sign-in identity, sessions and memberships, and the email address, display name, accepted-terms record and verified-email flag on the account record), and the account record itself is removed only after the 90-day window for revoked connection records published in Account Terms Section 9.3 has closed, because those retained records reference it and it cannot be removed while they do. Account Terms Section 9.1 and Privacy Notice Section 3.5 now state both steps and the de-identified state between them, and Section 9.1 no longer says connection records are deleted at closure, which Section 9.3 has always contradicted. Privacy Notice Section 6.2 separates the response deadline (default: 30 days), which is unchanged, from the removal of the record, which falls after it, and records that we give you the removable-on date in our response. This corrects a description, not a practice: no new data category, no new retention, and the 90-day and 365-day windows are unchanged.
Revision 2026-08-17 (terms-pack v1.1) — item 9 of the connection-record enumeration now names the revocation timestamp (revoked_at) beside the created and last-refresh timestamps; the field was added so the 90-day erasure of revoked connection records published in Account Terms Section 9.3 is executable. No new data category — a stored-field disclosure clarification, and the enumeration stays closed at eleven items.
Revision 2026-08-13 (terms-pack v1.1) — the connect service is covered for the first time: new Section 4 (what it does, the device key, the runtime dependency and its degradation, refresh-cutoff as the abuse control, the account-requirement scope fence). Section 1.1 is corrected: self-signup is free and open, and entitlements — not the signup gate — are what control access. Section 1.2 gains the accepted-terms version and 1.3/1.4 add the eleven-field connection record and the flight rows, both matched to the shipped store. Section 3.2 adds credential custody. The synthetic-demo-data claim (now Section 5) and the pilot-path fence (now Section 6) each gain a connect-service carve-out, because a production connection is not demo data and is not business data entering the Portal. Suspension (Section 8) states its connect consequences. Offboarding (Section 9) adds connection records and flight rows, names closure as an operator-run sequence rather than a self-serve button, and separates upstream vendor revocation from closure. Section 10 replaces the open counsel brackets with a liability cap and Wyoming governing law. Sections renumbered: old §4→§5, §5→§6, §6→§7, §7→§8, §8→§9, §9→§10.
Revision 2026-07-16 — first published version.
Hosted by Terakota. Your data at rest is yours; payloads transit our compute as service-provider processing.