Automate recurring agent work
Section: DOC-CP-scheduling-build-scheduled-agents#automate-recurring-agent-work.
Some agent work happens on a clock, not on a user tap: a daily briefing, a nightly summary, a weekly report. This guide wires a cron schedule to a Travila agent so a job fires on a timer, drives a conversation turn, and — optionally — delivers the result to your backend as a webhook event.
What you’ll build: a weekday briefing scheduled to start preparing at 9 a.m. in the selected timezone and appear in the existing user conversation when complete. Your backend receives the scheduled firing, asks the agent for the briefing and tracks the completed reply. Optionally, a webhook lets your backend react when that reply is published.
Prerequisites
Section: DOC-CP-scheduling-build-scheduled-agents#prerequisites.
- An API key (
sk_…) for your backend (issued through your account administrator or enabled key-management interface). See Authentication & API Keys. - A conversation thread — create one with
create-threadif you do not have one. See Build an AI chat assistant for the full setup. - A publicly reachable HTTPS URL for your callback endpoint, e.g.
https://api.example.com/hooks/scheduled-agent. The scheduler POSTs to it on every firing.
Step 1: Create the callback endpoint in your backend
Section: DOC-CP-scheduling-build-scheduled-agents#step-1-create-the-callback-endpoint-in-your-backend.
Your backend needs one HTTP endpoint that the scheduler will POST to on each firing. The body will be exactly the payload you configure in the schedule (see Step 4). The scheduler adds two headers:
Callback example: HTTP envelope · Signed claims.
POST /hooks/scheduled-agent HTTP/1.1
Authorization: Bearer <signed-jwt>
Idempotency-Key: sched:<schedule_id>:<scheduled_time_unix_ms>
Content-Type: application/json
<your schedule's payload, verbatim>
Verify and atomically persist acceptance plus a pending work item before returning 2xx. Process the agent work in a worker; a fast acknowledgement without durable work can lose the firing. Repeated failed deliveries can auto-pause the schedule.
Step 2: Verify the callback signature
Section: DOC-CP-scheduling-build-scheduled-agents#step-2-verify-the-callback-signature.
Every scheduler dispatch carries a signed JWT in the Authorization header. Verify it before acting — an endpoint that acts first and verifies afterwards is one that anyone can trigger.
Getting the public key
Section: DOC-CP-scheduling-build-scheduled-agents#getting-the-public-key.
The platform publishes its signing keys as a standard JWKS, unauthenticated and cacheable:
https://api.travila.ai/.well-known/jwks.json
Use the signing-key contract when configuring your verifier.
Claims
Section: DOC-CP-scheduling-build-scheduled-agents#claims.
Validate the signed claims, receiver audience and saved schedule before queuing the briefing. Follow the callback receiver recipe for durable acceptance and replay handling.
Step 3: Drive an agent turn from the callback
Section: DOC-CP-scheduling-build-scheduled-agents#step-3-drive-an-agent-turn-from-the-callback.
For this recipe, keep one conversation and the fixed “daily briefing” task with the user’s schedule. The worker uses that saved assignment to request the briefing. The scheduler’s HTTP acknowledgement happens before this slower generation work, so record both outcomes.
After saving the firing and pending work, a worker selects the user, conversation and fixed task from the schedule registration saved in your application. Check current business eligibility and the agreed task permissions before generation and again before delivery. Never use an LLM-generated user ID, destination or deep link as authority.
The worker may use send-message-sync for a bounded wait. Save a work record for the verified firing and the returned run ID. The callback's jti does not make that API call idempotent, and colon-separated firing IDs may be invalid as API idempotency keys. If the send times out, check the original run through the generation recovery flow before sending another turn. If you cannot establish the outcome, keep it unknown and investigate; do not automatically submit the same business action again.
curl -X POST https://api.travila.ai/api/v1/llm/send-message-sync \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "b81d5345-c1f9-4fb9-b558-a6327c75b842",
"userMessage": {
"role": "ROLE_USER",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "Generate the daily briefing."
}
]
}
}'
Reference: Send a message and wait for the result · Request fields.
Example completed response — a queued turn, tool pause or expired wait can instead return a nonterminal outcome:
{
"runId": "9d4c2e1f-...",
"status": "AGENT_STATUS_COMPLETED",
"messages": [
{
"role": "ROLE_ASSISTANT",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "Here is your daily briefing…"
}
],
"generatedBy": "9d4c2e1f-..."
}
],
"aggregateUsage": {
"promptTokens": 412,
"completionTokens": 88,
"totalTokens": 500
}
}
Reference: Send a message and wait for the result · Response fields.
Continue to delivery only when the agent run completes successfully. Use the run outcome contract to handle a wait, tool pause or unsuccessful result without generating the briefing twice.
Step 4: Create the schedule
Section: DOC-CP-scheduling-build-scheduled-agents#step-4-create-the-schedule.
With your endpoint ready, register the cron job. Point target.url at your callback endpoint:
curl -X POST https://api.travila.ai/api/v1/scheduler/create-job \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"name": "Daily agent briefing",
"scheduleType": "SCHEDULE_TYPE_CRON",
"cronExpression": "0 9 * * 1-5",
"timezone": "America/New_York",
"target": {
"url": "https://api.example.com/hooks/scheduled-agent",
"kind": "agent-briefing",
"payload": {
"task": "daily-briefing"
}
}
}'
Reference: Create a scheduled job · Request fields.
Response:
{
"scheduleId": "sched_a1b2c3d4e5f60718",
"name": "Daily agent briefing",
"state": "SCHEDULE_STATUS_ACTIVE",
"scheduleType": "SCHEDULE_TYPE_CRON",
"cronExpression": "0 9 * * 1-5",
"timezone": "America/New_York",
"nextTriggerAt": "2026-06-04T13:00:00Z",
"createdAt": "2026-06-03T14:00:00Z"
}
Reference: Create a scheduled job · Response fields.
Save scheduleId — you'll use it to pause, resume, or delete the schedule later.
Use the calendar/timezone reference when adjusting this briefing’s schedule.
Step 5: Subscribe to the results webhook (Optional)
Section: DOC-CP-scheduling-build-scheduled-agents#step-5-subscribe-to-the-results-webhook-optional.
If you want your backend to receive each assistant message as it lands — rather than only reading the send-message-sync response — subscribe to the llm.message_published event. Pass eventTypes in a single call to create both the endpoint and its subscription:
curl -X POST https://api.travila.ai/api/v1/webhooks/create-endpoint \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "scheduled-agent-results",
"url": "https://api.example.com/hooks/agent-results",
"description": "Receives assistant messages from scheduled agent runs",
"eventTypes": [
"llm.message_published"
]
}'
Reference: Create a webhook endpoint · Request fields.
Response:
{
"endpoint": {
"id": "ep_abc123",
"name": "scheduled-agent-results",
"url": "https://api.example.com/hooks/agent-results",
"status": "ENDPOINT_STATUS_ACTIVE",
"secret": "whsec_…"
},
"subscription": {
"id": "sub_def456",
"endpointId": "ep_abc123",
"eventTypes": [
"llm.message_published"
]
}
}
Reference: Create a webhook endpoint · Response fields.
Store the secret — it is the signing key for this webhook endpoint. Use the message event contract to verify and interpret the received payload before applying the update.
Follow the subscription and deduplication contract when adding or changing a result receiver.
Verify the complete workflow
Section: DOC-CP-scheduling-build-scheduled-agents#verify-the-complete-workflow.
Run one controlled briefing through the complete path: scheduled callback, durable acceptance, agent run and visible completed reply in the intended conversation. Keep the schedule, firing and run references together. Once the user can see the briefing, exercise interruption and duplicate-delivery cases below before enabling ongoing delivery.
Use an isolated conversation and a constrained schedule. Confirm all of these outcomes before enabling recurring delivery:
- Invalid, expired, wrong-audience or wrong-scope callbacks fail before work is accepted.
- Repeated identical deliveries produce one durable work item; changed payloads under the same identity are rejected. Simulate a crash after acceptance and verify the worker resumes.
- The accepted firing and generated run can be reconciled after a dropped response, without silently creating another turn.
- Failed, queued, timed-out, cancelled or unknown generation outcomes do not become successful notifications. Tool pauses follow the documented continuation flow.
- Delivery uses a stable business-effect identity, an authorized recipient and current domain state. Duplicate callbacks and webhook redelivery do not send the same briefing twice.
- Pause or deletion stops future scheduling according to the deployment's contract, while previously accepted or in-flight work is accounted for separately.
Next steps
Section: DOC-CP-scheduling-build-scheduled-agents#next-steps.
| I want to… | Go to |
|---|---|
| Pause, resume, or delete a schedule | Manage scheduled jobs |
| Understand retry and auto-pause behavior | Job execution and retries |
| See the complete callback verification algorithm | Verify a callback came from Travila |
| Browse all scheduler endpoints | Scheduler API Reference |
| Browse all webhook event types | Event catalog |
| Use async generation with polling instead | Send messages and get replies |
Document ID: DOC-CP-scheduling-build-scheduled-agents. Section identities and revisions.