- Documentation
- Client portal
- Connection request statuses and expiry
Connection request statuses and expiry
Reference for connection request statuses, magic-link expiry by recipient type, resend limits, and the errors you can hit.
A connection request is the record of you asking a client to connect an app. It moves through a fixed set of statuses, the link you send the client expires on a clock that starts at dispatch, and you can resend that link a limited number of times. This page is the lookup for every status, expiry window, resend rule, and error code in that flow.
It covers two distinct vocabularies that are easy to confuse:
- Request statuses track the lifecycle of the ask (has the client connected yet?).
- Connection statuses track the health of the credential that exists after the client connects. Those live on Manage client connections.
Request statuses
A connection request stores one of five statuses. The default at creation is pending.
| Status | Label | Meaning | Terminal |
|---|---|---|---|
pending | Pending | The request exists and is waiting on the client to connect. A queued request and a dispatched-but-unconnected request both sit here. | No |
fulfilled | Fulfilled | The client completed the provider's consent screen. A connection now exists in the workspace. | No |
expired | Expired | The link passed its expiry before the client connected. The link no longer opens. | Yes |
revoked | Revoked | The connection backing this request was revoked, which cascades back to the request. | Yes |
cancelled | Cancelled | You cancelled the request from the editor before it was connected. | Yes |
Status transitions
Only these moves are legal. Anything else is rejected as an illegal transition.
| From | To |
|---|---|
pending | fulfilled, expired, revoked, cancelled |
fulfilled | revoked |
expired, revoked, and cancelled are terminal. A request in any of those states never moves again. To collect the credential after that, queue and send a fresh request.
The "Queued (not yet sent)" editor label
Before you dispatch, the editor shows a sixth label, Queued (not yet sent), on the node slot and in the sidebar panel. This is a display projection, not a stored status: a queued row is pending in the record with dispatchedAt not yet set. It tells you the client has not been emailed and the expiry clock has not started.
| Editor label | Underlying status | When it shows |
|---|---|---|
| Queued (not yet sent) | pending | Dispatched timestamp is empty (you have not sent yet) |
| Waiting on client | pending | Dispatched, link sent, client has not connected |
| Connected | fulfilled | Client finished the consent screen |
| Request expired | expired | Link passed expiry before connection |
| Connection revoked | revoked | Backing connection was revoked |
| Request cancelled | cancelled | You cancelled the request |
A queued request has no expiry date. The clock starts only when you dispatch. A queued request ends only when you cancel it or delete the workflow draft, so a request you queued and forgot about will still be waiting, not silently expired.
Link expiry
The link you send is bound to one recipient and expires on a clock that starts at dispatch (expiresAt = dispatch time + window). The window depends on whether the recipient already has a portal account.
| Recipient type | Where they connect | Expiry window |
|---|---|---|
| Workspace member (has a portal account) | Inside the portal at /portal/connections | 4 hours from dispatch |
| Net-new email (no portal account) | A branded magic-link page | 7 days (168 hours) from dispatch |
The request modal surfaces this to you live as you pick a recipient. A workspace member shows "They have 4 hours from dispatch to connect." A net-new email shows "They have 7 days from dispatch to connect."
Expired requests are cleaned up automatically. Once a dispatched request passes its expiry, its status flips to expired and the link stops working immediately, so a client who clicks an old link lands on an error page rather than a stale consent flow.
Resend behavior
Each dispatched request carries a Resend email action. Resending re-mints the link and invalidates the previous one, so the client always holds at most one working link.
| Rule | Value |
|---|---|
| Resends allowed per request | 3 (post-dispatch sends only) |
| Minimum interval between resends | 5 minutes |
| Request must be | Dispatched and still pending |
| Effect of a resend | Mints a fresh link; the previous link stops working |
The editor pre-disables the Resend button to match these server rules and shows the reason inline:
{n} send(s) left.while you have resends remaining.Resend limit reached (3 / 3).at the cap.Available again in {n} min.during the 5-minute cooldown.
A resend re-mints the link, so any link you sent earlier (including the original dispatch) stops working. If a client reports a broken link after you resend, point them at the most recent email, not the first one.
Workspace and account limits
These caps apply to the agency side of the flow.
| Limit | Value | Scope |
|---|---|---|
| Requests created per hour | 60 | Per workspace |
| Dispatch operations per hour | 30 | Per workspace |
| Email previews rendered per hour | 60 | Per workspace |
| Outstanding pending requests | 1,000 | Per workspace |
| Outstanding pending requests | 10,000 | Per account |
Who can do what
| Action | Agency (you) | Client |
|---|---|---|
| Queue a request | Yes | No |
| Send to client (dispatch) | Yes | No |
| Resend the email | Yes | No |
| Cancel a request | Yes | No |
| Connect the app | No | Yes |
| Refresh or revoke the resulting connection | No | Yes (own connections only) |
The client never cancels a request. From their side they can only connect the app, then later refresh or revoke the connection it produced. Cancelling is an editor-only action you take on a queued or dispatched-pending request.
Errors
These are the codes and messages this flow returns. Resend failures all carry HTTP 429 or 422.
| Code | HTTP | Message | When it happens |
|---|---|---|---|
connection_request.dispatch_required | 422 | Send the request to the client before re-sending the email. | You tried to resend a request that is still queued (never dispatched). |
connection_request.cancelled | 422 | Cannot resend a request in status "{status}". | You tried to resend a request that is no longer pending (already fulfilled, expired, revoked, or cancelled). |
connection_request.email_resend_cap_breached | 429 | Email resend cap reached for this request. | You hit the 3-resend cap on one request. |
connection_request.resend_too_soon | 429 | Wait at least 5 minutes between resends. | You resent within 5 minutes of the last send. |
connection_request.note_too_long | 422 | (validation) | The note to the client exceeded 256 characters. |
connection_request.recipient_missing | 422 | (validation) | The request had no recipient email. |
connection_request.workspace_request_cap_breached | 429 | Workspace pending-request cap reached. | The workspace holds 1,000 outstanding pending requests. |
connection_request.illegal_status_transition | 422 | (transition rejected) | A status change that is not in the legal transition table was attempted. |
What the client sees on a dead link
When a client opens a link that has expired, was already used, or is invalid, every case renders the same screen by design:
This link can't be opened It may have expired, already been used, or is otherwise invalid. Ask the requester to send you a fresh link.
The client never sees which of those reasons applied. If they report a dead link, send a fresh one with Resend email (if the request is still dispatched and pending) or queue and send a new request (if it expired or was cancelled).
Related
- Request client credentials walks through queuing and sending a batched request from the editor.
- Manage client connections covers the connection health statuses (active, error, pending, revoked) and how clients refresh or revoke.
- Client authorizes an app shows the client side of the consent flow, in the portal and via the branded link.