Provider Keys (BYOK) & Skills
Two setup flows that other pages point at:
- BYOK — your own credentials for a third-party provider (OpenAI, Deepgram, ElevenLabs, Anthropic…), stored per workspace. Needed before a Release can use a provider Divinci does not front with its own key.
- Skills — instances of Divinci’s built-in integrations (calendar, email, SMS, web search). A Release’s tool loop attaches them by instance id, so the instance has to exist first.
They are independent — most skills need no BYOK — but they are both “do this before the thing you actually wanted to configure”.
BYOK: your own provider keys
Section titled “BYOK: your own provider keys”A BYOK record is one credential for one provider, scoped to one workspace.
31 of the 33 providers accept one (the exceptions are divinci and redis,
which are platform infrastructure).
// The credential's shape is per provider — openai wants apiKey (+ optional// organization), others want different fields entirely.const key = await divinci.byok.create(workspaceId, { name: "Production OpenAI", providerId: "openai", auth: { apiKey: "sk-...", organization: "org-..." },});
const { page, total } = await divinci.byok.list(workspaceId, { providerId: "openai" });await divinci.byok.update(workspaceId, key._id, { available: false }); // metadata onlyawait divinci.byok.delete(workspaceId, key._id);Rotating
Section titled “Rotating”Rotation replaces the credential in place, keeping the record’s id:
await divinci.byok.rotate(workspaceId, key._id, { auth: { apiKey: "sk-new-value..." },});Nothing that references the key needs re-pointing — RAG vectors, releases, and
tools all hold the BYOK id, not the secret. Use rotate() rather than
delete-and-recreate, which would orphan every consumer.
What is never returned
Section titled “What is never returned”The stored credential is encrypted at rest and never comes back from the
API. A record returns metadata only: name, providerId, available,
timestamps, and a keyPreview (a masked fragment, enough to tell two keys
apart). There is no endpoint that reads a workspace provider key back out.
When a key is required
Section titled “When a key is required”A tool declares which provider it needs, and whether it can use Divinci’s key:
useBYOK | Meaning |
|---|---|
| unset | Either Divinci’s platform key or yours |
"divinci-only" | Platform key only — BYOK is ignored |
"byok-only" | Your key is mandatory; the tool cannot run without one |
Around seventeen tools are byok-only today — chiefly the Vertex-hosted
third-party models (Grok, Qwen, Kimi, GLM, Jamba) and the Vertex Gemini
fine-tuners. Selecting one of these without a matching BYOK record leaves it
non-functional. For voice specifically, the Cloudflare-hosted TTS/STT options
run on the platform key while OpenAI Whisper, Deepgram, ElevenLabs and Cartesia
bill to yours — see
Channels & Access → Voice.
Skills: creating an instance
Section titled “Skills: creating an instance”A catalog integration is the Divinci-authored thing (google-calendar,
web-search). A skill instance is your configured copy of it. Releases
attach instances, never catalog entries.
// 1. See what existsconst catalog = await divinci.skills.listCatalog();// → [{ id: "google-calendar", label, authType: "oauth2", actions: [...], available }]
// 2. Create your instanceconst skill = await divinci.skills.create({ integrationId: "google-calendar", title: "Clinic bookings", instanceDescription: "Books 30-minute consults on the clinic calendar",});
// 3. skill.id is what a Release attachesEach catalog entry advertises its authType (oauth2 / api-key / basic),
its actions with their JSON Schemas, whether each action mutates, and an
available flag — an entry with available: false is present in the catalog but
not runnable.
Connecting an OAuth skill
Section titled “Connecting an OAuth skill”Three calls, with your redirect in the middle:
const { authorizeUrl, state } = await divinci.skills.startConnect( skill.id, "https://yourapp.example.com/oauth/callback",);// send the user to authorizeUrl; they come back with ?code=...
await divinci.skills.finishConnect(skill.id, { code, state, // the state from startConnect redirectUri: "https://yourapp.example.com/oauth/callback", // must MATCH exactly});
await divinci.skills.disconnect(skill.id); // revoke laterThe redirectUri passed to finishConnect must be identical to the one given
to startConnect — providers bind the authorization code to it, and a mismatch
fails the exchange.
Read connection state off the instance:
connection | Meaning |
|---|---|
connected | Ready |
expired | Was connected; token needs refreshing — reconnect |
disconnected | Never connected, or revoked |
not-required | This integration needs no auth |
Per-instance tool overrides
Section titled “Per-instance tool overrides”toolOverrides adjusts individual actions without forking the integration:
await divinci.skills.update(skill.id, { toolOverrides: { bookAppointment: { confirmationMessage: "Book {dateTime} for {durationMinutes} minutes?", requireConfirmation: true, }, },});requireConfirmation: true adds a confirmation stop to an action that would
not otherwise have one — useful for the self-directed actions (email-release,
sms-release) that skip the automatic floor. It cannot remove confirmation from
a mutating action; that floor is enforced server-side.
Attaching to a Release
Section titled “Attaching to a Release”Attaching is a Release update, not a skills call:
await divinci.releases.updateInWorkspace(workspaceId, releaseId, { skillConfig: { enabled: true, catalogSkills: { [skill.id]: ["bookAppointment", "getAvailabilities"] }, },});
// read back what a release has attachedconst attached = await divinci.skills.listForRelease(releaseId);Full loop configuration — the tool-calling model, iteration caps, MCP skills, and the confirmation model — is on Assistant Tools.
Gotchas
Section titled “Gotchas”- BYOK is per workspace; skills instances are per workspace. Cloning a Release into another workspace carries the ids but not the records they point at. Re-create both on the destination side.
available: falseon a BYOK record does not delete it. It withdraws the key from selection while keeping it (and its id) intact — the reversible way to take a credential out of service.- A skills catalog entry is not a promise.
available: falsemeans present but not runnable; check it before building a flow around an integration. email-usercannot be a workspace instance. It resolves recipients from the acting user’s identity, so it is refused on the release side and exists only as a user-owned skill. Release-owned emailing isemail-release.
Related
Section titled “Related”- Assistant Tools — the tool loop that calls these skills
- Channels & Access — the Release settings that consume provider keys
- Workspaces — where both records live