Militant API wiki

Endpoints List

Supporting pages, examples and technical details in a cleaner layout.

Complete documentation for all Militant API endpoints. You can also view the dynamic JSON endpoint list on /api/v1/index.php.

Access Levels & Roles

The API distinguishes between different roles, especially for moderation and live streaming:

See the full Translation guide

Fediverse (ActivityPub)

MILITANT supports the ActivityPub protocol — the open standard for decentralized social networks (Mastodon, Pleroma, Misskey, PeerTube…).

WebFinger Discovery

MILITANT users can be found from any Fediverse instance using their address:

@username@your-domain.com

This uses the WebFinger protocol exposed at:

GET /.well-known/webfinger?resource=acct:username@your-domain.com

ActivityPub Actor Profile

Each user has a JSON-LD Person profile accessible via:

GET /fediverse/actor.php?username={username}
Accept: application/activity+json

Response includes: identity, bio, avatar, banner, inbox, outbox, RSA public key.

Publication Feed (Outbox)

The 20 latest public posts of a user are available in ActivityPub format:

GET /fediverse/outbox.php?username={username}
Accept: application/activity+json

Fediverse Followers

GET /fediverse/followers.php?username={username}          → Main collection (total count)
GET /fediverse/followers.php?username={username}&page=1   → Page 1 of followers

---

Fediverse API (mobile app)

| Endpoint | Method | Description | |----------|--------|-------------| | /api/v1/fediverse.php?action=profile | GET | Own Fediverse profile | | /api/v1/fediverse.php?action=profile&user_id={id} | GET | Another user's Fediverse profile | | /api/v1/fediverse.php?action=followers | GET | Own Fediverse followers (paginated) | | /api/v1/fediverse.php?action=followers&user_id={id} | GET | Another user's Fediverse followers | | /api/v1/fediverse.php?action=following | GET | Own remote Fediverse following list (paginated) | | /api/v1/fediverse.php?action=following&user_id={id} | GET | Another user's remote Fediverse following list | | /api/v1/fediverse.php?action=feed | GET | Feed of posts from followed remote Fediverse accounts | | /api/v1/fediverse.php?action=feed&refresh=1 | GET | Refresh followed remote outboxes before returning the feed | | /api/v1/fediverse.php?action=search_remote&q={handle} | GET | Resolve or search a remote Fediverse account | | /api/v1/fediverse.php?action=remote_profile&q={handle_or_actor_url} | GET | Resolve a single remote Fediverse profile with recent posts | | /api/v1/fediverse.php?action=follow_remote | POST | Follow a remote Fediverse account | | /api/v1/fediverse.php?action=unfollow_remote | DELETE | Unfollow a remote Fediverse account |

#### Response action=profile

{
  "user_id": 42,
  "username": "anar",
  "actor_id": "https://domain.com/users/anar",
  "fediverse_handle": "@anar@domain.com",
  "fediverse_active": true,
  "followers_count": 17,
  "following_count": 9,
  "is_remote": false,
  "account_type": "local"
}

#### Response action=feed

{
  "posts": [
    {
      "id": 12,
      "remote_post_id": "https://mastodon.social/@alex/1143596789",
      "original_url": "https://mastodon.social/@alex/1143596789",
      "actor_url": "https://mastodon.social/users/alex",
      "username": "alex",
      "display_name": "Alex",
      "domain": "mastodon.social",
      "handle": "@alex@mastodon.social",
      "avatar": "https://mastodon.social/system/accounts/avatars/...",
      "content": "

Hello Fediverse

", "media_url": null, "media_type": null, "published_at": "2026-04-19 10:10:00", "created_at": "2026-04-19 10:12:00", "profile_url": "https://mastodon.social/@alex", "is_remote": true, "account_type": "remote" } ], "meta": { "current_page": 1, "per_page": 20, "total": 1, "total_pages": 1 }, "synced_posts": 3 }

#### Response action=remote_profile

{
  "actor_url": "https://mastodon.social/users/alex",
  "username": "alex",
  "display_name": "Alex",
  "domain": "mastodon.social",
  "handle": "@alex@mastodon.social",
  "avatar": "https://mastodon.social/system/accounts/avatars/...",
  "summary": "Union organizer and developer",
  "profile_url": "https://mastodon.social/@alex",
  "is_following": true,
  "is_remote": true,
  "account_type": "remote",
  "recent_posts": [
    {
      "remote_post_id": "https://mastodon.social/@alex/1143596789",
      "content": "

Hello Fediverse

", "published_at": "2026-04-19 10:10:00" } ] }

For POST /api/v1/fediverse.php?action=follow_remote and DELETE /api/v1/fediverse.php?action=unfollow_remote, the JSON body may contain one of these fields:

{
  "handle": "@alex@mastodon.social"
}

or:

{
  "actor_url": "https://mastodon.social/users/alex"
}

> Note: GET /api/v1/users.php also returns fediverse_actor_id, fediverse_followers_count, fediverse_following_count, fediverse_handle, is_remote, and account_type.

Technical Implementation Status

| Feature | Status | |---|---| | WebFinger discovery | ✅ Implemented | | Actor JSON-LD profile | ✅ Implemented | | Auto-generated RSA keys | ✅ Implemented | | Public post feed (Outbox) | ✅ Implemented | | Inbox (receiving activities) | ✅ Implemented | | Outgoing HTTP Signatures | ✅ Implemented | | Incoming signature verification | ✅ Implemented | | Signed Accept(Follow) response | ✅ Implemented | | Remote followers persisted in DB | ✅ Implemented | | Remote following persisted in DB | ✅ Implemented | | Remote profile resolution | ✅ Implemented | | Remote follow / unfollow via API | ✅ Implemented | | Remote feed synchronization and storage | ✅ Implemented |

Rate Limiting

All requests are rate-limited by endpoint:

| Endpoint | Limit | |----------|-------| | Auth | 50 req/h | | Posts | 100 req/h | | Comments | 150 req/h | | Comment Reactions | 200 req/h | | Messages | 200 req/h | | Likes/Reactions | 200 req/h | | Group Reactions | 200 req/h | | Upload | 50 req/h | | Export | 5 req/h | | Others | 100 req/h |

See README API

Audio/Video Calls (Flutter only)

Warning: Exclusive to the Flutter mobile app - Requires the header X-Flutter-App: militant-flutter-v1

| Endpoint | Method | Description | |----------|--------|-------------| | /api/v1/calls.php?action=initiate_talk | POST | Invite a group to a Nextcloud Talk room | | /api/v1/calls.php?action=initiate | POST | Start a 1-to-1 or group call | | /api/v1/calls.php?action=answer | POST | Answer a call | | /api/v1/calls.php?action=join | POST | Join a group call | | /api/v1/calls.php?action=peer_offer | POST | Send a WebRTC offer (group) | | /api/v1/calls.php?action=peer_answer | POST | Send a WebRTC answer (group) | | /api/v1/calls.php?action=ice_candidate | POST | Exchange ICE candidates | | /api/v1/calls.php?action=ice_restart | POST | Restart ICE (network change) | | /api/v1/calls.php?action=reject | POST | Reject a call | | /api/v1/calls.php?action=leave | POST | Leave a group call without ending it | | /api/v1/calls.php?action=end | POST | End a call | | /api/v1/calls.php?action=poll | GET | Poll for updates | | /api/v1/calls.php?action=history | GET | Call history |

Examples

Start a private call:

POST /api/v1/calls.php?action=initiate
Headers:
  Authorization: Bearer {token}
  X-Flutter-App: militant-flutter-v1
Body:
{
  "recipient_id": 123,
  "call_type": "audio",
  "offer": "v=0\r\no=- 123456..."
}

Start a group call:

POST /api/v1/calls.php?action=initiate
Headers:
  Authorization: Bearer {token}
  X-Flutter-App: militant-flutter-v1
Body:
{
  "group_id": 456,
  "call_type": "video",
  "offer": "v=0\r\no=- 123456..."
}