[{"data":1,"prerenderedAt":912},["ShallowReactive",2],{"guide:en:automations":3},{"id":4,"title":5,"body":6,"description":904,"extension":905,"meta":906,"navigation":907,"path":908,"seo":909,"stem":910,"__hash__":911},"guide_en/en/user/automations/index.md","Automations & Monitoring",{"type":7,"value":8,"toc":877},"minimark",[9,13,39,52,57,60,135,139,165,176,180,194,199,202,364,368,371,391,395,500,523,527,537,579,602,606,610,620,624,631,634,663,666,679,683,692,711,714,725,765,794,798,805,809,825,829,834,852,856,863,867],[10,11,5],"h1",{"id":12},"automations-monitoring",[14,15,16,17,21,22,25,26,29,30,34,35,38],"p",{},"Automations is Aptli's integration layer — the way your deployment reacts to what happens inside it and connects to systems outside it. It covers four things: ",[18,19,20],"strong",{},"rules"," that fire actions when events occur, ",[18,23,24],{},"hooks"," that push events to other systems, ",[18,27,28],{},"ingestion"," that pulls sensor and device data ",[31,32,33],"em",{},"in",", and ",[18,36,37],{},"monitoring"," that turns that incoming data into readings, charts, and alarms.",[14,40,41,42,45,46,51],{},"Automations is ",[18,43,44],{},"included in every plan",". What's metered is the number of external connections you wire up — see ",[47,48,50],"a",{"href":49},"#the-connection-allowance","The connection allowance"," below.",[53,54,56],"h2",{"id":55},"the-pages-at-a-glance","The pages at a glance",[14,58,59],{},"Automations lives in its own navigation group with four pages:",[61,62,63,79],"table",{},[64,65,66],"thead",{},[67,68,69,73,76],"tr",{},[70,71,72],"th",{},"Page",[70,74,75],{},"Tabs",[70,77,78],{},"What it's for",[80,81,82,96,109,122],"tbody",{},[67,83,84,90,93],{},[85,86,87],"td",{},[18,88,89],{},"Automations",[85,91,92],{},"Hooks · Event Triggers · Ingestion",[85,94,95],{},"Build outbound hooks, event-driven rules, and inbound data connectors.",[67,97,98,103,106],{},[85,99,100],{},[18,101,102],{},"Credentials",[85,104,105],{},"Outbound credentials · Inbound ingest keys",[85,107,108],{},"Store the secrets outbound actions use, and mint the API keys senders use to push data in.",[67,110,111,116,119],{},[85,112,113],{},[18,114,115],{},"Deliveries",[85,117,118],{},"Outbound deliveries · Inbound runs",[85,120,121],{},"A read-only activity log of everything sent out and pulled in.",[67,123,124,129,132],{},[85,125,126],{},[18,127,128],{},"Alarms",[85,130,131],{},"—",[85,133,134],{},"The live ledger of threshold and silence alarms.",[53,136,138],{"id":137},"hooks-the-quick-way-to-push-events-out","Hooks — the quick way to push events out",[14,140,141,142,145,146,149,150,153,154,149,157,160,161,164],{},"A ",[18,143,144],{},"hook"," is a signed destination subscribed to the events you pick. It's the simplest outbound integration: give it a ",[18,147,148],{},"Name",", a ",[18,151,152],{},"Destination URL",", the ",[18,155,156],{},"Events to send",[18,158,159],{},"Signing secret"," (so the receiver can verify the payload came from you), and — optionally — a ",[18,162,163],{},"Payload template",". Every matching event is POSTed to that URL. No conditions, no branching; just \"send these events there.\"",[14,166,167,168,171,172,175],{},"Use a hook when another system just needs to ",[31,169,170],{},"know"," something happened. Reach for an ",[18,173,174],{},"Event Trigger"," (below) when you need conditions or a non-webhook action.",[53,177,179],{"id":178},"event-triggers-rules-that-do-something","Event Triggers — rules that do something",[14,181,182,183,185,186,189,190,193],{},"An ",[18,184,174],{}," is the full ",[18,187,188],{},"trigger → conditions → actions"," engine. When an event fires and the conditions pass, one or more actions run. Start a new one from the ",[18,191,192],{},"What should happen automatically?"," recipe gallery, or drop into the full editor.",[195,196,198],"h3",{"id":197},"triggers","Triggers",[14,200,201],{},"Triggers are grouped by the part of Aptli they come from. A selection:",[203,204,205,232,249,266,283,303,316,335,349],"ul",{},[206,207,208,211,212,216,217,216,220,216,223,216,226,216,229],"li",{},[18,209,210],{},"Work"," — ",[213,214,215],"code",{},"workOrder.created",", ",[213,218,219],{},"workOrder.statusChanged",[213,221,222],{},"report.completed",[213,224,225],{},"report.validated",[213,227,228],{},"report.rejected",[213,230,231],{},"validation.statusChanged",[206,233,234,211,237,216,240,216,243,216,246],{},[18,235,236],{},"Projects & jobs",[213,238,239],{},"project.created",[213,241,242],{},"project.statusChanged",[213,244,245],{},"job.created",[213,247,248],{},"job.removed",[206,250,251,211,254,216,257,216,260,216,263],{},[18,252,253],{},"Inventory",[213,255,256],{},"inventory.created",[213,258,259],{},"stock.adjusted",[213,261,262],{},"stock.transferred",[213,264,265],{},"stock.low",[206,267,268,211,271,216,274,216,277,216,280],{},[18,269,270],{},"Imports & versions",[213,272,273],{},"geo.import.completed",[213,275,276],{},"geo.import.failed",[213,278,279],{},"version.submittedForReview",[213,281,282],{},"version.committed",[206,284,285,211,288,216,291,216,294,216,297,216,300],{},[18,286,287],{},"Users, files, help requests",[213,289,290],{},"user.invited",[213,292,293],{},"file.uploaded",[213,295,296],{},"file.quarantine_failed",[213,298,299],{},"helpRequest.created",[213,301,302],{},"helpRequest.statusChanged",[206,304,305,211,308,311,312,315],{},[18,306,307],{},"Sensor data",[213,309,310],{},"sensor.reading"," (fires once per ingest ",[18,313,314],{},"batch",", carrying that batch's aggregates — the bridge from ingestion to automation)",[206,317,318,211,320,323,324,327,328,330,331,334],{},[18,319,128],{},[213,321,322],{},"alarm.raised"," and ",[213,325,326],{},"alarm.resolved"," (§293). Unlike ",[213,329,310],{},", these carry the ",[18,332,333],{},"full action palette",", so a breach can create a work order, update a field, or notify someone — not just fire a hook",[206,336,337,211,340,216,343,216,346],{},[18,338,339],{},"Scheduled",[213,341,342],{},"schedule.daily",[213,344,345],{},"schedule.weekly",[213,347,348],{},"schedule.monthly",[206,350,351,211,354,216,357,216,360,363],{},[18,352,353],{},"SLA timers",[213,355,356],{},"timer.threshold",[213,358,359],{},"timer.expired",[213,361,362],{},"timer.escalated"," (emitted by running lifecycle timers)",[195,365,367],{"id":366},"conditions","Conditions",[14,369,370],{},"Conditions narrow when a trigger fires, evaluated against the event context and ANDed together (all must pass):",[203,372,373,379,385],{},[206,374,375,378],{},[213,376,377],{},"workOrder.status == 'completed'"," — only on completion",[206,380,381,384],{},[213,382,383],{},"actor.email endsWith '@myorg.com'"," — only internal users",[206,386,387,390],{},[213,388,389],{},"job.featureCount > 1000"," — only large imports",[195,392,394],{"id":393},"actions","Actions",[61,396,397,407],{},[64,398,399],{},[67,400,401,404],{},[70,402,403],{},"Action",[70,405,406],{},"Does",[80,408,409,423,433,443,456,466,476,486],{},[67,410,411,420],{},[85,412,413,416,417],{},[18,414,415],{},"Send notification"," / ",[18,418,419],{},"Send email",[85,421,422],{},"Notify a user, role, or the record's creator/assignee",[67,424,425,430],{},[85,426,427],{},[18,428,429],{},"Call webhook",[85,431,432],{},"POST a signed JSON payload to an external URL",[67,434,435,440],{},[85,436,437],{},[18,438,439],{},"Write to Postgres",[85,441,442],{},"Run a parameterised write against an external PostgreSQL database",[67,444,445,450],{},[85,446,447],{},[18,448,449],{},"Deliver artifact",[85,451,452,453],{},"Export the triggering records (JSON/CSV/GeoJSON) to a directory, S3-compatible bucket, or webhook. ",[31,454,455],{},"(SFTP is selectable but not yet functional — a delivery to it is logged as failed.)",[67,457,458,463],{},[85,459,460],{},[18,461,462],{},"Create work order / assignment / job",[85,464,465],{},"Spawn a fulfillment record",[67,467,468,473],{},[85,469,470],{},[18,471,472],{},"Update field",[85,474,475],{},"Set a field on the triggering record",[67,477,478,483],{},[85,479,480],{},[18,481,482],{},"Run calculation",[85,484,485],{},"Execute a configured calculation rule",[67,487,488,493],{},[85,489,490],{},[18,491,492],{},"Start SLA timer",[85,494,495,496,499],{},"Start a lifecycle timer on the record (which later emits the ",[213,497,498],{},"timer.*"," triggers)",[14,501,502,503,506,507,510,511,514,515,518,519,522],{},"Every trigger has a built-in ",[18,504,505],{},"Test run"," panel — one button that fires the rule against a ",[18,508,509],{},"synthesised sample context"," for its trigger. Two things to know before you use it: it ",[18,512,513],{},"skips the conditions"," (it runs the actions directly), and it is ",[18,516,517],{},"not a dry run"," — outbound actions (webhook, Postgres, artifact delivery) ",[18,520,521],{},"execute for real"," against your configured destinations, just flagged with a test badge in Deliveries. Emails are checked but not sent, and record-mutating actions (create/update) are skipped. So point a test at a safe destination; it's for confirming wiring, not a no-op preview.",[53,524,526],{"id":525},"ingestion-bringing-sensor-and-device-data-in","Ingestion — bringing sensor and device data in",[14,528,182,529,532,533,536],{},[18,530,531],{},"ingest connector"," is an external data source that feeds readings into Aptli. Each connector has a ",[18,534,535],{},"Mode",":",[203,538,539,569],{},[206,540,541,544,545,548,549,149,552,555,556,216,559,216,562,216,565,568],{},[18,542,543],{},"Pull (scheduled poll)"," — Aptli polls a vendor's REST API on an ",[18,546,547],{},"Interval"," (minimum 30 seconds). You set the ",[18,550,551],{},"URL",[18,553,554],{},"Credential",", and a small response mapping (",[18,557,558],{},"Readings path",[18,560,561],{},"Timestamp key",[18,563,564],{},"Value key",[18,566,567],{},"Metric key",") so Aptli can read the vendor's JSON.",[206,570,571,574,575,578],{},[18,572,573],{},"Push (sender posts)"," — the sender POSTs JSON batches to the connector's own inbound endpoint (shown once you save the connector), authenticated with an ",[18,576,577],{},"ingest API key",". Nothing to poll; the device or gateway pushes on its own schedule.",[14,580,581,582,585,586,590,591,594,595,597,598,601],{},"Either way, each connector names a ",[18,583,584],{},"Station feature ID"," (the map feature the readings belong to — see ",[47,587,589],{"href":588},"#monitoring--alarms","Monitoring & Alarms",") and a ",[18,592,593],{},"Unit",", and each batch it ingests fires the ",[213,596,310],{}," trigger. The ",[18,599,600],{},"Ingestion"," tab also shows a live view of scheduled polls (how many are active, delayed, or failed).",[53,603,605],{"id":604},"credentials-keys-and-the-connection-allowance","Credentials, keys, and the connection allowance",[195,607,609],{"id":608},"outbound-credentials","Outbound credentials",[14,611,612,613,616,617,619],{},"Outbound actions that reach an external system (webhooks, Postgres, S3/SFTP artifact delivery) authenticate through a ",[18,614,615],{},"stored credential"," rather than inline secrets. Create one once on the ",[18,618,102],{}," page and reference it by name. Secrets are encrypted at rest and never shown again after saving; non-secret config (base URLs, hostnames, regions) stays readable. Types: bearer / basic / API-key HTTP, S3, SFTP, and Postgres.",[195,621,623],{"id":622},"inbound-ingest-keys","Inbound ingest keys",[14,625,626,627,630],{},"Machine bearer keys that let a sender push into Aptli. Ingest-only, scoped to what they're allowed to do (push readings in, or pull portal submissions out), and the raw key is ",[18,628,629],{},"shown once at creation"," — copy it then.",[195,632,50],{"id":633},"the-connection-allowance",[14,635,636,637,640,641,216,643,646,647,650,651,654,655,658,659,662],{},"The commercial meter is the number of ",[18,638,639],{},"external connections",", not the feature itself. Each ",[18,642,531],{},[18,644,645],{},"API key",", and reusable ",[18,648,649],{},"outbound hook"," consumes one ",[18,652,653],{},"unit"," from a shared pool (internal event-trigger rules are unmetered). A chip on the Automations and Credentials pages shows ",[18,656,657],{},"\"{used} of {total} connectors/keys\""," with a breakdown of connectors, API keys, and hooks. The default allowance is ",[18,660,661],{},"3","; when you hit it, creating another prompts you to revoke an unused one or contact support to add more. Connections you already have keep running if the allowance later shrinks.",[53,664,589],{"id":665},"monitoring-alarms",[14,667,668,669,671,672,323,675,678],{},"Ingestion gets sensor data ",[31,670,33],{},"; monitoring is what you ",[31,673,674],{},"see",[31,676,677],{},"are warned about",".",[195,680,682],{"id":681},"stations-and-readings","Stations and readings",[14,684,141,685,688,689,691],{},[18,686,687],{},"station"," is simply a map feature that a sensor reports against. By default a connector's ",[18,690,584],{}," is the feature's own id, so readings key straight to it; senders that use their own station codes can be linked explicitly.",[14,693,694,695,698,699,702,703,706,707,710],{},"Once readings are flowing, the feature's record grows a ",[18,696,697],{},"Sensor readings"," section: for each metric, the ",[18,700,701],{},"latest value and unit"," plus a ",[18,704,705],{},"7-day sparkline",". If a station goes quiet but its source is still sending under other ids (a sensor was renamed at the source), Aptli flags it and offers a one-click ",[18,708,709],{},"Relink"," so you don't lose the history.",[195,712,128],{"id":713},"alarms",[14,715,716,717,720,721,724],{},"Alarm rules live ",[18,718,719],{},"on the ingest connector",". Turn on ",[18,722,723],{},"Raise alarms"," and set:",[203,726,727,733,739,749,755],{},[206,728,729,732],{},[18,730,731],{},"Alarm when value is"," — above or below a threshold",[206,734,735,738],{},[18,736,737],{},"Clear margin"," — how far back past the threshold a reading must go before the alarm auto-clears (hysteresis, so a value hovering on the line doesn't flap)",[206,740,741,744,745,748],{},[18,742,743],{},"Silence alarm after (minutes)"," — raise a ",[31,746,747],{},"silence"," alarm if no data arrives for this long (dead-sensor detection)",[206,750,751,754],{},[18,752,753],{},"Alarm recipients"," — who gets notified",[206,756,757,760,761,764],{},[18,758,759],{},"Escalate if unacknowledged after (minutes)"," + ",[18,762,763],{},"Escalation recipients"," — a second tier if no one acknowledges in time",[14,766,767,768,770,771,216,774,777,778,781,782,785,786,789,790,793],{},"The ",[18,769,128],{}," page is the live ledger. Each alarm is ",[18,772,773],{},"Active",[18,775,776],{},"Acknowledged",", or ",[18,779,780],{},"Resolved","; you ",[18,783,784],{},"Acknowledge"," it to signal someone's on it and ",[18,787,788],{},"Resolve"," it when it's handled (alarms also auto-clear when the reading recovers past the clear margin). Threshold alarms and silence (\"no data received\") alarms are shown distinctly, and an alarm carries its value/threshold/peak, who acknowledged it, and — if it escalated — an ",[18,791,792],{},"\"Escalated {date}\""," line with a delivery-status badge. A home-dashboard card surfaces active alarms so they don't sit unseen. The Alarms page is visible to any signed-in supervisor, not just automations admins, so the people who watch the work can watch the alarms.",[195,795,797],{"id":796},"two-way-ticket-loop","Two-way ticket loop",[14,799,800,801,804],{},"A hook can carry a ",[18,802,803],{},"write-back URL"," with each alarm: your external ticketing system POSTs status changes back to acknowledge or resolve the alarm, and the ticket's reference shows on the alarm as a link. This closes the loop when alarms are handled in another tool.",[195,806,808],{"id":807},"outcomes-and-share-links","Outcomes and share links",[14,810,811,812,815,816,820,821,824],{},"On a project, the ",[18,813,814],{},"Outcomes"," tab charts monitored metric series against completed-work milestones — see ",[47,817,819],{"href":818},"/addons/fulfillment/projects/#outcomes--did-the-work-move-the-needle","Projects",". You can publish a read-only, tokenized ",[18,822,823],{},"share link"," of those charts for outsiders, and revoke it any time. Readings are shown for context alongside work dates; Aptli makes no causal claim and the page is explicitly not certified measurement data.",[53,826,828],{"id":827},"deliveries-the-activity-log","Deliveries — the activity log",[14,830,767,831,833],{},[18,832,115],{}," page is read-only history, in two tabs:",[203,835,836,846],{},[206,837,838,841,842,845],{},[18,839,840],{},"Outbound deliveries"," — one row per outbound attempt: date, workflow, action, destination, outcome (",[18,843,844],{},"Success / Failed / Retrying / Dead letter","), attempt count, duration, and any error. Test runs are badged.",[206,847,848,851],{},[18,849,850],{},"Inbound runs"," — the ingest history: source, outcome, date, duration, rows, and error.",[53,853,855],{"id":854},"quick-connect","Quick Connect",[14,857,858,859,862],{},"For common integrations, the ",[18,860,861],{},"Quick connect"," wizard walks you through a recipe instead of the raw editor — e.g. \"Send new portal submissions to my system,\" \"Alert my system when stock runs low,\" \"Create a ticket when an alarm is raised,\" or \"Receive readings from my sensors or gateway.\" It wires the connector, hook, or rule for you.",[53,864,866],{"id":865},"permissions","Permissions",[14,868,869,870,873,874,876],{},"Automations doesn't use the global admin-rights grid. The three configuration pages (Automations, Credentials, Deliveries) are gated by a ",[18,871,872],{},"viewers / modifiers"," allow-list in the automations settings, so you grant access explicitly. The ",[18,875,128],{}," page is intentionally open to any signed-in user — watching alarms is an operations task, not a configuration one. Holders of the application-settings right always have a recovery path if the lists are empty.",{"title":878,"searchDepth":879,"depth":879,"links":880},"",2,[881,882,883,889,890,895,901,902,903],{"id":55,"depth":879,"text":56},{"id":137,"depth":879,"text":138},{"id":178,"depth":879,"text":179,"children":884},[885,887,888],{"id":197,"depth":886,"text":198},3,{"id":366,"depth":886,"text":367},{"id":393,"depth":886,"text":394},{"id":525,"depth":879,"text":526},{"id":604,"depth":879,"text":605,"children":891},[892,893,894],{"id":608,"depth":886,"text":609},{"id":622,"depth":886,"text":623},{"id":633,"depth":886,"text":50},{"id":665,"depth":879,"text":589,"children":896},[897,898,899,900],{"id":681,"depth":886,"text":682},{"id":713,"depth":886,"text":128},{"id":796,"depth":886,"text":797},{"id":807,"depth":886,"text":808},{"id":827,"depth":879,"text":828},{"id":854,"depth":879,"text":855},{"id":865,"depth":879,"text":866},"Wire Aptli to the outside world: event-driven rules and hooks, inbound sensor ingestion, outbound deliveries, and outcome monitoring with threshold alarms.","md",{},true,"/en/user/automations",{"title":5,"description":904},"en/user/automations/index","80NXW8lCztIWnLDw34CuSDMfF2UoOx5IyjcQw1NYXvg",1783969901900]