Skip to content
Reference

Trigger API Reference

This page is not normative

This page is not considered a core part of the Vultron Protocol as proposed in the main documentation. Although within the page we might provide guidance in terms of SHOULD, MUST, etc., the content here is not normative.

The Vultron reference implementation exposes its general-purpose protocol trigger endpoints at POST /actors/{actor_id}/trigger/{behavior}; the table below is generated from the running application, so it lists every endpoint the build knows. Each endpoint initiates a protocol behavior on behalf of the specified actor; the decision to act has already been made by the caller. Every endpoint has one row in the trigger registry (vultron/trigger_registry/), which records its request model, use case, result type and whether it is general-purpose or demo-only.

All endpoints accept JSON request bodies, return HTTP 202 on success with the resulting ActivityStreams activity in the response body, and run behavior execution as a background task so the HTTP response is not blocked.

Interactive exploration

When running the reference implementation locally, visit /docs for an interactive Swagger UI over the same schema this page is generated from.

For a conceptual overview of how trigger endpoints fit into the two-surface integration model, see Wiring a Capability.


Report Management

For the workflow view, see How to Report a Vulnerability.

submit-report

POST /api/v2/actors/{actor_id}/trigger/submit-report

Creates a VulnerabilityReport in the actor's DataLayer and queues an RmSubmitReportActivity (Offer) to the specified recipient. An optional proposed_embargo_end_time states the Reporter's embargo terms for the report; the Offer then carries them as proposedEmbargo (EP-04-004). Returns the serialised offer so the caller can deliver it to the recipient's inbox.

Request body (SubmitReportRequest):

Field Type Required
report_name string Yes
report_content string Yes
recipient_id string Yes
proposed_embargo_end_time string No

ack-report

POST /api/v2/actors/{actor_id}/trigger/ack-report

Triggers the ack-report behavior for the given actor. Emits a Read(Offer(VulnerabilityReport)) activity (RK) to the reporter and returns it in the response body (TRIG-04-001). Only an actor the Offer was addressed to may acknowledge it; it may do so whether or not a case exists, and RK is never sent to the CASE_MANAGER (RMB-08-003).

Request body (AckReportRequest):

Field Type Required
offer_id string Yes
note string No

validate-report

POST /api/v2/actors/{actor_id}/trigger/validate-report

Triggers the validate-report behavior for the given actor. Invokes the ValidateReportBT tree via the bridge layer and returns the resulting ActivityStreams activity (TRIG-04-001).

Request body (ValidateReportRequest):

Field Type Required
offer_id string Yes
note string No

invalidate-report

POST /api/v2/actors/{actor_id}/trigger/invalidate-report

Triggers the invalidate-report behavior for the given actor. Emits a TentativeReject(Offer(VulnerabilityReport)) activity (RmInvalidateReportActivity) and returns it in the response body (TRIG-04-001). Persists a ParticipantStatus record with RM.INVALID for the actor and report.

Request body (InvalidateReportRequest):

Field Type Required
offer_id string Yes
note string No

reject-report

POST /api/v2/actors/{actor_id}/trigger/reject-report

Triggers the reject-report behavior for the given actor. Emits a Reject(Offer(VulnerabilityReport)) activity (RmCloseReportActivity) and returns it in the response body (TRIG-04-001). A non-empty note is required (TRIG-03-004). Persists a ParticipantStatus record with RM.CLOSED for the actor and report. Returns HTTP 409 if the report's RM state has no close edge (e.g. VALID; VP-02-004), or if a case holds the report, whose participants close their part in it with leave-case instead (CM-23-019, TRIG-13-001): nothing is emitted.

Request body (RejectReportRequest):

Field Type Required
offer_id string Yes
note string Yes

Case Management

For the workflow view, see How to Manage a Case.

create-case

POST /api/v2/actors/{actor_id}/trigger/create-case

Creates a local VulnerabilityCase attributed to the actor and queues a CreateCaseActivity in the actor's outbox for delivery to the CaseActor. An optional report_id links an existing VulnerabilityReport to the new case.

Request body (CreateCaseRequest):

Field Type Required
name string Yes
content string Yes
report_id string No
to list[string] No

engage-case

POST /api/v2/actors/{actor_id}/trigger/engage-case

Triggers the engage-case behavior for the given actor. Emits a Join(VulnerabilityCase) activity (RmEngageCaseActivity), addressed to the CASE_MANAGER, which records the actor's RM ACCEPTED; the actor's replica copies that status from the ledger, and returns the activity in the response body (TRIG-04-001).

Request body (CaseTriggerRequest):

Field Type Required
case_id string Yes

defer-case

POST /api/v2/actors/{actor_id}/trigger/defer-case

Triggers the defer-case behavior for the given actor. Emits an Ignore(VulnerabilityCase) activity (RmDeferCaseActivity), addressed to the CASE_MANAGER, which records the actor's RM DEFERRED; the actor's replica copies that status from the ledger, and returns the activity in the response body (TRIG-04-001).

Request body (CaseTriggerRequest):

Field Type Required
case_id string Yes

add-report-to-case

POST /api/v2/actors/{actor_id}/trigger/add-report-to-case

Links a VulnerabilityReport to an existing VulnerabilityCase and queues an AddReportToCaseActivity in the actor's outbox addressed to the case's CASE_MANAGER alone (PCR-08-005). Returns 422 and queues nothing when the case has no CASE_MANAGER.

Request body (AddReportToCaseRequest):

Field Type Required
case_id string Yes
report_id string Yes

add-object-to-case

POST /api/v2/actors/{actor_id}/trigger/add-object-to-case

Adds any existing AS2 object (identified by object_id) to a VulnerabilityCase and queues an Add(object, target=case) activity in the actor's outbox addressed to the case's CASE_MANAGER alone, which commits it and replicates it to the participants (PCR-08-005). The object must already exist in the actor's datalayer. Returns 422 and queues nothing when no receiver would route the object as an addition to the case, when its type has its own flow (EmbargoEvent, CaseParticipant, CaseStatus), or when the case has no CASE_MANAGER. Type-specific convenience triggers (e.g., add-report-to-case) delegate here after performing type validation (TRIG-10-001).

Request body (AddObjectToCaseRequest):

Field Type Required
case_id string Yes
object_id string Yes

leave-case

POST /api/v2/actors/{actor_id}/trigger/leave-case

Triggers the leave-case behavior for the given actor, which any participant of the case may call (TRIG-13-001). Runs the actor's PreCloseAction call-out, then queues a Leave(VulnerabilityCase) activity addressed to the case's CASE_MANAGER alone, and returns it in the response body (TRIG-04-001). The CASE_MANAGER decides what the Leave means: the Case Owner's Leave closes the case, and any other participant departs while the case stays open (CM-23-002, CM-23-003). Returns HTTP 409 and queues nothing when the caller is the Case Owner and its replica records an active embargo: terminate the embargo first (TRIG-13-003). Returns HTTP 422 and queues nothing when the PreCloseAction call-out fails (TRIG-13-002).

Request body (LeaveCaseRequest):

Field Type Required
case_id string Yes

Embargo Management

For the workflow view, see How to Establish an Embargo.

propose-embargo

POST /api/v2/actors/{actor_id}/trigger/propose-embargo

Triggers the propose-embargo behavior for the given actor. Creates a new EmbargoEvent and emits an EmProposeEmbargoActivity (Invite(EmbargoEvent)) activity. EM state transitions: N → P (new proposal) or A → R (revision). Returns the resulting activity in the response body (TRIG-04-001).

Request body (ProposeEmbargoRequest):

Field Type Required
case_id string Yes
note string No
end_time string Yes

accept-embargo

POST /api/v2/actors/{actor_id}/trigger/accept-embargo

Triggers the accept-embargo behavior for the given actor. A participant accepts the current (or specified) embargo proposal with Accept(Invite(EmbargoEvent)), which records its own consent and moves no EM state. The case owner's accept is its decision for the case, Accept(EmbargoEvent, target=Case), which activates the embargo (EM state → ACTIVE). Returns the resulting activity in the response body (TRIG-04-001).

Request body (AcceptEmbargoRequest):

Field Type Required
case_id string Yes
proposal_id string No

reject-embargo

POST /api/v2/actors/{actor_id}/trigger/reject-embargo

Triggers the reject-embargo behavior for the given actor. A participant rejects the current (or specified) embargo proposal with Reject(Invite(EmbargoEvent)), which records its own refusal and moves no EM state. A CASE_MANAGER that is not the owner records its own refusal as its Update(EmbargoConsent) of its row instead, and sends no Reject: the CASE_MANAGER's Reject of a proposal is its abandonment of it (MSM-07-004). The case owner's reject is its decision for the case, Reject(EmbargoEvent, target=Case), which rejects the proposal (EM state PROPOSED → NONE or REVISE → ACTIVE, or unchanged while another proposal is open). When the owner is also the CASE_MANAGER and rejects the last open revision while CS is public, exploited, or attacked, the rejection also terminates the embargo in the same act (EM → EXITED), committed as the Reject entry followed by the owner's ET Remove(EmbargoEvent) entry; a refused termination commits neither (MSM-07-009, EMB-04-002). Returns the resulting activity in the response body (TRIG-04-001).

Request body (RejectEmbargoRequest):

Field Type Required
case_id string Yes
proposal_id string No

propose-embargo-revision

POST /api/v2/actors/{actor_id}/trigger/propose-embargo-revision

Triggers the propose-embargo-revision behavior for the given actor. Proposes a revision to the active embargo by emitting an EmProposeEmbargoActivity activity. Only valid when EM state is ACTIVE or REVISE; use propose-embargo for initial proposals. EM state transitions: ACTIVE → REVISE or REVISE → REVISE. Returns the resulting activity in the response body (TRIG-04-001).

Request body (ProposeEmbargoRevisionRequest):

Field Type Required
case_id string Yes
note string No
end_time string Yes

terminate-embargo

POST /api/v2/actors/{actor_id}/trigger/terminate-embargo

Triggers the terminate-embargo behavior for the given actor. Ends the active embargo with a Remove(EmbargoEvent) activity. Updates the case EM state to EXITED and clears the active embargo. An EARLY request may name its cause (FIX_READY with its vendors, FIX_DEPLOYED or OTHER); one that names none is recorded as OTHER. A THREAT_SIGNAL cause, or any cause on END_TIME_REACHED, is refused with HTTP 422 (EMB-13-004, EMB-13-005). Returns HTTP 409 if no active embargo exists. Returns the resulting activity in the response body (TRIG-04-001).

Request body (TerminateEmbargoRequest):

Field Type Required
case_id string Yes
reason TerminationReason No
cause any No

Actor Participation

For the workflow view, see How to Manage Case Participants.

suggest-actor-to-case

POST /api/v2/actors/{actor_id}/trigger/suggest-actor-to-case

Emits a RecommendActorActivity addressed to the case owner (typically the CaseActor). The CaseActor then autonomously invites the suggested actor via RmInviteToCaseActivity.

Request body (SuggestActorToCaseRequest):

Field Type Required
case_id string Yes
suggested_actor_id string Yes
roles list[CVDRole] No

invite-actor-to-case

POST /api/v2/actors/{actor_id}/trigger/invite-actor-to-case

Sends the case owner's Offer of the invitee, with the offered roles, to the case's CASE_MANAGER, which emits and commits the Invite (ADR-0109). The case must exist in the actor's DataLayer.

Request body (InviteActorToCaseRequest):

Field Type Required
case_id string Yes
invitee_id string Yes
roles list[CVDRole] No

accept-actor-recommendation

POST /api/v2/actors/{actor_id}/trigger/accept-actor-recommendation

Emits an Accept(Offer(CaseParticipant)) from the Case Owner's identity addressed to the CaseActor, completing the ADR-0026 CM-16-006 approval step. The Offer(CaseParticipant) must already exist in the actor's DataLayer (delivered by the CaseActor).

Request body (AcceptActorRecommendationRequest):

Field Type Required
cp_offer_id string Yes
case_actor_id string Yes

accept-case-invite

POST /api/v2/actors/{actor_id}/trigger/accept-case-invite

Accepts an RmInviteToCaseActivity by emitting an RmAcceptInviteToCaseActivity queued in the actor's outbox for delivery to the case owner.

Request body (AcceptCaseInviteRequest):

Field Type Required
invite_id string Yes

reject-case-invite

POST /api/v2/actors/{actor_id}/trigger/reject-case-invite

Rejects an RmInviteToCaseActivity by emitting an RmRejectInviteToCaseActivity queued in the actor's outbox for delivery to the case owner.

Request body (RejectCaseInviteRequest):

Field Type Required
invite_id string Yes

offer-case-participant-role

POST /api/v2/actors/{actor_id}/trigger/offer-case-participant-role

Emits Offer(CaseParticipantRole, target=Actor, context=VulnerabilityCase) from the requesting actor. This is the canonical role-delegation wire format introduced by ADR-0039, replacing the deprecated offer-case-manager-role endpoint. The Offer is addressed to the case's CASE_MANAGER, which forwards it to the target. The role field is required, and the CASE_MANAGER refuses an Offer of CASE_OWNER or CASE_MANAGER (CM-33-003). See SE-08-003.

Request body (OfferCaseParticipantRoleRequest):

Field Type Required
case_id string Yes
target_actor_id string Yes
role CVDRole Yes

offer-case-ownership-transfer

POST /api/v2/actors/{actor_id}/trigger/offer-case-ownership-transfer

Emits the requesting Case Owner's proposal, an Offer(Offer(VulnerabilityCase)), to the case's CASE_MANAGER, which offers the case to the specified transferee on the owner's behalf. The case must exist in the actor's DataLayer. The transferee must also be known. The returned activity is the proposal, which the withdraw trigger names (TRIG-11-001).

Request body (OfferCaseOwnershipTransferRequest):

Field Type Required
case_id string Yes
transferee_id string Yes
content string No
end_time string No

accept-case-ownership-transfer

POST /api/v2/actors/{actor_id}/trigger/accept-case-ownership-transfer

Emits an Accept(Offer(VulnerabilityCase)) from the accepting actor to the case's CASE_MANAGER. The ownership transfer offer must already exist in the actor's DataLayer (TRIG-11-002, CM-21-006).

Request body (AcceptCaseOwnershipTransferRequest):

Field Type Required
offer_id string Yes

reject-case-ownership-transfer

POST /api/v2/actors/{actor_id}/trigger/reject-case-ownership-transfer

Emits a Reject(Offer(VulnerabilityCase)) from the declining actor to the case's CASE_MANAGER, which ledgers and broadcasts the decline. The ownership transfer offer must already exist in the actor's DataLayer (TRIG-11-005, CM-21-010, CM-21-012).

Request body (RejectCaseOwnershipTransferRequest):

Field Type Required
offer_id string Yes

withdraw-case-ownership-transfer

POST /api/v2/actors/{actor_id}/trigger/withdraw-case-ownership-transfer

Emits an Undo of the Case Owner's own ownership-transfer proposal to the case's CASE_MANAGER, which withdraws the offer it made from it, and ledgers and broadcasts the withdrawal, if the offer is still open. offer_id names the proposal, which must already exist in the actor's DataLayer (TRIG-11-006, CM-21-015).

Request body (WithdrawCaseOwnershipTransferRequest):

Field Type Required
offer_id string Yes

Reading path: You maintain a vulnerability tracker and want it to talk to your partners

This page is part of Build against the contract.

Before this page:

Back to the start of this reading path