Revoking and disconnects
A connection can end from three directions: you end it, the host ends it, or Haven ends it. Each looks different to your integration, and handling them properly is most of what separates an integration that ages well from one that generates support tickets.
Revoking a token
POST /api/public/oauth/revoke, RFC 7009.
token=hvat_... or hvrt_...
token_type_hint=access_token | refresh_token # optional
The response is 200 with an empty body, always. An unknown token, an already-revoked token and a token belonging to a different client all return the same thing. That is required by the standard, and the reason is that any other behavior turns the endpoint into an oracle for whether a token exists.
Revoking a refresh token also revokes every access token it minted and the rest of its rotation chain. Revoking an access token affects only that token.
Revoking does not end the host's authorization. The grant is the host's consent, not your session. After revoking every token you hold, the connection still exists and you can obtain new tokens without asking the host again. If you want the connection genuinely gone, call the disconnect operation, which is a different thing and says so.
That asymmetry is deliberate. A partner's "log out" quietly deleting a host's consent would be as surprising as the reverse.
When the host disconnects
Hosts manage connected applications in their Haven account and can revoke yours at any moment. When they do, every token dies immediately and your next call returns 401 with invalid_token. A refresh returns invalid_grant.
There is no way to prevent this and no notice beforehand. Design for it: surface a clear reconnect path in your own interface, stop background work for that account rather than retrying, and do not treat it as an error condition worth alerting on. A host disconnecting an integration is a normal thing for a host to do.
Once webhooks ship, connection.revoked will tell you at the moment it happens rather than on your next failed call.
When Haven suspends
Haven can suspend an application or a whole developer organization. Suspension is reversible and is used for incident response: a leaked secret, an integration behaving abusively, or a security disclosure being worked through.
Your token calls return 403 with partner_suspended, and the token endpoint returns invalid_client. Haven contacts your security address. This is the reason that address has to reach a person who can act.
A grant can also be suspended without any action by you or the host, when the authority behind it goes away: the person who authorized you loses their seat on the account, or the agency link they were acting through is severed. The host sees the application paused rather than removed, and restoring the seat restores the connection.
Distinguishing the cases
Your error handling should tell these apart, because the remedies differ completely.
| What you see | What happened | What to do |
|---|---|---|
401 invalid_token | Access token expired | Refresh |
invalid_grant on refresh | Host revoked, or the granting seat is gone | Prompt the host to reconnect |
403 partner_suspended | Haven suspended you | Contact Haven; do not retry |
403 insufficient_scope | Valid connection, missing permission | Re-authorize with the added scope |
401 invalid_client at token | Your credentials are wrong or your app is not approved | Check the secret; check approval status |
Only the first is routine. The third and fifth mean stop and involve a human.
Rotating your client secret
You can hold several live secrets at once, which makes rotation an overlap rather than a cutover: mint the new one, deploy it, confirm traffic has moved, then revoke the old one. Nothing breaks in between.
The raw secret is displayed exactly once at creation. Haven stores a hash and cannot show it to you again, only replace it.