# Plug a service into OMNIA + NOUS

Open `/connect` for the visual Integration Studio. The protocol works with any service able to make HTTPS requests; provider-specific adapters and credentials are still required to retrieve data from closed providers. This is an integration foundation, not a promise of automatic improvement for arbitrary data.

## Contract v1

All endpoints return JSON. Use your deployment's bearer token and verified identity headers where configured. Keep credentials on your backend. The Studio accepts an API/account key and/or a signed OMAI identity token. Account keys scope services to that account. A shared root token represents one owner, not independent tenants. Production multi-owner deployments require the existing verified-identity configuration. Local development is one shared development boundary. Records are private.

| Method | Route | Input / output |
| --- | --- | --- |
| POST | `/v1/services` | `{name, metric, direction: "higher" or "lower", idempotencyKey}` → serviceId |
| GET | `/v1/services` | Owned services |
| POST | `/v1/services/{id}/runs` | `{text OR fluxId OR observations, variant, consent:{measure:true,store:true}, idempotencyKey}` → measurements, Flux ID, NOUS node ID, test hypotheses |
| GET | `/v1/services/{id}/runs` | Owned service runs and results |
| POST | `/v1/services/{id}/outcomes` | `{runId, value, idempotencyKey}` → one reported outcome per run |
| GET | `/v1/services/{id}/evaluation` | Baseline/variant counts, means, differences, exploratory intervals |

Use stable idempotency keys from your own event IDs. Retrying the same input returns the same result; changing input with the same key returns 409. Missing consent returns 403; unknown/unowned resources return 404. Text is limited to 100,000 characters. Exactly one of text, fluxId, or observations is required.

## JavaScript

```js
import { OmniaClient } from './sdk/omnia-client.js';
const omnia = new OmniaClient({baseUrl: process.env.OMNIA_URL, token: process.env.OMNIA_TOKEN});
const service = await omnia.register({
  name: 'Support assistant', metric: 'Resolution minutes',
  direction: 'lower', idempotencyKey: 'support-registration-v1'
});
const run = await omnia.run(service.serviceId, {
  text: 'Authorized support response goes here.', variant: 'baseline',
  consent: {measure:true, store:true}, idempotencyKey: 'ticket-123-baseline'
});
// Read the actual outcome from your service; do not invent one from an OMNIA score.
await omnia.outcome(service.serviceId, {
  runId: run.runId, value: 12, idempotencyKey: 'ticket-123-resolution'
});
const comparison = await omnia.evaluate(service.serviceId);
```

## Audio, image, video, sensors, and other data

- WAV/PNG/text: upload using `POST /v1/jobs`, retain the job ID, poll until completed, then send its `fluxId` to a service run. Existing consent and retention headers apply.
- Video: `client.uploadVideo(file, {onProgress})` supports MP4/MOV/WebM/MKV up to 2 GiB and 65 seconds. Store the progress callback's jobId; after interruption reselect the identical file and pass that ID. On completion use `job.integration.fluxId` in a service run. Video originals are removed after analysis; derived records remain.
- Sensors and structured observations: submit `observations` (1–256 entries) instead of text or fluxId. Each entry declares `evidenceClass`, `quantityKind`, `value`, `unit`, `method`, and `methodVersion`, with optional calibration and uncertainty. The existing measurement validator creates a manifest and a Flux-backed service run. Example: `{evidenceClass:"derived_signal", quantityKind:"request latency", value:120, unit:"ms", method:"service-timer", methodVersion:"v1"}`. Do not mislabel model inferences as physical measurements.
- Closed services: your backend obtains authorized data using its existing provider integration. OMNIA does not obtain access just because the service is registered.

## What the service receives

Text enters the existing structural analyzer, private Flux store, measurement manifests, NOUS graph, and pipeline trace. Existing Flux inputs must be readable by the same owner. The response contains observed features, normalized measurements, lineage references, and conditional text-structure test ideas. These are hypotheses, not semantic truth or business-value scores. Video may have no calibrated E/F/V scores; its raw measurements remain available.

A baseline run must use variant `baseline`. Give an alternative a stable name such as `shorter-response-v1`; apply the change in your service and report the actual success metric. At least five outcomes in each group unlock an exploratory comparison. Approximate normal intervals on differences of means are descriptive at small sample sizes; nonrandomized groups, repeated looks, correlated observations, and multiple variants can mislead. Use randomized holdouts and a prespecified evaluation before rollout. The system does not automatically modify an external service.

## Operational limits

Registrations, run receipts, and outcomes persist in `data/service-integrations.json` using atomic replacement and serialized writes. This prototype store targets a single server process; multi-replica operation requires a transactional database. There are no outbound webhooks: pull results through the API. Raw text is not retained by this layer, although structural measurements and service results are retained. Existing source-retention and authorization rules still apply. Audio/text/image upload queues remain in-memory; video uploads and analysis support restart recovery.
