Developers
REST API & Webhooks
Build on top of IGMsg. Programmatically manage automations, query DM logs, and receive real-time event webhooks.
Authentication
Every API request must include a Bearer token in the Authorization header. Generate tokens at igmsg.com/developer. Tokens look like igmsg_ followed by 40 alphanumeric characters.
curl https://igmsg.com/api/v1/me \
-H "Authorization: Bearer igmsg_YOUR_TOKEN_HERE"
The plaintext token is shown once at creation - store it in a secret manager (1Password, AWS Secrets Manager, your CI's secrets store). You cannot retrieve it again, but you can always revoke and re-issue.
Base URL & versioning
All endpoints live under https://igmsg.com/api/v1. We will only ever introduce additive changes within v1 - new fields, new endpoints. Removals or breaking changes will live in v2.
Rate limits
60 requests per minute per token. Responses include standard headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
When exceeded, you'll get 429 Too Many Requests with a Retry-After header. Implement exponential backoff in your client.
Error format
Errors are JSON with an error code and human-readable message. HTTP status codes follow standard conventions (401 unauthenticated, 403 forbidden, 404 not found, 422 validation error, 429 rate-limited, 5xx server error).
{
"error": "unauthorized",
"message": "Invalid or expired API token."
}
Endpoints
GET /me - Current user
curl https://igmsg.com/api/v1/me \
-H "Authorization: Bearer igmsg_YOUR_TOKEN"
{
"id": 42,
"name": "Manish Sharma",
"email": "manish@example.com",
"plan": "pro",
"created_at": "2026-01-12T08:30:11+00:00"
}
GET /instagram-accounts - List connected IG accounts
{
"data": [
{
"id": 7,
"username": "yourbrand",
"ig_user_id": "17841401234567890",
"profile_picture_url": "https://...",
"is_connected": true,
"token_expires_at": "2026-07-15T12:00:00+00:00",
"connected_at": "2026-04-02T09:14:33+00:00"
}
]
}
GET /posts - List posts
Paginated. Query params: per_page (1-100, default 25), instagram_account_id (filter).
curl "https://igmsg.com/api/v1/posts?per_page=10&instagram_account_id=7" \
-H "Authorization: Bearer igmsg_YOUR_TOKEN"
GET /automations - List automations
Paginated. Returns automation objects with their linked post.
POST /automations - Create automation
curl -X POST https://igmsg.com/api/v1/automations \
-H "Authorization: Bearer igmsg_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"post_id": 123,
"name": "Spring launch",
"keywords": ["SHOP", "BUY"],
"keyword_match_mode": "exact",
"message_template": "Here's the link! {{link}}",
"is_active": true
}'
Returns 201 with the created automation. Required fields: post_id, name, keywords, message_template. Optional: keyword_match_mode (exact|contains|any, default exact), button_url, button_text, reply_to_comment, reply_template, delay_seconds (0-3600), is_active.
GET /automations/{id} - Get one automation
PUT /automations/{id} - Update automation
Same field validation as create, but all fields are optional. Returns the updated automation.
POST /automations/{id}/toggle - Activate/deactivate
Flips is_active. Returns the updated automation.
DELETE /automations/{id} - Delete automation
Returns { "deleted": true }.
GET /dm-logs - List DM delivery logs
Paginated. Filters: status (sent|failed|queued), automation_id, since (ISO 8601 timestamp).
curl "https://igmsg.com/api/v1/dm-logs?status=sent&since=2026-05-01T00:00:00Z" \
-H "Authorization: Bearer igmsg_YOUR_TOKEN"
Webhooks
IGMsg sends HTTPS POST requests to URLs you register at igmsg.com/developer. Every request is signed and idempotency-safe.
Configuration
Each endpoint gets a unique signing secret (starts with whsec_) generated when you create it. Use this to verify webhook authenticity.
Available events
dm.sent- a DM was successfully delivereddm.failed- a DM send failed (rate limit, expired token, etc.)automation.created- new automationautomation.updated- automation modifiedautomation.toggled- activated or deactivatedautomation.deleted- automation removedinstagram.connected- IG account linkedinstagram.disconnected- IG account unlinked
Payload format
{
"event": "dm.sent",
"created_at": "2026-05-17T15:42:11+00:00",
"data": {
"dm_log_id": 9182,
"automation_id": 47,
"instagram_account_id": 7,
"recipient_username": "fan_handle",
"recipient_ig_id": "17841...",
"comment_id": "17926...",
"comment_text": "SHOP"
}
}
Request headers
Content-Type: application/jsonUser-Agent: IGMsg-Webhook/1.0X-IGMsg-Event- the event name (same aseventin body)X-IGMsg-Delivery- unique delivery ID (use to deduplicate retries)X-IGMsg-Signature-t={timestamp},v1={hmac_sha256_signature}
Signature verification
The signature is computed as:
signed_payload = "{timestamp}.{request_body}"
signature = HMAC-SHA256(signed_payload, your_signing_secret)
Reject requests where the computed signature doesn't match. Also reject requests where timestamp is more than 5 minutes old (replay protection).
PHP example
$secret = 'whsec_...';
$header = $_SERVER['HTTP_X_IGMSG_SIGNATURE'] ?? '';
preg_match('/t=(\d+),v1=([a-f0-9]+)/', $header, $m);
[$_, $timestamp, $providedSig] = $m;
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', "{$timestamp}.{$body}", $secret);
if (!hash_equals($expected, $providedSig)) {
http_response_code(401);
exit('Bad signature');
}
if (abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit('Timestamp too old');
}
$payload = json_decode($body, true);
// ... handle event ...
Node.js example
const crypto = require('crypto');
function verify(req, secret) {
const header = req.headers['x-igmsg-signature'] || '';
const m = header.match(/t=(\d+),v1=([a-f0-9]+)/);
if (!m) return false;
const [, timestamp, providedSig] = m;
if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${req.rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(providedSig));
}
Retries
If your endpoint returns a non-2xx status (or times out after 30s), we retry with exponential backoff: 1 min, 5 min, 15 min, 1 hour, 4 hours. After 5 failed attempts the specific delivery is marked failed but the endpoint stays active. After 20 consecutive failures across deliveries, the endpoint is auto-disabled and you'll need to re-enable it from /developer.
Idempotency
The same event will never be delivered twice with the same X-IGMsg-Delivery header value. Store that ID server-side and ignore duplicates if you see one.
Need help?
Email hello@igmsg.com with the request ID (in any non-2xx API response under error.request_id) and we'll look it up.