Skip to main content

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.

FieldRequiredRules
keyYesTrimmed and normalized to lowercase; letters, numbers, and hyphens; 3–61 characters.
nameYesA non-empty display name.
versionYesBegins with a semantic major.minor.patch version.
capabilitiesYesA non-empty list of supported capability names.
webhookUrlNoAn endpoint URL associated with the integration when a webhook is configured.
metadataNoNon-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

CapabilityUse it for
navigationDeclares a navigation extension.
session-widgetDeclares a session-level extension or panel.
registration-hookDeclares registration-related extension behavior.
webhookDeclares 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:

OperationEndpoint
List edition pluginsGET /developer-platform/plugins
Read one pluginGET /developer-platform/plugins/:id
Register or updatePOST /developer-platform/plugins
DisablePATCH /developer-platform/plugins/:id/disable
EnablePATCH /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/webhooks to subscribe an edition to submission.created, registration.completed, or session.updated.
  • Use GET /integrations/webhooks/:id/deliveries to inspect delivery history.
  • Use PATCH /integrations/webhooks/:id/disable to 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/json
  • x-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.