A B2B partner - a referral partner, an introducer, an agent, a co-counsel firm - is an outside party you work with repeatedly, not a one-off client. Opbox serves that relationship with the same primitive that powers every external surface: the Portal. You build a portal scoped to the partner, attach exactly the matters, files, and requests they should see, give a named person at the partner an access link, and exchange messages and tasks across that boundary. The partner sees their window and nothing of your workspace around it.
There is no separate partner subsystem and no partner-specific data type. A partner portal is a portal you have configured for a recurring external counterpart, governed by the same exposure allow-list, the same external tier, and the same deny-by-default fence as a client portal. What makes it a partner relationship is how you populate and persist it, not a different set of rules underneath.
What it does
A persistent external window per partner. Create a portal for the partner and it becomes a standing surface you can keep adding to over time, rather than a throwaway link. Each portal pins the template version it was built from, so the layout and configuration are a known-good snapshot that a later template change cannot reshape underneath a live relationship. You can list your workspace portals with their status and their link and object counts, so the set of active partner relationships is one read away.
Named-email access principals, one link per person. Add a person at the partner by email and Opbox mints them a personal access link backed by a token. The pairing of portal and email is unique, and adding a principal resolves or creates the underlying party record for that person, so the same individual is tracked consistently. A link starts inactive and binds to the first person who claims it under a serialized first-claim, so exactly one holder wins and a forwarded link cannot be picked up by someone it was not meant for. You can add several named people from the same partner firm, each with their own link.
You share exactly what the partner should see. Attach specific objects - a matter, a file, a request - to the portal’s exposure allow-list, one at a time. Anything you have not attached does not exist as far as the partner is concerned: it is denied by absence, not hidden behind a setting that could be flipped by accident. For each attached object you set its visibility: full detail, a read-only view, hidden fields, or whether the partner can write back. The exposure manifest is a single read, so “exactly what is exposed to this partner” always has one answerable answer.
A messaging thread across the boundary. Post messages to the portal thread, and the partner can post back. The thread is the external-boundary surface, distinct from your internal comments, and any attachments on it honour each file’s sensitivity and internal-only marking, so an internal note never leaks across the boundary.
Tasks you assign and the partner completes. Assign a to-do to the partner - a form to fill, a payment, a document to provide - and they complete or submit it from inside their portal. A submitted form flows through the matter engine and advances the matter; an uploaded file lands as an encrypted record. Completion is idempotent and origin-pinned, so a re-submitted task does not double-fire.
The partner can ask for more, but the portal never widens itself. If the partner needs something not yet shared, the request-access affordance lets them ask. That lands as an approval gate naming the specific object requested - it never quietly widens exposure on its own. Only your staff approving the gate, then running the exposure write, adds the object to the allow-list. The request surface is rate-limited per token and per IP so it cannot be used to probe for what exists.
One partner can never reach another. Each link carries a token scoped to its single portal. There is no shared index to page through and no sequential IDs to walk, and a request for something that is not theirs returns the same answer as a request for something that does not exist. The external read resolves only that portal’s own allow-list, so the window is strictly one-way.
A full lifecycle and a kill switch. Suspend a partner portal to pause access, reactivate it later, or archive it to end access for good while keeping the complete record and audit chain. If you ever need to invalidate every outstanding link for a portal at once, a single scope-wide call bumps the access version and every stale token is rejected immediately.
The partner-specific composition the legacy product layered on top - referral codes, tiered partner levels, and commission-rate management - is not part of the Opbox substrate. The substrate provides the generic portal primitives above; a partner programme of that kind would be authored as a vertical’s configuration on top of them, not as a built-in feature here.
How you use it
Build the partner’s portal. Create a portal from a template, which pins a known-good configuration and sets the branding and layout. This is your staging area: you assemble it before the partner ever sees it.
Share the objects the partner should act on. Attach the matters, files, and requests, and for each one choose how much is visible - full, read-only, hidden fields, or write-back. Read the exposure manifest to confirm exactly what is on the allow-list before any link goes out.
Add the people at the partner. Add each named contact by email to mint their personal access link. The link is inactive until the first claim binds it to one holder, so you can issue links ahead of time without them being hijacked.
Work the relationship. Post to the thread, assign tasks, and watch responses, forms, and uploads flow back into the matter and onto the audit record in real time. There is no separate inbox to reconcile.
Handle requests for more. When the partner asks for access to something not yet shared, it arrives as a gate for you to approve. Approve it and run the exposure write to add the object; the portal never widens itself.
End or pause access. Suspend the portal to pause it, reactivate it when work resumes, or archive it to close the relationship while keeping the record. Bump the access version if you need to invalidate every outstanding link in one call.
The kernel verbs behind it
Each goes through the one front door - permission-checked and audited before it runs. These are the verbs most specific to a partner portal.
portal.archive- terminal teardown: withdraw all external access while retaining the record and audit chain.portal.bump-access-version- the scope-wide kill switch that invalidates every outstanding link’s token at once.portal.create- instantiate a portal from a pinned template version for a new partner.portal.get- read one portal and its resolved configuration.portal.link.activate- the serialized first-claim that binds a link to exactly one holder.portal.link.add- add a named-email access principal at the partner and mint their token.portal.link.revoke- terminally cut one person’s link.portal.list- list your workspace portals with status and link and object counts.portal.message.post- append a message to the portal thread across the external boundary.portal.object.attach- add a matter, file, or request to the partner’s exposure allow-list.portal.object.detach- remove an object from the allow-list; un-attached is a hard deny.portal.object.list- read the exposure manifest: each object’s visibility, hidden fields, write-back, and traversal.portal.set-visibility- choose how much of an attached object the partner sees: full, read-only, hidden fields, or write-back.portal.task.assign- assign the partner a to-do, such as a form or a payment.portal.task.complete- the partner completes or submits an assigned task, flowing it back to the matter.portal.request-access- the partner asks for something not yet shared; it lands as a gate, never a self-widening.portal.session.start- the partner’s authenticated entry into their portal.portal.traverse- the bounded, deny-by-default read the partner uses to walk only what was shared.
See the full set in the portal verb reference.