Network triggers
A network trigger watches a connected source — a mailbox or a Microsoft Teams channel — and starts a network from a chosen template whenever a matching message arrives, with no person in the loop.
Every trigger belongs to the user who created it and runs with that user's identity, so a triggered run reaches exactly what its owner could reach by hand. All endpoints are scoped to the caller: you only ever see or change your own triggers. Before creating a trigger, connect its source under Integrations; List available sources reports which sources you have connected.
A trigger fires only on messages that arrive after it is enabled: the first poll records a starting position and matches nothing, so switching one on never replays a full inbox.
- GET /network-triggers/sources List available sources
- GET /network-triggers List triggers
- POST /network-triggers Create a trigger
- GET /network-triggers/{trigger_id} Retrieve a trigger
- PATCH /network-triggers/{trigger_id} Update a trigger
- DEL /network-triggers/{trigger_id} Delete a trigger
- GET /network-triggers/{trigger_id}/preview Preview a trigger
- POST /network-triggers/{trigger_id}/run Run a trigger now
- GET /network-triggers/{trigger_id}/events List trigger deliveries
Paths are relative to /api
The trigger object
One rule linking a source to a network template.
Attributes
-
idintegerThe trigger's unique identifier.
-
namestringA human-readable name.
-
sourcestringThe kind of source watched.
-
providerstringThe connected provider backing the source.
-
templateIdstringThe network template a match runs.
-
enabledbooleanWhether the trigger is active.
-
configobjectThe source-specific filter and settings.
-
lastPolledAtnullable stringWhen the trigger was last polled.
-
lastTriggeredAtnullable stringWhen the trigger last started a run.
-
lastErrornullable stringThe most recent error, or null.
-
createdAtnullable stringWhen the trigger was created.
-
updatedAtnullable stringWhen the trigger was last changed.
{
"id": 7,
"name": "Support mailbox",
"source": "email",
"provider": "ms365mail",
"templateId": "document_review",
"enabled": true,
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice"
},
"lastPolledAt": "2026-09-01T09:34:12Z",
"lastTriggeredAt": "2026-09-01T09:30:00Z",
"lastError": null,
"createdAt": "2026-08-20T11:00:00Z",
"updatedAt": "2026-09-01T09:34:12Z"
} List available sources
GET /api/network-triggers/sources
Returns the sources the caller can build a trigger on and whether each is connected.
Returns each source a trigger can watch, the providers that back it, and whether the caller has connected them. Use connected to decide whether to offer a source or send the user to connect it under Integrations first.
- Authentication
- Bearer token How it works
Parameters
No parameters.
Returns
Returns the available sources and their connection state.
Errors
- 503 The integration credential store is unavailable on this deployment.
curl "$VDF_BASE_URL/api/network-triggers/sources" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/sources`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/sources",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"sources": [
{
"source": "email",
"providers": [
{
"provider": "ms365mail",
"connected": true,
"account": "ada@example.com"
},
{
"provider": "email",
"connected": false,
"account": null
}
],
"connected": true
},
{
"source": "teams",
"providers": [
{
"provider": "ms365teams",
"connected": false,
"account": null
}
],
"connected": false
}
]
} List triggers
GET /api/network-triggers
Returns the caller's triggers, newest first.
Returns the triggers owned by the caller. Filter to one source with the source query parameter.
- Authentication
- Bearer token How it works
Query parameters
-
sourcestringReturn only triggers for this source.
Possible values-
email -
teams
-
Returns
Returns a list of trigger objects.
curl "$VDF_BASE_URL/api/network-triggers?source=email" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers?source=email`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
params={
"source": "email",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"triggers": [
{
"id": 7,
"name": "Support mailbox",
"source": "email",
"provider": "ms365mail",
"templateId": "document_review",
"enabled": true,
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice"
},
"lastPolledAt": "2026-09-01T09:34:12Z",
"lastTriggeredAt": "2026-09-01T09:30:00Z",
"lastError": null,
"createdAt": "2026-08-20T11:00:00Z",
"updatedAt": "2026-09-01T09:34:12Z"
}
]
} Create a trigger
POST /api/network-triggers
Creates a trigger that runs a template when a matching message arrives.
Creates a trigger for the caller. The source's provider must already be connected under Integrations, or the request is refused with 409. When provider is omitted, a connected provider for the source is chosen automatically. A new trigger starts enabled unless enabled is set to false; its first poll only records a starting position.
For a teams trigger, config must identify a channel with teamId and channelId, or a chat with chatId. For an email trigger, config may narrow matches with fromAddress, subjectContains, bodyContains, unreadOnly, and folder.
- Authentication
- Bearer token How it works
Body parameters application/json
-
sourcestring RequiredThe source to watch.
Possible values-
email -
teams
-
-
namestring RequiredA name for the trigger, 200 characters or fewer.
-
templateIdstring RequiredThe network template a match runs.
template_idis accepted as an alias. -
providerstringThe connected provider backing the source. Defaults to a connected provider for the source. Use
ms365mailoremailfor email,ms365teamsfor Teams. -
configobjectSource-specific filter and settings.
-
enabledbooleanWhether the trigger is active on creation.
Returns
Returns the created trigger object in trigger.
Errors
- 400 The definition is invalid: an unknown source or provider, a missing name or template, or a Teams trigger without a channel or chat.
- 409 The source's provider is not connected for the caller.
- 503 The integration credential store is unavailable on this deployment.
curl -X POST "$VDF_BASE_URL/api/network-triggers" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "email",
"name": "Support mailbox",
"templateId": "document_review",
"provider": "ms365mail",
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice"
},
"enabled": true
}' const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
source: 'email',
name: 'Support mailbox',
templateId: 'document_review',
provider: 'ms365mail',
config: {
fromAddress: 'customer@example.com',
subjectContains: 'invoice',
},
enabled: true,
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"source": "email",
"name": "Support mailbox",
"templateId": "document_review",
"provider": "ms365mail",
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice",
},
"enabled": True,
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"trigger": {
"id": 7,
"name": "Support mailbox",
"source": "email",
"provider": "ms365mail",
"templateId": "document_review",
"enabled": true,
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice"
},
"lastPolledAt": null,
"lastTriggeredAt": null,
"lastError": null,
"createdAt": "2026-09-01T09:30:00Z",
"updatedAt": "2026-09-01T09:30:00Z"
}
} Retrieve a trigger
GET /api/network-triggers/{trigger_id}
Returns one of the caller's triggers.
Returns a single trigger the caller owns.
- Authentication
- Bearer token How it works
Path parameters
-
trigger_idinteger RequiredThe trigger to retrieve.
Returns
Returns the trigger object in trigger.
Errors
- 404 No such trigger belongs to the caller.
curl "$VDF_BASE_URL/api/network-triggers/7" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/7`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/7",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"trigger": {
"id": 7,
"name": "Support mailbox",
"source": "email",
"provider": "ms365mail",
"templateId": "document_review",
"enabled": true,
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice"
},
"lastPolledAt": "2026-09-01T09:34:12Z",
"lastTriggeredAt": "2026-09-01T09:30:00Z",
"lastError": null,
"createdAt": "2026-08-20T11:00:00Z",
"updatedAt": "2026-09-01T09:34:12Z"
}
} Update a trigger
PATCH /api/network-triggers/{trigger_id}
Also available as PUT /api/network-triggers/{trigger_id}
Updates a trigger the caller owns. Supply only the fields you want to change; omitted fields keep their current values. A trigger's source cannot be changed. Re-enabling a trigger clears its last recorded error. PUT and PATCH behave identically.
- Authentication
- Bearer token How it works
Path parameters
-
trigger_idinteger RequiredThe trigger to update.
Body parameters application/json
-
namestringA new name, 200 characters or fewer.
-
templateIdstringA new network template.
template_idis accepted as an alias. -
providerstringA new provider for the source.
-
configobjectReplacement filter and settings.
-
enabledbooleanWhether the trigger is active.
Returns
Returns the updated trigger object in trigger.
Errors
- 400 The resulting definition is invalid.
- 404 No such trigger belongs to the caller.
curl -X PATCH "$VDF_BASE_URL/api/network-triggers/7" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enabled": false
}' const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/7`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
enabled: false,
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.patch(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/7",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"enabled": False,
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"trigger": {
"id": 7,
"name": "Support mailbox",
"source": "email",
"provider": "ms365mail",
"templateId": "document_review",
"enabled": false,
"config": {
"fromAddress": "customer@example.com",
"subjectContains": "invoice"
},
"lastPolledAt": "2026-09-01T09:34:12Z",
"lastTriggeredAt": "2026-09-01T09:30:00Z",
"lastError": null,
"createdAt": "2026-08-20T11:00:00Z",
"updatedAt": "2026-09-01T10:00:00Z"
}
} Delete a trigger
DEL /api/network-triggers/{trigger_id}
Permanently deletes a trigger the caller owns and its delivery history. This cannot be undone.
- Authentication
- Bearer token How it works
Path parameters
-
trigger_idinteger RequiredThe trigger to delete.
Returns
Returns success: true once the trigger is deleted.
Errors
- 404 No such trigger belongs to the caller.
curl -X DELETE "$VDF_BASE_URL/api/network-triggers/7" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/7`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.delete(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/7",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true
} Preview a trigger
GET /api/network-triggers/{trigger_id}/preview
Also available as POST /api/network-triggers/{trigger_id}/preview
Returns the messages a trigger would fire on now, without firing.
Polls the trigger's source and returns the messages that match its filter, without starting any run or advancing the trigger's position. Use it to confirm a filter before enabling a trigger. Preview always looks back over a recent window, even for a trigger that has never polled. GET and POST behave identically.
- Authentication
- Bearer token How it works
Path parameters
-
trigger_idinteger RequiredThe trigger to preview.
Returns
Returns the matches the trigger would fire on.
Errors
- 404 No such trigger belongs to the caller.
- 409 The trigger cannot poll: its source is not connected or its settings are incomplete.
- 502 The source could not be read.
curl "$VDF_BASE_URL/api/network-triggers/7/preview" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/7/preview`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/7/preview",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"matches": [
{
"externalId": "ms365mail:AAMkAGI2...",
"summary": "customer@example.com: Invoice 1042 query",
"occurredAt": "2026-09-01T09:29:00Z",
"preview": "From: Grace Hopper <customer@example.com>\nSubject: Invoice 1042 query\n..."
}
]
} Run a trigger now
POST /api/network-triggers/{trigger_id}/run
Polls a trigger once and dispatches any matching messages immediately.
Runs one poll-and-dispatch pass for a trigger the caller owns, the same pass the background poller performs on a schedule. Any matching message starts a network run as the trigger's owner, and each message is delivered at most once. Returns a report of what the pass did.
- Authentication
- Bearer token How it works
Path parameters
-
trigger_idinteger RequiredThe trigger to run.
Returns
Returns a report of the pass in report.
Errors
- 404 No such trigger belongs to the caller.
- 502 A matching message could not be dispatched to run its network.
curl -X POST "$VDF_BASE_URL/api/network-triggers/7/run" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/7/run`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/7/run",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"report": {
"triggerId": 7,
"name": "Support mailbox",
"polled": true,
"primed": false,
"matched": 1,
"dispatched": 1,
"skipped": 0,
"failed": 0,
"runIds": [
"trigger-7"
],
"error": ""
}
} List trigger deliveries
GET /api/network-triggers/{trigger_id}/events
Returns the recent deliveries recorded for a trigger.
Returns the trigger's recent deliveries, newest first — each message it acted on and what happened. The caller must own the trigger.
- Authentication
- Bearer token How it works
Path parameters
-
trigger_idinteger RequiredThe trigger whose deliveries to list.
Query parameters
-
limitintegerMaximum deliveries to return, from 1 to 200.
Returns
Returns the recent deliveries.
Errors
- 404 No such trigger belongs to the caller.
curl "$VDF_BASE_URL/api/network-triggers/7/events?limit=25" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/network-triggers/7/events?limit=25`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/network-triggers/7/events",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
params={
"limit": 25,
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"events": [
{
"id": 91,
"externalId": "ms365mail:AAMkAGI2...",
"status": "dispatched",
"runId": "trigger-7",
"summary": "customer@example.com: Invoice 1042 query",
"error": null,
"createdAt": "2026-09-01T09:30:00Z"
}
]
}