Now in developer preview

Connect to
any account.

Passage is an account linking API for developers. Your users log in on their own device — credentials never touch your servers. Read billing data, payment methods, order history, and more from any online service.

create-link.ts
const link = await passage.links.create({
  provider: "tmobile",
  operations: [
    { type: "mobileBillingStatement:read" },
    { type: "paymentMethod:read" },
  ],
  webhookUrl: "https://api.yourapp.com/passage/webhook",
});

// Give this to your mobile app — opens as an App Clip
return { claimCode: link.claimCode, url: link.appClipUrl };

Three steps. Zero credentials on your servers.

01

Create a link

Your backend calls POST /v1/links with the provider and operations you need. You get back a claim code and an App Clip URL — a lightweight entry point that requires no app install.

02

User authenticates on-device

The user opens the App Clip and logs into the target service in a secure webview. Their credentials stay entirely on their device — Passage never sees or stores them. You get a live session with full telemetry.

03

Receive structured data

Once the automation completes, you receive an ES256-signed webhook with validated, structured results — billing statements, payment methods, order histories, whatever you requested. Verify the signature and you're done.

Built for developers who ship.

Zero-knowledge by design

Users authenticate directly in a secure webview on their device. Passwords, MFA codes, and session tokens never leave the phone. Your servers only receive the structured data you asked for.

credentials: never_transmitted

Playwright-like API

Navigate, click, fill, wait for selectors — familiar browser automation primitives, relayed in real-time over WebSockets.

Multi-operation links

Request billing data and payment methods in a single link. Operations execute sequentially — one authentication, multiple results.

Live telemetry

Console logs, network requests, navigation events, screenshots — streamed in real-time. Debug sessions as they happen.

Signed webhooks

ES256 JWT signatures on every webhook payload. Fetch the public key by kid, verify the signature, and trust the data.

No app install required

Links open as iOS App Clips — instant, frictionless entry points that require zero download. Users are connecting in seconds.

Edge-native infrastructure

Built on Cloudflare Durable Objects. Sessions run at the edge, close to your users. Sub-50ms relay latency worldwide.

What you can build.

Bill pay & verification

Pull billing statements from carriers and utilities. Verify amounts, due dates, and payment history — without asking users for screenshots or PDFs.

mobileBillingStatement:read

Payment method portability

Read saved payment methods from one service and add them to another. Let users move their cards between platforms without re-entering details.

paymentMethod:readpaymentMethod:write

Account verification

Confirm a user owns an account at a third-party service — telecom, utility, or retailer — without ever touching their credentials.

Order & purchase history

Access order histories from delivery apps, e-commerce platforms, and subscription services. Power cashback, receipt tracking, or spend analytics.

orderHistory:read

Insurance & coverage verification

Verify insurance coverage, policy details, or claims status by connecting to carrier portals. Replace manual document uploads.

Custom automations

Use the Sessions API to build any workflow against any website with a login. If a user can do it in a browser, Passage can automate it.

A session primitive, not a black box.

Your backend
REST API / Webhooks
Passage
Durable Object session
WebSocket relay SQLite state Telemetry
User's device
Secure webview (App Clip)
Commands flow left to right. Results flow right to left. The Durable Object is a stateful relay — it never interprets page content or stores credentials.
< 50ms
Command relay latency
0
Credentials stored
300+
Edge locations (Cloudflare)

Pre-built automations.
Growing every week.

T-Mobile tmobile
mobileBillingStatement:readpaymentMethod:readpaymentMethod:write
AT&T att
mobileBillingStatement:readpaymentMethod:readpaymentMethod:write
Verizon verizon
mobileBillingStatement:readpaymentMethod:readpaymentMethod:write
Uber Eats ubereats
orderHistory:read
Your service

Write custom automations against any website. The session primitive is generic — if a user can log in, Passage can connect.

From link to data in minutes.

webhook.ts
import { verifyWebhook } from "@passage/connect";

export async function handlePassageWebhook(req: Request) {
  const payload = await verifyWebhook(req, {
    publicKeyUrl: "https://connect.getpassage.ai/webhook_verification_key/get",
  });

  if (payload.status === "complete") {
    const billing = payload.results["mobileBillingStatement:read"];

    // Structured, validated data — ready to use
    console.log(billing.amountDue);    // "142.50"
    console.log(billing.periodStart);  // "2025-02-01"
    console.log(billing.currency);     // "USD"
  }
}
ConnectView.swift
import PassageSDK

struct ConnectView: View {
  var claimCode: String

  var body: some View {
    PassageConnectView(claimCode: claimCode)
      .onConnectionComplete { result in
        // User authenticated, automation ran, data returned
        print("Billing: \(result.billing.amountDue)")
      }
      .onConnectionError { error in
        print("Error: \(error.localizedDescription)")
      }
  }
}

Need full control? Drive the browser yourself.

Passage Connect gives you pre-built automations and structured data. But underneath it is a general-purpose session primitive — and you can use it directly.

Connect

  • Pre-built provider automations
  • Structured, validated results
  • Webhooks on completion
  • Ship in an afternoon

Sessions

  • Playwright-like browser commands
  • yieldToUser for human-in-the-loop
  • Live telemetry and screenshots
  • Automate any website

Both APIs share the same session infrastructure — Cloudflare Durable Objects, WebSocket relay, on-device webview. Connect is built on Sessions. Use whichever fits your use case.

automate.ts
const session = await passage.sessions.create();
const browser = await session.connect();

// Navigate, click, fill — Playwright-style commands
await browser.navigate({ url: "https://example.com/login" });

// Hand control to the user — they log in on their device
const result = await browser.yieldToUser({
  status: { subheading: "Log in to continue..." },
  conditions: [
    { type: "networkRequest", urlContains: "api/account", captureBody: true },
  ],
  timeout: 120_000,
});

// Extract data from the captured response
const account = JSON.parse(result.networkCapture.responseBody);

// Keep going — scrape, navigate, extract more data
await browser.navigate({ url: "https://example.com/settings" });
const html = await browser.innerHTML({ selector: ".account-details" });

Start connecting
accounts today.

Get API keys, explore the docs, and ship your first integration. Developer preview is free.