14. Integrations
Two ways to connect this account to another system. API keys let a foreign system read and write here; webhooks let us tell a foreign system that something happened. Both live under Integrations, and both require the "manage API keys" permission, which only owners and administrators hold.
API keys
A key authenticates exactly as a person does — same addresses, same permissions. That is deliberate: there is no second, separate interface that will eventually behave differently from the portal.
curl https://invoice.tatwelletech.com/api/v1/portal/customers \
-H "X-API-Key: twt_..."
Three rules worth knowing:
The key is shown exactly once. There is no button to see it again — a key that can be read back ends up in a screenshot and a support ticket. Lost means replaced.
A key can never do more than the person who created it. You choose permissions when creating one, and only the permissions you hold yourself are offered. Choose as few as possible: a key for an inventory system usually needs no more than reading customers and creating invoices.
A key belongs to exactly one company. The header a person uses to switch companies does not move it.
Revoking takes effect immediately and permanently; the row stays visible, because a key that was used is part of the record.
Webhooks
Instead of asking repeatedly whether something happened, register an address and we will tell you.
Currently published: invoice.finalized, invoice.paid, incoming.received,
incoming.approved, incoming.booked, customer.created.
https only, and the address must not be on an internal network — checked when you save it, and again on every delivery, because a DNS record can change afterwards.
Delivery and retries
Delivery happens in the background, never while you work: whether your server answers right now must not decide how long finalizing an invoice takes.
If your server does not answer with a 2xx we try again — after one minute, then two, four, eight, up to six hours apart, eight times in all. That spans an overnight outage without overwhelming anybody. After that the delivery counts as failed, but it does not disappear: you see it in the log with its last error and can put it back on the queue with Send again once your system is running.
Verifying the signature
Every message carries X-TWT-Signature: t=<timestamp>,v1=<signature>. The
signature is HMAC-SHA256 over <timestamp>.<body>, using the signing secret you
saw once when creating the endpoint.
mac = hmac.new(secret.encode(), f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()
Always verify the signature, and reject messages whose timestamp is well in the past — otherwise a message captured once could be replayed indefinitely. We never follow redirects.
The X-TWT-Delivery header carries a unique id. Use it to avoid processing the
same message twice: we retry on failure, and a message you processed but did not
acknowledge will arrive again.
No comments to display
No comments to display