Setup
- Go to Integrations in the Bitfab portal.
- Under Scenarios, click Connect on the Scenario callback card.
- Enter the URL Bitfab should send to (https only) and a Signing secret of at least 16 characters.
- Click Save, then Test Connection. Bitfab sends a ping, and any 2xx answer passes.
The request
Bitfab sends aPOST with a JSON body:
scenario.trigger and scenario.data are null when the scenario has not been generated yet. rootSpan is null when the trace has no root span. environment is the environment the trace was recorded in, or null. callerMetadata is the metadata your code attached to the trace, {} when there is none.
When Bitfab does not send
Bitfab sends once per trace added to a dataset, and skips the trace when:- the trace is a replay. Its scenario belongs on the trace it replays;
- Bitfab builds the trigger for this trace function and it came out empty. Nothing is saved, so the scenario keeps showing the trace’s input and output.
{ "type": "ping", "version": 1, "organizationId": "..." }.
Bitfab may add fields to the request, and new type values, without raising version, so ignore the ones you do not know. version goes up only when a field you already read changes shape or meaning.
Verifying the signature
Every request carries aBitfab-Signature header:
v1 is the hex HMAC-SHA256 of <t>.<raw body>, keyed with your signing secret. Compute it over the raw body before parsing it, compare it in constant time, and reject requests whose t is more than a few minutes old.
The answer
Answer200 with a JSON object, or 204 when you have nothing to add. Every field is optional, and a field you leave out is left as it is. A field Bitfab does not know is refused, so a misspelled field fails loudly instead of being dropped.
A record looks like this:
kind is any name for the kind of record your systems hold, such as memory, order, or ticket. ref names the record in your systems. at is when it was written, or null. asOf is run when the record is as it was when the run started, and now when it is as it is today. quote is the exact text Bitfab looks for in the run’s spans, falling back to text when it is null.
The trigger
scenario.trigger is null until a trigger is saved, and records are refused until one is. Send it in the same answer as the records. History, missing items, and the actual outcome can be saved without a trigger, and the trigger stays unset until an answer sends one. Every field is required:
History and sources
Ahistory entry is one earlier fact, in time order:
role is thread start for the message that opened the thread and fact for anything else.
sources describes how a captured copy of your systems was read. Its shape is specific to captures Bitfab already reads, so leave it out unless Bitfab has asked you to send it.
Merge or replace
Leavemode out, or send merge, to add to what the scenario holds. Send replace when your answer is the full picture: each of records, history, and missing that you send replaces the saved one whole, so an empty list clears it. A list you leave out is kept in either mode, so { "mode": "replace", "records": [] } clears the records and nothing else.
Repeats inside one answer are dropped in both modes: identical records, history entries with the same kind and quote, and the same missing text.
In merge mode, sending the same answer twice leaves the scenario as it was after the first.
Describe the situation only. A scenario is read by the person who labels the run, so never say what the run should have done.