Version

Copilot

Subscriby Copilot as a connector's creator surface reaches it — where the creator stands, a message that opens the connector's own thinking display at once and runs on the queue, a confirmation card answered by its id, and the surface port the answer streams back through.

Subscriby\Connector\Core\Copilot. Subscriby Copilot is the operator over a creator's own tools: it answers from live data and does the creator's routine work, with a confirmation before anything destructive runs. On the dashboard it lives in a panel beside every page; on a platform that has a conversation with creators it lives in that conversation, and this contract is how a connector hands it a message. Every call takes the CreatorRef of the account that is talking and runs as that creator, so whether they may use the Copilot (the copilot:use team permission), whether a turn can be paid for (the plan's monthly allowance, then Copilot Credits) and what the turn may do (the creator's own abilities, through the same tools the REST API and the MCP server expose) are decided by the core exactly as for the panel.

A turn never runs inside your request. ask() checks the creator and the credit, opens your display through your CopilotSurface port in the same call, so the creator sees the Copilot thinking before any model has answered, and runs the model on the queue; the worker repaints your display as the model streams and ends it with the answer. You park the thread the ticket names and hand it back with the next message. Nothing of the answer comes back from ask() itself.

standing()

$standing = $this->copilot->standing($creator);

$standing->allowed;         // false when the creator's team role lacks copilot:use
$standing->freeTurnsLeft;   // 10 on Free, 25 on Starter, 50 on Growth, counting down through the month
$standing->credit;          // "$12.50", the Copilot Credits balance formatted
$standing->exhausted;       // true when the allowance and the credit are both spent

The line a surface prints before the first question. A creator with no plan can still hold Copilot Credits (a pack bought earlier, a promotion), so a surface asks for an account rather than for a plan and lets the core refuse by credit.

ask()

use Subscriby\Connector\Data\CopilotAsk;

$ticket = $this->copilot->ask($creator, new CopilotAsk(
    installation: $bot->installationRef(),   // the installation the creator is talking through
    account: $chat->identityRecord(),        // the account that is talking
    message: $text,                          // as typed, or as the tapped button read
    threadId: $state->threadId(),            // the thread the last ticket named, or null
    projectId: $state->projectId(),          // the project the conversation is about, when opened from one
    newThread: false,                        // true to leave the thread for a fresh one
    showQuestion: false,                     // true when the message came from a button, so the answer repeats it
));

$state->recordThread($ticket->threadId);

The order of checks: the creator's role (not_allowed), the credit (credit_exhausted, cap_reached), the message (message_invalid: empty or over the configured length), then the installation and the account (surface_unavailable: the installation is unknown or not operational, its connector declares no copilot or binds no surface, or the creator holds no account on it), then the thread: the one named while the creator still holds it, else a new one, about projectId when given (project_unknown when the creator may not see it). A thread the core has pruned is replaced, never refused, because a surface only parks what it was last told. Then begin() on your surface, and the turn is queued. A surface that throws from begin() stops the turn before anything is charged: a turn nobody can see is not worth paying for.

decide()

use Subscriby\Connector\Data\CopilotDecision;

$ticket = $this->copilot->decide($creator, new CopilotDecision(
    installation: $bot->installationRef(),
    account: $chat->identityRecord(),
    actionId: $data->get('id'),              // the card's id, as your button carried it
    approve: true,
));

A card is named by its id alone: the core finds the thread behind it and checks the creator owns it, so a button carries nothing but the id. A cancel settles the card at once, runs nothing, charges nothing and answers null; a confirm checks the credit, opens your display and queues the continuation like a turn, answering the thread it runs in. A card already answered, or never the creator's, is action_unknown; one that waited past its ten minutes is action_expired.

What a turn costs

A turn draws one unit from the creator's monthly allowance, then from their Copilot Credits; a turn past four tool steps draws two; a confirmation is a turn; a cancel is free; a turn whose model failed is not charged, and your display is told so through fail(). The connector never sees a price and never charges anything.

Refusals

Every method throws Subscriby\Connector\Exceptions\CopilotRefused. getMessage() is the core's sentence in the creator's language; reason is stable and yours to branch on: creator_unknown, not_allowed, credit_exhausted, cap_reached, message_invalid, project_unknown, thread_unknown, action_unknown, action_expired, surface_unavailable. A surface treats creator_unknown as missing information, answers credit_exhausted and cap_reached with the way to top up (the dashboard's Billing page, signed in), and relays the rest.

What is not here

The answer, the thinking, the tools, the links and the follow-ups reach you through CopilotSurface, never as a return value. Threads are the core's, listed on the dashboard and pruned after ninety idle days; the operator's tools are the core's own catalogue under the creator's abilities; and nothing here lets a member talk to the Copilot, because a member surface is a separate contract with no tools at all.

Park nothing but the thread and the project

The thread id and the project the conversation is about are the two things a surface keeps between messages; the follow-up buttons of the last answer are the third, kept by your own surface because their words never fit in callback data. Everything else is read fresh from the core.

How is this guide?

Last updated on

Version

On this page

Subscriby is a product
designed by you — for you.
No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request

For AI agents: llms.txt · llms-full.txt