How to Schedule Tweets with a REST API
June 16, 20267 min read
Scheduling tweets is one of the most common automation use cases. You write your content ahead of time, set a time, and the API posts it for you. No manual action needed. Here's how to build it with ChirpAPI and a few lines of code.
## Basic Concept
The approach is simple: store your tweets with a scheduled time, run a cron job every minute, and post any tweets whose time has arrived. The flow looks like this:
- You (or your app) save a tweet with a `scheduled_at` timestamp
- A cron job runs every minute
- It checks for tweets where `scheduled_at > /var/log/tweet-scheduler.log 2>&1
`plaintext
## Node.js Implementation
`
const sqlite3 = require('better-sqlite3');
const fetch = require('node-fetch');
const API_KEY = 'YOUR_CHIRPAPI_KEY';
const db = sqlite3('scheduler.db');
async function postPending() {
const now = new Date().toISOString().slice(0, 19);
const pending = db.prepare(
SELECT id, text FROM tweets WHERE status='pending' AND scheduled_at<=?
).all(now);
for (const {id, text} of pending) {
try {
const res = await fetch('https://api.chirpapi.fun/v1/tweet', {
method: 'POST',
headers: {
'Authorization': Bearer ${API_KEY},
'Content-Type': 'application/json'
},
body: JSON.stringify({text})
});
if (res.ok) {
db.prepare(`UPDATE tweets SET status='posted' WHERE id=?`).run(id);
console.log(`Posted: ${text.slice(0, 50)}...`);
} else {
db.prepare(`UPDATE tweets SET status='failed' WHERE id=?`).run(id);
}
} catch (err) {
db.prepare(`UPDATE tweets SET status='error' WHERE id=?`).run(id);
}
}
}
postPending();
`plaintext
## Timezone Handling
Always store and compare times in UTC. Convert to the user's timezone only for display:
`
from zoneinfo import ZoneInfo
User says "post at 9 AM Jakarta time"
jakarta = ZoneInfo("Asia/Jakarta")
scheduled = datetime(2026, 6, 17, 9, 0, 0, tzinfo=jakarta)
utc_time = scheduled.astimezone(timezone.utc)
Store utc_time in database
`plaintext
## Best Posting Times
Based on engagement data across multiple accounts:
- **Weekdays:** 8-10 AM and 12-1 PM (user's timezone)
- **Weekends:** 10 AM - 12 PM
- **Avoid:** After 8 PM (lower engagement)
- **Best days:** Tuesday, Wednesday, Thursday
## Error Handling and Retries
Network requests fail. Add retry logic:
`
import time
def post_with_retry(text, max_retries=3):
for attempt in range(max_retries):
try:
resp = requests.post(API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={"text": text},
timeout=10
)
if resp.status_code == 200:
return resp.json()
if resp.status_code == 429: # Rate limited
time.sleep(60 * (attempt + 1))
continue
return None
except requests.exceptions.Timeout:
time.sleep(5 * (attempt + 1))
return None
`
Originally published at ChirpAPI Blog.
Top comments (0)