Skip to content

Connect an account

Your customer clicks Connect Linear in your product. This guide takes them through Zupflow’s hosted Connect page and back.

You’ll buildA Connect button that links a customer’s account, in a tab or a popup
TimeAbout 15 minutes
You needAn app configured in the environment, and a workspace
Your product
IntegrationsLinearConnect
Your backend creates a session and sends the person to its URL.
Hosted by Zupflow
/connect/cs_ref…Connect LinearContinue
Runs the sign-in: OAuth, or a token the person pastes.
The service
Authorize access?Authorize
The person signs in with the service itself.
Installation
Linear k7m2qdconnected23 tools listed
Credentials sealed, tools listed, and the person is back at your return_url.
The person never gives your product their credentials, and you never store them.

In the Console, under Developers → Connect, set for each environment:

  • Return URLs: the exact URLs Connect may send people back to. No wildcards.
  • Allowed origins: the origins allowed to frame the page or open it in a popup and hear its message. In Sandbox, http://localhost is allowed too.

The app must be configured in that environment, too.

sequenceDiagram
actor P as Person
participant F as Your frontend
participant B as Your backend
participant Z as Zupflow
participant S as Provider
P->>F: Connect Linear
F->>B: start
B->>Z: create Connect session
Z-->>B: session.url
F->>Z: open session.url (popup or redirect)
Z->>S: consent
S-->>Z: callback with code
Z->>Z: exchange, seal, create installation
Z-->>F: postMessage or redirect to return_url
F->>B: done?
B->>Z: read the session
Z-->>B: completed + installation
  1. Your backend creates a session with an API key of the workspace’s environment.

    const session = await zupflow.connectSessions.create(workspaceId, {
    app_id: appId,
    intent: "create",
    label: "Work Linear",
    installation_id: null,
    return_url: "https://app.example.com/integrations",
    });
    return { url: session.url, sessionId: session.id };
  2. Your frontend sends the person to session.url, in a redirect or a popup. The page runs the OAuth consent or asks for the token, then seals the credentials into an installation.

  3. The person comes back.

    • In a tab, a completed session redirects to return_url with zupflow_session=<session id> added.
    • In a popup, the page posts { type: "zupflow.connect.finished", session_id, status } to the opener and closes.
  4. Your backend reads the session to know the outcome, and its installation.

    const session = await zupflow.connectSessions.get(workspaceId, sessionId);
    if (session.status === "completed") {
    // the installation is connected; its tools are being listed
    }
function connect(url: string, sessionId: string) {
const popup = window.open(url, "zupflow-connect", "width=520,height=720");
return new Promise<void>((resolve) => {
const done = () => {
window.removeEventListener("message", onMessage);
clearInterval(timer);
resolve();
};
const onMessage = (event: MessageEvent) => {
if (event.origin !== new URL(ZUPFLOW_URL).origin) return;
if (event.data?.type === "zupflow.connect.finished" && event.data.session_id === sessionId) done();
};
window.addEventListener("message", onMessage);
// The popup may lose its opener: poll your backend as well.
const timer = setInterval(async () => {
if (popup?.closed || (await sessionFinished(sessionId))) done();
}, 2000);
});
}

Whatever ends the wait, ask your backend for the session’s status before showing a result.

When an installation’s credentials stop working, Zupflow sends installation.reconnect_required. Create a session with intent: "reconnect" and the installation_id; the installation keeps its ID, short_id and grants.

connect_session.completed, connect_session.failed and installation.connected tell your backend the same thing without polling. See Webhooks.