POST /api/decisions: Specter returns an outcome and records the decision for later retrieval, inspection,
and reporting.
Outcomes
Every decision resolves to one of four outcomes.
Specter is designed to fail open: if a backend errors or times out and the rule’s
on_error is allow,
Specter skips that backend rather than blocking the customer. See the rule engine.
The decision request
Every decision request has the same envelope, whatever schema it is decided against:string
default:"default"
Selects the active ruleset — and through it, the schema the rest of
the body is validated against. Always accepted; never part of the schema itself.
422 naming the path — without echoing the value of a regulated field.
The transaction payload
These are the fields of the built-in transaction schema, the payload every instance understands. A context whose ruleset binds a custom schema takes the fields of that schema here instead. Three are required; the rest are optional but enrich the evaluation. Fields that carry regulated data are marked in the API reference, and the marker — not the field’s name — governs how Specter validates, redacts, and retains the value.object
required
Payment credential —
type: "pan", "masked_pan", "sepa", or "paypal". A pan credential is only accepted on an
SAQ_D or ROC instance; on the default SAQ_A level it is rejected — see
Instance configuration.object
required
Must contain
id.object
required
Must contain
reference, amount (minor units), and currency (ISO 4217).object
IP address, fingerprint, user agent, session, and language.
object
Addresses forwarded to applicable backends.
object
Addresses forwarded to applicable backends.
array
Cart line items; each needs at least
name or sku.object
Travel data (passengers, legs) forwarded to backends that consume it.
object
Flat string key-value pairs, available to rules as
$.metadata.*. Forwarded to
backends and stored on the decision record, so treat it as data you share with
your backend providers.The decision response
string
The outcome.
object
The
(name, version) the decision was evaluated against — the binding of the ruleset that served it.
Version is absent for the built-in transaction schema.string
The ruleset that served the decision.
integer
The exact version pinned to the decision. Evidence replay uses this version, not whatever is
ACTIVE
later.array
Rules that fired, in evaluation order.
array
One entry per executed backend rule, including any error such as
insufficient_context. Present when the ruleset includes backend rules.string
HMAC-SHA256 identifier for the payment credential.The decision record
Every decision is recorded. Raw credential identifiers (PAN, IBAN, PayPal email) are never stored: the record keeps only the credential fingerprint and a masked form. Retrieve a past decision withGET /api/decisions/{id}; it carries the
same schema, ruleset_id, and ruleset_version attribution as the response, so you can tell which payload
type and which rules produced it.
Retention
Your instance configures a retention window, in days, per classification marker (pii, pci-pan,
pci-sad). Once a window has passed, every field of that scope reads as null on the record — for pii
that is customer_id, device_ip, and device_fingerprint — while the rest of the record is untouched.
any-scoped fields (amount, reference, masked credential, credential fingerprint) are never aged out, so an
old decision can still be correlated. A scope without a window is retained without bound. The boundary is
enforced on every read, not only when the background sweep runs.
backend_results[].raw_response is the backend’s own shape, so no marker resolves inside it: it is set to
null on the first configured window to expire. backend_reference is held outside the body and survives.
Evidence and replay
Two endpoints, both underdecisions:read, answer the first question anyone asks about a block — what value
made this rule fire:
GET /api/decisions/{id}/payloadreturns the request as it stood when the decision was evaluated, redacted per marker at write time:anyfields keep their value,piifields keep their path with a[REDACTED]sentinel, apci-panvalue is stored as its credential fingerprint, andpci-sadis never stored.GET /api/decisions/{id}/evidencereturns an evaluation trace in the same shape as a simulation: every rule of the pinned ruleset version with its outcome and, for each rule that fired, the evidence — the resolved operands of a comparison, the count / window / threshold of a velocity rule, the entry a blacklist rule matched. Evidence is replayed (the pinned ruleset re-evaluated against the stored payload, deterministically) where the input is frozen, and captured at decision time where it is not (counters, blacklist matches). Each entry says which, and whether replay reproduced it at full fidelity.
any, pii, pci-pan); the pii and pci-pan windows are bounded by the general
retention window of that scope, and turning a scope on is not retroactive. A decision with nothing stored
answers 200 with retained: false — a normal state, not an error. A decision made by the block-all
safeguard pins no ruleset, so its trace is null even when the payload was retained. Because the
regulated scopes are reduced at rest, the store holds no raw PAN and no SAD and is available on instances
below SAQ_D.
Resolving a REVIEW decision
AREVIEW decision is not final — it asks for a human judgement. Once your team has reviewed the transaction,
resolve it to record the accept/reject outcome and forward it to the backends that flagged it:
decisions:write scope.
- Only decisions with
decision: "REVIEW"can be resolved — others return422. - Each decision can be resolved once — a second attempt returns
409.
Request
string
required
accept or reject.string
Free-text note stored on the resolution.
Response
resolution is stored on the decision and returned by subsequent GET /api/decisions/{id} calls. Only
backends that produced a REVIEW result participate; Specter forwards the outcome to each through its
Link integration, and a backend that does not support resolution is
skipped.
Related
Rule engine
How rules combine to produce an outcome.
Lifecycle events
Feed transaction outcomes back to Specter and its backends.