Reference
Triggers
A trigger tells Mobius when to start a loop. The loop is the saved plan. Each successful start creates a new run tied to the loop version that existed at that time.
Manual runs work a little differently from automatic triggers. Every loop can always be started with its Run button or through the API. You do not add, enable, or remove a manual trigger.
You can add any number of automatic triggers to a loop:
| Trigger | Use it when | Example |
|---|---|---|
| Schedule | A clock decides when work starts | Run a check every weekday at 9:00 AM |
| Event | A received event decides when work starts | Run when a pull request is opened |
| HTTP request | Your software directly asks Mobius to start | Start from an internal portal |
Each automatic trigger has its own Enabled switch. Keep new triggers disabled until the loop has completed safely with manual test input.
Create a safe test loop
Use the same harmless loop for the schedule and HTTP tests on this page:
- Open Build > Loops and select New loop.
- Name the loop
Trigger walkthrough. - Remove the Agent step that appears in the new loop.
- Select Add step > Sleep and set the duration to
1second. - Select Create, then select Run on the loop page.
- Confirm that the run reaches Completed and its Timeline shows one completed Sleep step.
Do not add an automatic trigger until this manual run succeeds. The test loop has no agent calls, integrations, or external side effects.
Test a schedule from end to end
- Return to the
Trigger walkthroughloop and select Edit loop. - Select Add trigger > Schedule.
- Under Runs, choose Every few minutes and
5 minutes. - Choose the intended Timezone and leave the trigger enabled.
- Select Save changes.
The loop page should show the enabled schedule. Within five minutes, a new item should appear under Recent runs. Open it and confirm:
- the run is Completed;
- Timeline shows the Sleep step completed; and
- Meta identifies the scheduled source and includes its scheduled time.
After the test, edit the loop, remove the five-minute schedule, and save. A manual run proves the loop works; only an automatic run proves the schedule works.
Manual runs
On a loop page, select Run to start with an empty event object. Use the arrow beside Run, then Run with event, when you want to provide JSON test data.
For example:
{
"ticket": {
"number": "T-104",
"priority": "high"
}
}The new run's Event tab should show the same object. Manual testing is a
safe way to check step references such as ${{ event.ticket.number }}, but it
does not test an automatic trigger's event matcher or condition.
Starting another manual run creates new work. If the loop sends messages or changes outside records, use test destinations and check for prior effects before running it again.
Schedules
A schedule stores both a recurrence and a timezone. The app provides common choices such as every few minutes, hourly, daily, weekdays, weekly, and monthly. It also lets advanced users edit the five-field cron expression.
The trigger defaults to weekdays at 9:00 AM in the browser's timezone. Review both values before saving. The summary beneath the controls shows the schedule Mobius will use.
A schedule may fire while an earlier run is still active. The loop's concurrency policy decides whether the new start runs in parallel, queues, skips, or replaces the earlier run. Configure that policy in the loop settings; it is not a schedule setting.
Events
An event trigger matches events that Mobius receives from a connected integration or from a project capability such as tables.
Test an event with a table row
This test uses only Mobius and the side-effect-free Trigger walkthrough loop.
First create a source for the test event:
- Open Build > Tables and select New table.
- Name it
trigger_walkthrough_events. - Name the first column
test_id. Leave its type asstring, and leave it marked Required and Identity. - Select Create.
Now add a trigger to the test loop:
-
Open Build > Loops > Trigger walkthrough and select Edit loop.
-
Select Add trigger > Event.
-
For Event source, choose Tables.
-
For Event type, choose
table.row.inserted. -
Select Add condition and enter:
event.data.test_id == "match-001" -
Turn the trigger off, select Save changes, and review the saved event type and condition on the loop page.
-
Edit the loop again, enable the trigger, and save.
Open Build > Tables > trigger_walkthrough_events, select Insert rows, keep JSON selected, and enter:
{
"test_id": "match-001"
}The preview should say Ready to insert 1 row. Select Insert row, return to the loop, and wait up to one minute for a new item under Recent runs. Open the run and confirm:
- Event contains
event.data.test_idwith the valuematch-001; - Meta contains
table_name: trigger_walkthrough_events; and - Timeline reaches Completed after the Sleep step.
This proves receipt, matching, run creation, and completion separately. To
check the negative case, insert a second row with test_id set to
no-match-001. Watch Recent runs and Trigger activity for one full
minute. Neither list should gain an item for that row, because the condition
returned false.
After the test, remove the event trigger from the loop and save. Then return to
Build > Tables and delete trigger_walkthrough_events.
Use events from an integration
The same trigger controls apply to connected systems. Choose the narrowest
event type that represents the work you want, then use Add condition to
filter fields from event or meta. Selecting a source initially matches
every event from that source, so narrow it before enabling the trigger.
Use the expression directly, without ${{ ... }}. A condition that returns
false creates neither a run nor a Trigger activity row. If the condition
cannot be evaluated, such as when a referenced field is missing, Mobius creates
a failed Trigger activity row and does not start a run.
Before enabling an integration trigger, open Library > Integrations, select the provider, and inspect a harmless sample under Recent events. That view confirms receipt and shows the actual payload in your project. After enabling the trigger and sending one uniquely identifiable test event, verify its run's Event, Meta, and Timeline just as you did for the table row.
Do not treat provider receipt as proof that the trigger matched, or treat a created run as proof that the loop completed. Disable or remove the trigger after the test.
The event catalog lists available event names and the normalized fields for project events.
HTTP triggers
An HTTP request trigger gives the loop a delivery URL. External software sends
a request to that URL with the event data for the run. Test it against the
harmless Trigger walkthrough loop:
- Edit the loop and select Add trigger > HTTP request.
- Turn that trigger's Enabled switch off, then select Save changes.
- On the loop page, copy the generated Delivery URL into a temporary entry in a password manager or another approved secret store. Clear the clipboard.
- Open Signing options > Generate signing secret.
- Add the full
whsec_...secret to the same temporary entry, then clear the clipboard. Mobius shows the secret only once. - Edit the loop again, enable the HTTP trigger, and save.
Without a signing secret, the loop page labels the endpoint Unsigned. Do not expose an unsigned trigger to an untrusted network: anyone who can call it may be able to start paid or side-effecting work. Treat both the URL and signing secret as sensitive configuration.
Run this Python 3 standard-library example. It prompts for both values at run time, hides them as you paste them, and does not put either value in the command or process arguments. Copy each value from the temporary secret-store entry only when prompted, then clear the clipboard again:
python3 - <<'PY'
import getpass
import hashlib
import hmac
import json
import urllib.request
url = getpass.getpass("Delivery URL: ").strip()
secret = getpass.getpass("Signing secret: ")
body = json.dumps(
{"test_id": "trigger-walkthrough"},
separators=(",", ":"),
).encode()
signature = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
request = urllib.request.Request(
url,
data=body,
method="POST",
headers={
"Content-Type": "application/json",
"X-Mobius-Signature": f"sha256={signature}",
"X-Idempotency-Key": "trigger-walkthrough-1",
},
)
with urllib.request.urlopen(request) as response:
print(response.status, response.read().decode())
PYThe response should be 202 Accepted with this shape:
{
"source_event_id": "sevt_...",
"status": "accepted",
"deduped": false
}202 proves that Mobius saved the incoming event; run creation happens
asynchronously. Return to the loop and wait up to one minute for a new Recent
runs item. Open it and confirm Event contains
test_id: trigger-walkthrough, Meta names the HTTP trigger, and Timeline
reaches Completed. If no run appears within a minute, continue with
Find where an automatic start stopped.
Run the same Python command again and paste the same values. The unchanged
idempotency key should immediately return the same source_event_id with
deduped: true. Watch Recent runs for one full minute and confirm that it
still contains only one HTTP run whose Event has
test_id: trigger-walkthrough. A real calling system must use a stable, unique
key for each logical event.
Next, prove that the signing secret is required. This command sends a different
event without X-Mobius-Signature:
python3 - <<'PY'
import getpass
import urllib.error
import urllib.request
url = getpass.getpass("Delivery URL: ").strip()
request = urllib.request.Request(
url,
data=b'{"test_id":"unsigned-should-fail"}',
method="POST",
headers={"Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(request) as response:
print(response.status)
except urllib.error.HTTPError as error:
print(error.code)
PYIt should print 401. Watch Recent runs and Trigger activity for one
full minute and confirm that neither list gains an item whose event has
test_id: unsigned-should-fail. A 401 response plus the absence of a run
proves that Mobius rejected the request before starting work.
Immediately before removing the trigger, return to its loop page and copy the complete Delivery URL into the temporary secret-store entry again. Clear the clipboard. Then edit the loop, remove the HTTP trigger, and save. Removing it invalidates the delivery URL and deletes that trigger's signing secret.
Prove that the old URL is revoked without sending the secret again:
python3 - <<'PY'
import getpass
import urllib.error
import urllib.request
url = getpass.getpass("Old delivery URL: ").strip()
request = urllib.request.Request(
url,
data=b"{}",
method="POST",
headers={"Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(request) as response:
print(response.status)
except urllib.error.HTTPError as error:
print(error.code)
PYThe command should print 404. Any other result means the endpoint was not
revoked as expected; return to the loop and confirm the HTTP trigger was
removed and the change was saved. After the 404, delete the temporary
secret-store entry and clear the clipboard.
The interactive API reference defines request
size limits, error responses, and how to find a run by source_event_id. Use
that contract before adding caller retries.
Some external products call any outbound HTTP delivery a “webhook.” In Mobius, the request entering Mobius is an HTTP request trigger. A webhook is the opposite direction: Mobius sends an event to your software.
Clean up the walkthrough
After finishing the schedule, event, and HTTP tests, the
Trigger walkthrough loop should have no automatic triggers. Keep it if you
want a side-effect-free test loop. Otherwise open its Loop actions menu,
select Delete loop, and confirm the deletion. Its existing test runs remain
available for inspection, but the loop cannot start new runs.
When starts collide
All trigger types use the loop's concurrency policy:
- Queue creates a queued run and starts it after the earlier active run reaches a final state.
- Skip records trigger activity but creates no run.
- Replace stops the earlier run and starts the new one. It does not undo an external action the earlier run already performed.
- Parallel allows both to run, subject to the organization's plan limit.
See Decide what happens when runs overlap for timing, version, and queue behavior. A broad event matcher or exposed HTTP URL can create many starts quickly, so choose concurrency before enabling it.
Find where an automatic start stopped
Use these records in order:
- Source receipt: does the provider's
Library > Integrations > provider > Recent events list the event, did the
test table insert the row, or did the HTTP caller receive
202 Accepted? - Loop > Recent runs: did that event create a run?
- Loop > Trigger activity: was an automatic start evaluated but blocked by a concurrency rule or run-start limit?
- Run > Timeline: did the created run complete its steps?
If the provider event exists but neither a run nor trigger activity appears,
check the selected project, the trigger's Enabled switch, event type, and
condition. A disabled trigger, event-type mismatch, or condition that evaluates
to false produces no activity row. A condition evaluation error, concurrency
skip, or rejected start does produce a row with its reason. If a run exists,
the trigger worked; diagnose the run itself.
For a schedule, also verify the saved timezone and recurrence. For an HTTP trigger, use the caller's HTTP response together with the API contract. The Source events guide covers the full provider path.