Convivial Bridge

Put a next home inside your program's app

Bridge lets a housing organization — a recovery residence network, transitional housing program, or reentry program — embed Convivial's apartment search inside its own app.

Draft. This document accompanies sort-bridge-api.yaml v1.0.0-draft and is shared for partner and engineering review. Endpoints ship with the Bridge release; sandbox access comes with your partner agreement.

How it works

When a resident is ready for a place of their own, they browse Convivial network communities where events, neighbor matching, and local perks are part of the listing — and their expressed interest is tracked all the way to a signed lease. Your team follows progress from your own system; the resident's history stays private.

Your backend creates a short-lived, signed session for a resident and renders the returned embed_url in a WebView or iframe. Everything inside that surface is built and hosted by Convivial. Your integration is the thin layer around it: create sessions, receive webhooks, read reports.

Your systems
Your backend Holds the API key — server only
Your app WebView / iframe
Convivial
Bridge API sessions · leads · webhooks
Convivial embed Resident browses & consents here
Property
Leasing team Convivial dashboard
Standard Convivial lead Source masked
  1. 1Create session — your backend sends an opaque ref plus preferences; Bridge returns an embed_url good for 24 hours.
  2. 2Render — your app loads that URL in a WebView or iframe.
  3. 3Consented lead — the resident enters contact info inside Convivial's surface; it reaches the one property they chose, with your organization masked.
  4. 4Webhooks — lead.status_changed and friends fire back to you, keyed to your reference, carrying no PII.

One placement, end to end. The only things that ever cross out of your systems are an opaque reference and housing preferences. Contact information exists only between the resident, Convivial, and the one property they chose — delivered as a standard Convivial lead with the source masked.


Quickstart

1

Create a session when a resident is ready

Server-to-server, with your API key. partner_resident_ref is an opaque ID from your system — never a name, email, or phone number. Requests that look like they contain personal information are rejected.

# sandbox
curl https://sandbox.api.sortresidential.com/bridge/v1/embed/sessions \
  -H "Authorization: Bearer sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_resident_ref": "res_8f3d2c9a",
    "preferences": {
      "budget_max_cents": 125000,
      "bedrooms": [0, 1],
      "areas": ["Houston, TX"],
      "move_in_after": "2026-11-01"
    },
    "locale": "en"
  }'

→ 201
{ "id": "ses_01j9x2", "status": "created",
  "embed_url": "https://embed.sortresidential.com/s/ses_01j9x2?t=…",
  "expires_at": "2026-09-15T16:03:22Z" }

The URL is signed and lives 24 hours. When it expires, create a new session with the same reference — saved listings and open leads follow the reference, so the resident continues where they left off.

2

Render the embed in your app

iOS — Swift
let webView = WKWebView(frame: view.bounds)
webView.load(URLRequest(
  url: URL(string: session.embedURL)!))
view.addSubview(webView)
Android — Kotlin
webView.settings
  .javaScriptEnabled = true
webView.loadUrl(
  session.embedUrl)
Web
<iframe src="{{embed_url}}"
  title="Find your next home"
  style="width:100%; height:640px;
         border:0"></iframe>

Pass theme.accent_hex when creating the session and the embed picks up your accent color, so the surface sits naturally inside your app.

3

Listen for progress

Register a webhook endpoint once; every event that follows is keyed to your own partner_resident_ref, so routing it to the right case file needs no lookup. Verify signatures before trusting a delivery:

// Node — express with raw body
import crypto from "node:crypto";

function verifySortWebhook(req) {
  const parts = Object.fromEntries(
    req.headers["sort-signature"].split(",").map(p => p.split("=")));

  const expected = crypto
    .createHmac("sha256", process.env.SORT_WEBHOOK_SECRET)
    .update(parts.t + "." + req.rawBody)
    .digest("hex");

  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;

  return fresh && crypto.timingSafeEqual(
    Buffer.from(parts.v1), Buffer.from(expected));
}

Endpoints

The full contract, with schemas and examples, lives in sort-bridge-api.yaml. The surface is deliberately small:

EndpointWhat it doesTier
POST/embed/sessions Create a resident session; returns the signed embed_url. Core
GET/embed/sessions/{id} Session status and activity counts for a case-manager view. Core
GET/listings Network availability with the community block, ranked by stated preferences. Core
GET/listings/{id} One listing in full. Core
GET/leads Lead status by session, reference, or stage. Core
POST/leads Create leads from your own native UI. Residents still consent through Convivial before any contact info is shared. API tier
POST/webhook-endpoints Register a delivery URL (list, delete, and test endpoints included). Core
GET/reports/placements Monthly funnel — sessions to signed leases — plus referral-fee lines when your agreement includes them. Core

Webhook events

EventFires when
embed_session.openedThe resident opens their search for the first time.
lead.createdThe resident submits interest in a listing, consent on record.
lead.status_changedThe lead moves: contacted, tour scheduled, toured, applied, approved.
lead.lease_signedPlacement complete. Includes the referral ledger entry when fees apply.
embed_session.expiredA session lapsed without activity — a nudge opportunity for the case manager.

Deliveries are signed (HMAC-SHA256, Sort-Signature header), retried with backoff for 24 hours, and disabled after 7 failing days. Acknowledge with any 2xx within 10 seconds.

Privacy by design

Bridge exists for people at a sensitive moment, so these five rules are part of the API contract — enforced by schema and server behavior, not left to good intentions:

You never send resident PII.

Sessions carry an opaque reference and housing preferences. Schemas are closed; unknown fields are rejected, and references that look like emails or phone numbers return 422 pii_suspected.

No program or health information exists in this API.

There are no fields for program enrollment, treatment, or history — nothing to fill in, nothing to leak. Free text is limited to housing notes and filtered server-side.

Contact info belongs to the resident.

They enter it themselves, inside Convivial's surface, behind a consent screen that names the one property that will receive it.

Source masking.

Leasing teams see a standard Convivial lead. Your organization's name, category, and existence are never shown to the property; attribution lives only in your reports and the referral ledger.

Preference-only matching.

Ranking uses budget, bedrooms, area, move-in date, pets, and accessibility — never a protected-class attribute. This supports everyone's fair-housing obligations; many Bridge residents are protected under the Fair Housing Act's disability provisions, and the design assumes it.

Commercial terms — including whether placements carry referral fees — live in your partner agreement, and both sides should have counsel review it.

Sandbox & go-live

Sandbox keys (sk_test_…) work against sandbox.api.sortresidential.com with fictional inventory, and POST /webhook-endpoints/{id}/test sends a signed sample event. Before switching to live keys:

Talk to us about Bridge

Sandbox access and the full sort-bridge-api.yaml spec come with your partner agreement. Tell us about your program and we'll get you a key.

Email [email protected]
Convivial Bridge — partner integration guide, draft for review
Spec: sort-bridge-api.yaml v1.0.0-draft  ·  Questions: [email protected]