Afilipost ← Back to the front page

API reference

Every endpoint, with the bodies your program will actually see.

Base address: https://api.afilipost.com · Machine-readable schema: openapi.json

GET /v1/accounts

The accounts connected to your workspace. Filter with ?platform=instagram.

Response

{
  "accounts": [
    {
      "_id": "8b1e…7d",
      "platform": "instagram",
      "username": "afilipost",
      "displayName": "Afilipost",
      "isActive": true,
      "status": "ok",
      "profileId": { "_id": "0a4c…19" }
    }
  ]
}

POST /v1/media/presign

Ask for a signed upload address, then PUT the file straight to storage.

Request

{
  "filename": "reel.mp4",
  "contentType": "video/mp4",
  "size": 18432000
}

Response

{
  "mediaId": "3d90…aa",
  "uploadUrl": "https://…",   // buraya PUT
  "publicUrl": "https://cdn.afilipost.com/…mp4",
  "expiresIn": 3600,
  "contentType": "video/mp4"
}

The bytes never pass through the API. The signed address is valid for an hour; an upload already in flight is not cut off when it expires.

POST /v1/posts

Create or schedule a post. One post can target several accounts at once.

Request

{
  "content": "Today's repo: a terminal file manager.",
  "mediaItems": [
    { "type": "video",
      "url": "https://cdn.afilipost.com/…mp4",
      "filename": "reel.mp4",
      "mimeType": "video/mp4" }
  ],
  "platforms": [
    { "platform": "instagram",
      "accountId": "8b1e…7d",
      "platformSpecificData": {
        "shareToFeed": true,
        "firstComment": "Comment REPO for the link"
      } }
  ],
  "scheduledFor": "2026-08-24T19:40:00.000Z",
  "timezone": "UTC",
  "idempotencyKey": "repo-4192-tr"
}

Response

{
  "post": {
    "_id": "0f7a…42",
    "status": "scheduled",
    "scheduledFor": "2026-08-24T19:40:00.000Z",
    "platforms": [
      { "platform": "instagram",
        "accountId": "8b1e…7d",
        "status": "scheduled",
        "platformPostId": null }
    ]
  }
}

Send idempotencyKey and a retried request will not create a second post. Two extras neither competitor has: scheduledFor may be the literal string "auto" — the server picks the slot from the channel's rhythm (gap, daily cap, day window, collision buffer, isolated per API key); and a chain array attaches post-publish steps: [{kind:"crossPost", afterMinutes:5, accountIds:[…]}] publishes the same content elsewhere 5 minutes after this post goes live, [{kind:"followUp", …, content, mediaItems}] publishes new content.

GET /v1/posts

List posts. Filter with ?status=scheduled&accountId=…&limit=200.

Response

{ "posts": [ { "_id": "0f7a…42", "status": "scheduled", … } ] }

Useful for spacing your own queue: read what is already scheduled on an account before you pick the next slot.

GET /v1/posts/{id}

One post with its per-destination status.

Response

{
  "post": {
    "_id": "0f7a…42",
    "status": "published",
    "platforms": [
      { "platform": "instagram",
        "status": "published",
        "platformPostId": "17912…04",
        "permalink": "https://www.instagram.com/p/…",
        "publishedAt": "2026-08-24T19:40:12.000Z" }
    ]
  }
}

platformPostId is null until the post actually goes out. A comment automation needs it, so poll here before creating one.

POST /v1/comment-automations

Attach a keyword → DM rule to a published post.

Request

{
  "accountId": "8b1e…7d",
  "platformPostId": "17912…04",
  "name": "Repo link — TR",
  "keywords": ["repo", "link", "edit"],
  "matchMode": "contains",
  "typoTolerance": true,
  "commentReply": "Sent it to your DMs 📩",
  "dmMessage": "Here's the link. Follow for a new one daily.",
  "buttons": [
    { "type": "url", "title": "Open repo",
      "url": "https://github.com/…" }
  ],
  "followGate": {
    "message": "Follow first, then tap below 👇",
    "buttonLabel": "I'm following"
  }
}

Response

201 { "ok": true }

Instagram only, and the post must already be live. Calling it twice for the same post is not an error — it answers 200 with existing: true. Send followGate and the link is held behind a button: when it is tapped we read Meta's is_user_follow_business flag and only hand the link over to a follower. If Meta does not return that flag, the link is sent anyway — a real follower is never left waiting at the door.