Example application
This is the reference instrumentation example: an ATS-style webhook consumer where the entire Seamward integration is the observeWebhook call. Copy it into your own project; everything it needs is the collector package and your two runtime connection values.
The complete example
Code example
import Fastify from "fastify";import { createSeamwardCollector } from "@seamward/collector";
const collector = createSeamwardCollector({ connectionKey: process.env.SEAMWARD_CONNECTION_KEY!, ingestToken: process.env.SEAMWARD_INGEST_TOKEN!, policy: { version: "example-v1", dropFields: [], hashFields: ["candidate_email"], },});
const candidates = new Map<string, Record<string, unknown>>();
const handleCandidateWebhook = collector.observeWebhook( { routeTemplate: "/webhooks/candidates", }, async (payload) => { const candidate = payload as { id?: string }; if (typeof candidate.id !== "string") { return { statusCode: 400, outcome: { accepted: false } }; } candidates.set(candidate.id, candidate); return { statusCode: 202, eventType: "candidate.create", outcome: { accepted: true, businessObjectType: "candidate", businessObjectId: candidate.id, }, }; },);
const app = Fastify();app.post("/webhooks/candidates", async (request, reply) => { const result = await handleCandidateWebhook( request.body as Record<string, unknown>, ); return reply.code(result.statusCode ?? 200).send();});
await app.listen({ port: 4190 });
process.once("SIGTERM", async () => { await collector.stop(); process.exit(0);});Three things to notice:
- The business logic is untouched. The handler stores the candidate exactly as it would without Seamward; observation wraps it.
- The outcome is the contract.
accepted,businessObjectType, andbusinessObjectIdare what expected-outcome rules later match on; the malformed-payload branch records a rejection as a decision (400,accepted: false) rather than a crash. - PII is handled at the edge. The policy hashes
candidate_emailfor any pipeline that uses the redaction helpers, and payload values never ship regardless.
Run it against your workspace
- Select the workspace's Development environment and connect an Integration there instead of using Production.
- Set
SEAMWARD_CONNECTION_KEYandSEAMWARD_INGEST_TOKENin the example's environment. - Install the collector per the Node guide, start the app, and POST a candidate to
/webhooks/candidates. - Confirm the first observation from the integration page; the evidence you see contains fingerprints and hashes, and not one payload value.
Produce a known incident
With the example running, controlled changes produce each failure class on demand:
- Send the same payload with
idrenamed tocandidate_id: a structural finding. - Send
idas a number instead of a string: atype-changedfinding. - Create an expected-outcome rule for
candidate.create, then send an event whose downstream result never arrives: a missing-outcome incident after the rule's delay window.
Keep these experiments in the test integration; baselines are per-integration, so production evidence stays clean.
Observe another protocol
The same SDK wraps every protocol without changing your existing clients. Create a separate Integration and Connection-key-bound collector for each direction/protocol boundary:
| Operation | Collector entry point | Metadata you provide |
|---|---|---|
| Outbound HTTP API | observeFetch | stable route template, optional event type, request or response side |
| Inbound webhook | observeWebhook | stable route template, handler outcome |
| Queue publish | observeQueuePublish | stable queue or topic label |
| Queue consume | observeQueueConsumer | stable queue, topic, or subscription label |
| Scheduled import or export | observeScheduledFeed | stable feed label and direction |
The queue and scheduled-feed wrappers are broker-neutral; broker-specific adapters are not shipped. Follow the Node.js collector guide, PHP collector guide, or Laravel collector guide for runtime-specific examples.
Next steps
- Node collector guide: the full setup this example assumes.
- Collector SDK reference: every wrapper, result, and compatibility status.
- Detect silent business failures: what the outcome contract enables.
