Core API
The contracts a connector calls into the core — how they are bound, the records and refs that cross them, the idempotency every write keeps, the exceptions, and what the nine contracts cover.
Ports are the core calling the connector. The Core API is the inverse: interfaces under Subscriby\Connector\Core\* that the application implements and binds in its container, and that a connector calls instead of importing application classes. A core refactor that keeps the contract breaks no connector, and a connector never touches a table it does not own.
Getting hold of a contract
Ask for the interface in a constructor. The application's connector service provider binds each one to its implementation, so any class the container builds (a port, a handler, a job in your package) receives it:
use Subscriby\Connector\Core\Identities;
use Subscriby\Connector\Core\Installations;
final class ExampleInboundController
{
public function __construct(
private readonly Installations $installations,
private readonly Identities $identities,
) {}
}The nine contracts
| Contract | Reads | Writes |
|---|---|---|
Installations | By id, platform id or your storage ref; a project's or the platform's list; the stored credentials of one you can name. | record() an installation, recordState() a health verdict, forget() one. |
Identities | By id or platform id; who holds an identity (creator, member). | record() an identity, link it to a creator or a member, complete a handshake. |
Spaces | By id, or by installation, kind and platform id. | record() a place, bindResource() an existing resource to it. |
Resources | By id, by place, or a project's list on your connector. | create() the resource that sells a place the creator picked. |
Grants | By id, or by the reference you issued. | record() a grant (migration and legacy mirroring). |
Creators | — | register() an email-first creator account from a connector's sign-up. |
Alerts | Whether a creator's alerts reach one of their accounts. | Switch that account on or off for every alert class. |
Recovery | What the application keeps ready for a project's recovery on your connector. | registerStandby() a reserve place for a resource, replaceSpace() the place it lost. |
Support | Whether a project takes support messages; the thread behind a relay ping, a quoted relay message or a relay-space thread; the project's relay target. | ingest() a member's message, reply() with a creator's answer written on the platform, linkRelaySpace() / unlinkRelaySpace(). |
Refs and records
Two families of value object cross the boundary:
- Refs (
InstallationRef,IdentityRef,SpaceRef,ResourceRef,GrantRef,ProjectRef,CreatorRef,MemberRef,HandshakeRef) name a row the core already has: its UUID, the external id and, where you keep a row of your own, yourstorageRef. The core hands them to your ports and the Core API hands them back from every read and write. - Records (
InstallationRecord,IdentityRecord,SpaceRecord,GrantRecord,CreatorRegistration) describe what the core should write. Everyrecord()is idempotent on the natural key the page names: a second record of the same bot, account, place or grant updates the row rather than adding one, so a connector may record on every event and on every deploy.
Eloquent models never cross. A ref carries what a port needs to act; when a port needs more than a ref holds, the answer is a new field on the ref or a new read on the contract, never a query.
Exceptions
| Exception | Thrown by | Factories |
|---|---|---|
Subscriby\Connector\Exceptions\HandshakeRefused | Identities::completeHandshake() | expired(), identityHeld(), purposeNotSupported(), installationMismatch() |
Subscriby\Connector\Exceptions\RegistrationRefused | Creators::register() | emailTaken(), accountRefused() |
Subscriby\Connector\Exceptions\ResourceRefused | Resources::create(); the recovery writes that name a resource. | kindOutsidePlace(), placeUnknown(), projectUnknown(), resourceUnknown(), notPermitted(); read $reason. |
Subscriby\Connector\Exceptions\RecoveryRefused | Recovery::registerStandby(), Recovery::replaceSpace() | because(); read $reason and relay userMessage(), the core's translated sentence. |
Subscriby\Connector\Exceptions\SupportRefused | Support::ingest(), Support::reply(), the relay-space writes. | conversationUnknown(), projectUnknown(), installationUnknown(), spaceUnknown(), notPermitted(); read $reason. |
Subscriby\Connector\Exceptions\ConnectorNotRegistered | A contract asked about a connector key the registry lacks. | — |
Every other refusal is a null read: a find*() that answers null means the core knows no such row, and the connector decides what that means for the event in hand.
What the contracts cover
Installations, identities, spaces, resources, grants, creator registration, alert routing, recovery coverage with the standby and replacement writes and the support inbox in both directions. Everything a connector does against the core goes through these nine contracts, and the tutorial walks the calls in the order a connector makes them.
Authorisation is the core's
Every write on the Core API applies the same rules as the dashboard action behind it: a creator who may not link an identity to another creator's account is refused with the same exception whether they try on the web or from a chat. Your connector never checks a permission; it presents the facts and reads the answer.
How is this guide?
SpaceCatalog
How a creator picks a place to gate and whether the installation controls it — link requests by purpose, instructions, diagnosis, and what the SDK does not yet let a third party complete.
Installations
The installation rows as a connector may read and write them — finding by id, platform id or storage ref, listing a project's or the platform's, recording one, recording a health verdict, forgetting one.