Build a Task Bot with the REST API
Step-by-step walkthrough: create an API key, make your first request, and build a Python script that posts overdue task reminders
This tutorial walks you through building a simple task bot that checks for overdue tasks and posts reminders to a channel. You'll start with raw curl commands to understand the API, then wrap everything into a Python script you can run on a cron.
By the end you'll have a working integration that talks to the REST API documented at /docs/api.
Prerequisites
- A Saltare workspace (any plan)
- A channel to post reminders in (e.g.
#general) - Python 3.8+ with
requestsinstalled, or justcurlto follow along manually
Step 1: Create an API key
- Open your workspace and go to Settings → API Keys
- Click Create API Key
- Name it something descriptive:
task-reminder-bot - Select these scopes:
tasks:read— to list overdue tasksmessages:write— to post reminderschannels:read— to look up the target channel
- Leave Agent binding empty (this bot posts as your user, not as an agent)
- Click Create and copy the
sk_sal_…token immediately — you won't see it again
Export it in your terminal for the rest of this tutorial:
export SALTARE_API_KEY="sk_sal_your_token_here"
export SALTARE_URL="https://app.saltare.com"
Step 2: Verify the key works
The /api/v1/me endpoint confirms your identity and workspace:
curl -s "$SALTARE_URL/api/v1/me" \
-H "Authorization: Bearer $SALTARE_API_KEY" | python3 -m json.tool
You should see something like:
{
"workspace": {
"name": "Acme Corp",
"slug": "acme-corp"
},
"user": {
"name": "Jane Smith",
"email": "[email protected]"
},
"scopes": ["tasks:read", "messages:write", "channels:read"]
}
If you get a 401, double-check the token. If you get a 403, make sure the key hasn't expired or been revoked.
Step 3: List tasks
Fetch all open tasks:
curl -s "$SALTARE_URL/api/v1/tasks?state=open" \
-H "Authorization: Bearer $SALTARE_API_KEY" | python3 -m json.tool
The response includes pagination headers. For a small workspace you'll get everything in one page. For larger ones, check X-Total-Pages and pass ?page=2 to paginate.
Filter to overdue tasks by combining state with due_before:
curl -s "$SALTARE_URL/api/v1/tasks?state=open&due_before=$(date -u +%Y-%m-%d)" \
-H "Authorization: Bearer $SALTARE_API_KEY" | python3 -m json.tool
Each task in the response looks like:
{
"slug": "fix-login-bug",
"title": "Fix login redirect loop",
"state": "open",
"due_date": "2026-04-14",
"assignee": {
"type": "User",
"name": "Jane Smith"
}
}
Step 4: Find your target channel
Look up the channel slug you want to post reminders to:
curl -s "$SALTARE_URL/api/v1/channels" \
-H "Authorization: Bearer $SALTARE_API_KEY" | python3 -m json.tool
Find the channel you want (e.g. general) and note the slug value.
Step 5: Post a message
Try a manual message first:
curl -s -X POST "$SALTARE_URL/api/v1/messages" \
-H "Authorization: Bearer $SALTARE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel_slug": "general",
"body": "Hello from the API!"
}' | python3 -m json.tool
You should see the message appear in the channel. If you get a 422, check that the channel slug is correct and your key has the messages:write scope.
Step 6: Put it together in Python
Here's a complete script that checks for overdue tasks and posts a summary:
#!/usr/bin/env python3
"""Overdue task reminder bot for Saltare."""
import os
from datetime import date
import requests
API_KEY = os.environ["SALTARE_API_KEY"]
BASE_URL = os.environ.get("SALTARE_URL", "https://app.saltare.com")
CHANNEL = os.environ.get("SALTARE_CHANNEL", "general")
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
def get_overdue_tasks():
"""Fetch all open tasks past their due date."""
today = date.today().isoformat()
tasks = []
page = 1
while True:
resp = requests.get(
f"{BASE_URL}/api/v1/tasks",
headers=HEADERS,
params={
"state": "open",
"due_before": today,
"page": page,
"per_page": 50,
},
)
resp.raise_for_status()
batch = resp.json()
if not batch:
break
tasks.extend(batch)
total_pages = int(resp.headers.get("X-Total-Pages", 1))
if page >= total_pages:
break
page += 1
return tasks
def post_reminder(tasks):
"""Post an overdue task summary to the configured channel."""
if not tasks:
return
lines = [f"**{len(tasks)} overdue task(s)** as of {date.today().isoformat()}:\n"]
for task in tasks:
assignee = task.get("assignee", {}).get("name", "Unassigned")
due = task.get("due_date", "no date")
lines.append(f"- **{task['title']}** (due {due}, assigned to {assignee})")
body = "\n".join(lines)
resp = requests.post(
f"{BASE_URL}/api/v1/messages",
headers=HEADERS,
json={"channel_slug": CHANNEL, "body": body},
)
resp.raise_for_status()
print(f"Posted reminder with {len(tasks)} task(s)")
if __name__ == "__main__":
overdue = get_overdue_tasks()
if overdue:
post_reminder(overdue)
else:
print("No overdue tasks — nothing to post")
Run it:
pip install requests
python task_reminder.py
Step 7: Schedule it
Run the script daily with cron:
# Edit your crontab
crontab -e
# Add this line (runs weekdays at 9 AM)
0 9 * * 1-5 SALTARE_API_KEY=sk_sal_... /usr/bin/python3 /path/to/task_reminder.py
Or use a Saltare automation skill to run it from within the workspace — no external server needed. See the Weekly Status Report recipe for the automation skill approach.
Error handling
The API returns standard HTTP status codes:
| Code | Meaning | What to do |
|---|---|---|
401 |
Invalid or missing token | Check your API key |
403 |
Key lacks the required scope | Add the missing scope in Settings |
404 |
Resource not found | Verify the slug or ID |
422 |
Validation error | Check the error.message field for details |
429 |
Rate limited | Back off and retry after a few seconds |
Rate limits are 600 requests/minute per key — more than enough for a periodic bot. If you're doing bulk operations, add a short sleep between pages.
Next steps
- Add webhook triggers — instead of polling on a cron, subscribe to
task.createdevents and check due dates in real time. See React to Events with Webhooks. - Bind to an agent — create the API key with an agent binding so reminders appear as messages from your bot agent, not your personal account.
- Read the full reference — the REST API docs cover every endpoint, parameter, and error code.
- Trigger agent runs —
POST /api/v1/agents/:slug/messagequeues an agent response, letting you kick off AI workflows from external systems.
Tips
- One key per integration. Revoking one shouldn't break the others.
- Use narrow scopes. This bot only needs
tasks:read,messages:write, andchannels:read. Don't give it*. - Set an expiry on temporary keys. If you're just experimenting, set a 7-day expiry so you don't leave stale keys around.
- Check the OpenAPI spec.
GET /api/v1/openapi.jsonreturns the machine-readable spec — drop it into Postman or use it for client code generation.