List rules
Every rule on the connection, in the order they are evaluated.
Runs the real call against your workspace, with your own key.
GET /rules
Every rule on the connection, in the order they are evaluated.
How a rule runs
export OE=https://api.openemail.ukexport AUTH="Authorization: Bearer $OPENEMAIL_API_KEY"A rule is a list of conditions over an arriving message and a list of actions to take on anything that matches them. Rules belong to the CONNECTION rather than to whoever wrote one. A workspace key sees the same rules a colleague does, and deleting the author’s account does not take them with it.
A connection holds 100 rules, and each of them holds at most 20 conditions and 10 actions. Those are runaway-script guards rather than plan limits: the 101st rule is rule_limit_reached, a 422, and the 21st condition is refused by the schema before anything is written.
match: "all" ANDs the conditions together, match: "any" ORs them, and negate on a single condition is NOT. There is no nested boolean tree: (A and B) or C is two rules. That is a decision rather than a shortcut. A recursive schema cannot be described in the OpenAPI document with $refStrategy: "none", cannot be handed to an MCP client as JSON Schema, and is the exact shape that has blown TypeScript’s instantiation ceiling in this repo before. Two rules is also how a person reads it back six months later.
Every enabled rule on the connection is evaluated against every arriving message, in position order, lowest first. Evaluation stops after a matching rule that carries stopProcessing: true, and nothing below it is considered at all. Where two matching rules both name a folder, the LATER one wins and the message ends up in its folder, which is the reading a numbered list gives you and the one thing about ordering worth stating rather than leaving to be discovered.
Rules fail OPEN. A condition an older client wrote, a value that will not compile to a pattern, a database that will not answer: each of those is skipped and the message is delivered as it would have been, with the failure logged against the run. A rule engine that throws is a message that never arrives; a rule engine that is skipped is one message in the wrong folder.
Nothing is retroactive. A rule decides what happens to mail arriving after it exists, and there is deliberately no endpoint that applies one to a mailbox you already have. See POST /rules/{id}/test, which answers the question people are actually asking when they reach for that.
Example
Needs rules:read. limit goes to 100, cursor is opaque (pass back the nextCursor you were given), and enabled narrows to one side of the switch.
curl "$OE/rules?limit=25&enabled=true" -H "$AUTH"{ "object": "list", "data": [ { "object": "rule", "id": "rul_7f3a1c94e05d3862c1f0a44b", "name": "Receipts to their own label", "description": null, "enabled": true, "position": 0, "match": "all", "conditions": [ { "field": "from_domain", "op": "matches", "value": "*.stripe.com", "negate": false }, { "field": "subject", "op": "contains", "value": "receipt", "negate": false } ], "actions": [ { "type": "label", "value": "USER_RECEIPTS" }, { "type": "archive" } ], "stopProcessing": true, "lastMatchedAt": "2026-08-29T11:04:12.000Z", "matchCount": 148, "createdAt": "2026-08-01T09:00:00.000Z", "updatedAt": "2026-08-20T16:31:00.000Z" } ], "hasMore": false, "nextCursor": null}enabled takes the strings true and false rather than a coerced boolean, and that is not fussiness: Boolean("false") is true, so a coerced query would have answered "show me my disabled rules" with the enabled ones and looked like it worked.
The order of the list is the evaluation order, so reading it top to bottom is reading what happens to a message. position is not unique and is not an id (it is renumbered by POST /rules/reorder), so pin a rule by its rul_ id and never by where it currently sits.
matchCount and lastMatchedAt are counted in the database as mail arrives rather than read and rewritten, so two messages landing at once cannot lose a count between them. A rule that has never fired reads 0 and null, which is the answer worth acting on when somebody says a rule is not working.