AI-Written Notifications

Schedule rules whose copy is written fresh at every send from a short brief — what the app is, standing instructions, language and example notifications — checked before it goes out, never repeating recent sends, and never sent blank. Preview it first with the sample endpoint.

A schedule rule with contentMode: "ai" carries a brief instead of a fixed title and body. At every send, Native Notify writes one new notification from the brief, checks it, and sends it to the rule's audience like any other scheduled send — so a weekly reminder never reads the same twice.

It works for every project: Agent Notify projects (any cadence, audience and environment a rule takes) and classic Expo apps (daily and weekly rules to all devices or a segment). The older classic AI Push schedules are a separate API and keep working unchanged.

The brief

FieldRequiredLimitNotes
appDescriptionyes2,000 charactersWhat the app is and what the notifications should be about. Put every fact you want mentioned here — times, places, what is new.
instructionsno2,000 charactersStanding rules for the writer: tone, topics to avoid, calls to action.
languageno60 charactersThe language to write in. Default "English".
examplesno10 examples, 300 characters eachExample notifications for the voice — a list of strings, or one string with one example per line. They set the tone and are never copied.

A weekly AI-written rule for a bookstore, saved paused so you can preview it first:

{
  "name": "Saturday story hour",
  "enabled": false,
  "contentMode": "ai",
  "appDescription": "Maple Street Books, a family bookstore. Invite families to Saturday story hour at 10:00 in the children's corner, and mention that new picture books arrive every week.",
  "instructions": "Warm and brief. No prices or discounts. Always say story hour starts at 10:00.",
  "language": "English",
  "examples": [
    "Story hour starts at 10 — bring the little ones!",
    "New picture books just arrived in the children's corner."
  ],
  "frequency": "weekly",
  "dayOfWeek": 5,
  "timeOfDay": "17:00",
  "timezone": "America/Chicago",
  "audienceKind": "all"
}

Send it to POST /api/agent/apps/:appId/schedules — every other field (cadence, audience, environment, pushData, quiet hours) works exactly as on Scheduling. An AI rule stores no title or body: in the rule list it has title: null, body: null and its brief under ai, and each run records the copy that actually went out.

What happens at each send

  1. The runner claims the occurrence — at most once, like every rule.
  2. It asks the model for one title and body, handing it the brief and the rule's 10 most recent sent notifications, so it varies the angle and wording instead of repeating itself.
  3. The answer is checked: a non-empty title of at most 65 characters and a non-empty body of at most 180 (an emoji counts once), with markup, markdown and wrapping quotes removed. An unusable answer gets one corrective retry.
  4. Usable copy is sent to the rule's audience and saved on the run (title, body) — which is also the history step 2 reads next time.
  5. No usable copy means nothing is sent. If the model cannot be reached, or both answers are unusable, the run is recorded failed with the reason, and the rule tries again at its next occurrence. There is never a blank, placeholder or fallback push.

The writing rules

Every AI-written notification follows the same rules, whatever the brief says:

  • Modest, kind and appropriate for the whole family — nothing crude, suggestive, violent, hateful or mocking.
  • Nothing about gambling, alcohol, drugs, tobacco, the occult or party culture.
  • No fear, guilt or pressure tactics.
  • No invented facts — no prices, discounts, dates, deadlines or promises the brief does not state.
  • Plain text in the brief's language, one clear idea, at most one emoji.
  • The owner's standing instructions are followed unless they conflict with these rules.

Preview a sample

POST https://app.nativenotify.com/api/agent/apps/:appId/schedules/ai-sample

Writes one sample from a brief — nothing is saved and nothing is sent. Send the brief fields, or ruleId of an existing AI rule: its stored brief fills the fields you leave out, and its recent sends count as the no-repeat history, exactly as at send time.

{
  "appDescription": "Maple Street Books, a family bookstore. Invite families to Saturday story hour at 10:00.",
  "instructions": "Warm and brief. No prices or discounts.",
  "language": "English"
}

Response — 200:

{
  "ok": true,
  "sample": {
    "title": "Story hour this Saturday",
    "body": "Bring the family to the children's corner at 10:00 for stories and brand-new picture books."
  },
  "model": "~deepseek/deepseek-flash-latest",
  "attempts": 1
}

attempts is 2 when the corrective retry was needed. Every sample is a real model call, so each account user can write 20 samples a minute and 300 a day (the daily count resets at midnight UTC).

StatusCodeMeaning
400bad_briefThe brief is invalid — missing appDescription, or a field over its limit (field names it).
400bad_rule_idruleId is not a positive integer.
404app_not_found, rule_not_foundThe app is not one this account can access, or the rule is not on it.
429limit_reachedThe per-minute or per-day sample limit is used up.
502llm_failed, invalid_outputThe model could not be reached, or returned no usable copy after the retry.
503llm_not_configuredAI writing is not configured on the server.

The same call is behind the dashboard's Generate sample button (the rule form) and Sample button (a saved AI rule), and the chat always writes a sample before it saves an AI rule — the Turn on schedule card shows it, and a brief that cannot produce usable copy saves nothing.

Saving and editing

  • contentMode: "ai" needs appDescription (or a stored brief, on an update); a missing or oversized field answers 400 bad_schedule, and the error's field names it.
  • title and body are ignored for an AI rule. Switching a fixed rule to AI clears its fixed title and body — switching back needs them again. Switching back to fixed keeps the brief stored, so it is still there if you switch to AI later.
  • PATCH changes only the fields you send: { "instructions": null } clears the instructions, { "examples": [] } clears the examples.

For agents

The MCP server has generate_ai_schedule_sample (the sample endpoint — pass app_description, or rule_id), and create_schedule_rule / update_schedule_rule take content_mode: "ai" with app_description, instructions, language and examples. A good agent flow: write a sample, show it to the user, adjust the brief, and only then create the rule with enabled: true — or save it with enabled: false and let the user turn it on.