master-zapier-plan-draft/packages/dev-overview/02-endpoint-io.md
George Lambert 86b421db05
Some checks failed
offline / test (push) Has been cancelled
Add dev-overview: designed vs running NATS routes and Zapier-Verae path.
Independent Forgejo repo maps every verae.* address, endpoint I/O, job
monitor loop, and remaining billing/archive wiring.
2026-09-14 13:25:04 -04:00

5.3 KiB

Endpoint I/O

Each product NATS address: what it is for, who sends, who receives, how to attach.

Connect with a long-lived client:

NATS_URL=nats://10.10.10.21:4222,nats://10.10.10.22:4222,nats://10.10.10.23:4222

Public edge (token in /etc/nats/public-edge.token on NS1): nats://<token>@70.88.205.138:4222. Do not put that URL in Zapier.


verae.zapier.jobs.watch

For Work queue: “poll Verae until this jobId is terminal.”
In from middleware enqueueWatch after POST /api/timestamp (or mock) returns jobId
Out to job-poller worker (queue job-poller, durable on ZAPIER_JOBS)
Then poller calls Verae GET /api/status/{jobId} over HTTPS, not NATS

Payload: tenantId, veraeUserId, jobId, tokenRef, enqueuedAt, attempt, maxAttempts, intervalMs, traceId. JWT stays in middleware (tokenRef); never on Zapier.

Connect Verae-side: do not subscribe this from api.veraetime.net. The poller is the Verae HTTP client. To add another watcher, start another job-poller consumer in the same queue group.


verae.zapier.jobs.events

For Terminal outcomes: timestamp.completed / failed / timeout
In from job-poller after Verae status is not pending
Out to (1) middleware waitForJobEvent (wait HTTP); (2) webhook router → webhooks.deliver; (3) optional verae-jobs-events mailbox

If JOBS_EVENTS_EXCLUSIVE=1, only verae-jobs-events is the durable consumer and republishes verae.internal.jobs.events. Default lab: middleware wait + webhook worker share the stream.


verae.zapier.webhooks.deliver

For HTTPS POST to hooks.zapier.com (REST Hook)
In from webhook worker on completed/failed events
Out to Zapier cloud HTTPS, never NATS

Slow consumer: this is the flood/backlog path. Keep replica floors on the worker.


verae.zapier.usage

For Optional meter of Zap actions on NATS
In from designed: middleware / edge
Out to designed: USAGE_WRITER → books
Running stream exists; no writer; middleware uses local usage files

Finish: publish here from recordUsage, consume into verae.billing.usage.recorded.


Billing (verae.billing.*) — account-balance SoT

Request-reply unless noted. Queue on account-balance. Not JetStream (except you could mirror later).

Address For In from Out to
statement.get prepaid, credits, usage, payments portal, CS, sales, admin, access-web/api reply to requester
balance.get cents only internal reply
balance.adjust CS credit or portal reload CS, access-web (reload kind only) books + reply
usage.recorded meter pub zappier-edge (designed) account-balance subscriber
payment.recorded reload/invoice pub portal books
credit.applied goodwill pub CS books
customer.put upsert customer edge/IAM books

Authz must pass verae.access.authz.check before these from a public plane. Leaf plane cannot call billing (policy).


Access planes

Address For In Out
verae.access.authz.check allow/deny { plane, subject, principal } every plane { allow, reason }; deny also pubs authz.deny
verae.access.web.* browser portal access-web HTTP billing statement/reload after authz
verae.access.api.* customer x-api-key access-api statement; HTTPS to middleware for jobs
verae.access.zapier.* Zapier HTTPS only access-zapier jobs.watch via HTTP to middleware, not Zapier NATS
verae.access.leaf.* S2S access-leaf archive + jobs; never billing
verae.access.staff.* CS/sales/accounting access-staff billing after authz

Identity

Address For In Out
verae.identity.bind bind email/customerId → veraeUserId portal / middleware reply
verae.identity.lookup lookup by customerId or veraeUserId same reply

Queue identity. Fleet keepFloor.


Archive / tree

Address For In Out
verae.archive.put WORM/tree write (hash, meta, file meta, merkle leaf) splitter (in-process from middleware today) every worm/tree (JS)
verae.archive.query broadcast lookup aggregator all worm/tree, no queue group
verae.archive.reply.<correlationId> bloom hit only worm/tree aggregator

Silence = miss. Chain seal does not wait on archive.


How to connect Verae API to NATS

api.veraetime.net is HTTPS. It does not subscribe. The glue is middleware:

  1. Set VERAE_API_BASE_URL=https://api.veraetime.net and MOCK_VERAE=false.
  2. Middleware login (username/password) → JWT stored as tokenRef.
  3. POST /api/timestamp → 202 { jobId }.
  4. Publish verae.zapier.jobs.watch.
  5. Poller GET /api/status/{jobId} until completed / failed.
  6. Publish verae.zapier.jobs.events.
  7. Wait HTTP and/or REST Hook.

Do not point Verae at NATS_URL. Do not put NATS in Zapier env. A new worker that must see seals uses jobs.events or HTTP GET /zapier/v1/status/{jobId}.

Template for a new addressed process: clone verae-nats-process, rename verae.example.process.*.