Skip to content

Integrations

Integrations

Integrations bind external receive/send behavior to a collection. Each is one file beside the model, discovered automatically.

Definition

Declare an integration as named bindings in +integrations.ts — one binding per external system, each with its own receive and send behavior:

import { defineConnection, definePull } from '@norbital-ai/bolt/authoring';
import { Schema } from 'effect';
import type { Integrations } from './$types.js';

const accounting = defineConnection({
  baseUrl: 'https://erp.internal.example/api/v1',
  authentication: { type: 'bearer', token: { env: 'ACCOUNTING_TOKEN' } }
});

export default {
  accounting: {
    policies: ['sites_read', 'accounting_integration'],
    connection: accounting,
    receive: {
      invoices_changed: definePull({
        pull: { schedule: '15 * * * *', method: 'GET', path: '/invoices/changed' },
        records: { field: 'invoices' },
        input: Schema.Struct({ external_code: Schema.String, amount: Schema.Number }),
        identity: { column: 'external_code', value: (row) => row.external_code },
        map: (row) => ({ external_code: row.external_code, amount: row.amount })
      })
    },
    send: {
      confirm: {
        on: { update: ({ previous, record }) => previous.status !== record.status },
        send: { method: 'POST', path: '/sites/confirmed' },
        body: ({ record }) => ({ reference: record.name })
      }
    }
  }
} satisfies Integrations;

Connections stay with the host

Connections and secret values remain host facilities; tenant source declares requirements only — no credentials ever reach workspace code. See Facilities .

Choose the narrowest role

Companion roles overlap on purpose — pick the narrowest one that fits:

  • Write contract — mutation invariants and same-transaction effects ( write contract)
  • Pipelines — reusable bulk ingest and artifact contracts ( pipelines)
  • Integrations — reliable external delivery that reuses pipelines