Plugin Integration
This guide is for an external developer building a plugin or connected service for an ARBEC conference. It covers the currently released contract: manifest registration, API-key access to published agenda data, and signed webhooks.
:::note Current rollout status
The current API can register, list, enable, and disable plugin manifests. The public SDK package, runtime loader, plugin execution hooks, and self-service developer portal are staged capabilities and are not yet part of this public docs release. A manifest does not upload or execute third-party code.
:::
Roles and authorization
External developers build and operate the integration. An authorized conference manager performs the organization-level setup because the current manifest, API-key, and webhook-management endpoints require conference management permission.
Do not ask an external developer to share a personal admin token with plugin code. The conference organization should make the registration and credential handoff through its own secure process.
Before you integrate
Agree these values with the conference organization:
- an authorized operator who can register the integration
- an organization, conference, and edition context
- a stable plugin key and semantic version
- at least one supported capability
- the API scopes the companion service needs
- a public HTTPS endpoint if webhooks are required
Plugin records are scoped by organization, conference, and edition. A plugin registered for one edition must not be treated as globally available to every conference.
Manifest contract
Register a manifest with POST /developer-platform/plugins.
| Field | Required | Rules |
|---|---|---|
key | Yes | Trimmed and normalized to lowercase; letters, numbers, and hyphens; 3–61 characters. |
name | Yes | A non-empty display name. |
version | Yes | Begins with a semantic major.minor.patch version. |
capabilities | Yes | A non-empty list of supported capability names. |
webhookUrl | No | An endpoint URL associated with the integration when a webhook is configured. |
metadata | No | Non-secret JSON metadata for the owning edition. |
The API trims the key, name, version, and webhook URL, normalizes the key to lowercase, removes duplicate capability entries, and stores the manifest in the current edition context. Registering the same key again updates that edition's manifest and marks it active.
Supported capabilities
| Capability | Use it for |
|---|---|
navigation | Declares a navigation extension. |
session-widget | Declares a session-level extension or panel. |
registration-hook | Declares registration-related extension behavior. |
webhook | Declares webhook-based extension behavior. |
The capability list is intentionally explicit. If a capability is not listed here, the manifest validator rejects it.
Register a plugin
An authorized conference manager sends the registration request with the platform's normal bearer token. The token is not a plugin runtime credential.
POST /developer-platform/plugins
Authorization: Bearer <authenticated-token>
Content-Type: application/json
{
"key": "agenda-insights",
"name": "Agenda Insights",
"version": "1.0.0",
"capabilities": ["session-widget", "webhook"],
"webhookUrl": "https://example.test/hooks/arbec",
"metadata": {
"owner": "conference-technology-team"
}
}
On success, the response contains the stored plugin record with an active
status. The response includes the generated plugin id, which is required for
lifecycle operations.
Manage the plugin lifecycle
Use the returned plugin id for lifecycle operations:
| Operation | Endpoint |
|---|---|
| List edition plugins | GET /developer-platform/plugins |
| Read one plugin | GET /developer-platform/plugins/:id |
| Register or update | POST /developer-platform/plugins |
| Disable | PATCH /developer-platform/plugins/:id/disable |
| Enable | PATCH /developer-platform/plugins/:id/enable |
Disabling a plugin keeps its manifest available for inspection while marking it inactive. Re-enable it only after the integration has passed its edition-level checks.
Create an API key for a companion service
API keys belong to the organization rather than to an individual edition. An authorized operator creates one with the scopes required by the service:
POST /integrations/api-keys
Authorization: Bearer <authenticated-token>
Content-Type: application/json
{
"label": "Agenda companion app",
"scopes": ["agenda:read"],
"expiresAt": "2027-01-31T00:00:00.000Z"
}
The response contains the secret once. Store it in a secret manager, never in
source control, browser code, or plugin metadata. Use PATCH /integrations/api-keys/:id/revoke to revoke a key that is no longer needed.
Read the public agenda
Use the API key against an edition owned by the same organization:
GET /api/public/v1/editions/<edition-id>/agenda
x-api-key: arbec_<api-key-secret>
The response contains published sessions ordered by start time. The
agenda:read scope is required; invalid, expired, or revoked keys are
rejected.
The same data is available through POST /graphql/public with
Authorization: Bearer arbec_<api-key-secret>. The current GraphQL schema
supports the agenda(editionId) query and does not support subscriptions.
Connect webhooks
Plugin registration and external integrations are separate surfaces:
- Use
POST /integrations/webhooksto subscribe an edition tosubmission.created,registration.completed, orsession.updated. - Use
GET /integrations/webhooks/:id/deliveriesto inspect delivery history. - Use
PATCH /integrations/webhooks/:id/disableto stop future deliveries.
Create a subscription with a public HTTPS target and a signing secret:
POST /integrations/webhooks
Authorization: Bearer <authenticated-token>
Content-Type: application/json
{
"eventType": "session.updated",
"targetUrl": "https://example.test/hooks/arbec",
"secret": "store-this-in-your-secret-manager"
}
The target URL must use HTTPS and cannot resolve to localhost or a private network address. The secret is encrypted for storage and is never returned as plain text by the subscription list endpoint.
Each delivery is a JSON POST with:
content-type: application/jsonx-arbec-event: <event-name>x-arbec-signature: sha256=<hex-digest>
The signature is an HMAC-SHA256 digest of the exact request body using the subscription secret. Verify it before parsing or processing the payload:
import {createHmac, timingSafeEqual} from 'node:crypto';
export function isValidArbecSignature(
rawBody: string,
header: string | undefined,
secret: string,
): boolean {
if (!header?.startsWith('sha256=')) return false;
const expected = createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const received = header.slice('sha256='.length);
return received.length === expected.length &&
timingSafeEqual(Buffer.from(received), Buffer.from(expected));
}
Return a 2xx response after accepting a delivery. ARBEC records the response status, response body, request payload, and duration in delivery history. A delivery that fails or returns a non-2xx status increments the subscription's retry counter; the current dispatcher does not promise a fixed retry schedule.
Keep secrets separate
Keep admin tokens, API keys, and webhook secrets outside the manifest. Use
metadata only for descriptive, non-secret values that help the organization
operate the integration.
Integration checklist
Before enabling a plugin in a live edition, verify:
- the manifest key and version identify the intended release
- every capability is required by the integration
- the plugin is registered in the correct edition context
- webhook endpoints validate signed deliveries before processing payloads
- API keys have only the scopes the integration needs and an expiry when one is appropriate
- the disable path has been tested and the integration can recover cleanly
For the broader extension model and planned SDK direction, continue with Plugin System. For the public API surfaces, see API Overview.