API Reference

REST API, JSON responses, standard HTTP codes. All mutating endpoints require authentication.

Base URL:

All list endpoints accept a ?share=<token> query param for public read-only access without authentication.

BadgeMeaning
AuthJWT or API-Key required
OwnerPrimary owner or co-owner
O/COwner, co-owner, or collaborator with sufficient permissions
PrimaryPrimary owner only (not co-owners)
AdminAdmin role required

Authentication

POST /api/v1/auth/login
REQUEST
{ "email": "user@example.com", "password": "..." }
RESPONSE
{ "token": "eyJ...", "user": { "user_id": "...", "display_name": "Ghost" } }

Include the token: Authorization: Bearer <token>

Or use a long-lived API Key: X-API-Key: <key> (manage in Settings → API Keys)

Note: The API is completely stateless and does not use or set cookies for authentication. You must always provide the Bearer token or API key.
ENDPOINTS
MethodPathNotes
GET /api/v1/auth/me Current user info: id, email, display_name, role, is_approved.
POST /api/v1/auth/magic Request a magic-link login email. Body: { "email": "..." }.
GET /api/v1/auth/magic/verify Verify magic link token from email. Query: ?token=. Returns JWT.
GET /api/v1/auth/discord Redirect to Discord OAuth2 login flow.
GET /api/v1/auth/discord/callback Discord OAuth2 callback. Returns JWT on success.
GET /api/v1/auth/email-verify Verify a new email address. Query: ?token=.
Users
GET /api/v1/users/search Auth

Live user search for autocomplete (collaborator/co-owner/group-member pickers). Query: ?q= (min 2 chars).

{ "users": [{ "id": "...", "display_name": "Ghost" }] }
Settings & Account
MethodPathAuthNotes
PUT /api/v1/settings/display-nameAuth Update display name. Body: { "display_name": "..." }
DELETE /api/v1/settings/accountAuth Permanently deletes account and all associated data.
API Keys
MethodPathAuthNotes
GET /api/v1/api-keysAuth Lists all API keys for the current user.
POST /api/v1/api-keysAuth Generates a new API key. Body: { "name": "..." }

Mods

GET /api/v1/mods

Browse the mod catalog. Query params: search, tag, sort (name_asc, name_desc, size_desc, updated_desc), page, limit (max 100).

{ "mods": [{...}], "total": 1250, "pages": 63 }
GET /api/v1/mods/autocomplete

Fast autocomplete search. Query param: q.

[{ "workshop_id": "...", "name": "...", "image_url": "..." }]
GET /api/v1/mods/:workshopID

Full mod metadata including dependency_ids, tags, image_url, author, summary.

Sub-Resources — /api/v1/mods/:workshopID/...
PathDescription
/metadataLightweight metadata (DB only, no extra tables).
/itemsWeapons, vehicles, gear. Filter: ?type=vehicle|weapon|gear, ?version=
/missionsExtracted scenarios. Filter: ?version=
/depsDependency graph with sizes.
/versionsFull version history & changelogs.
/screenshotsOfficial screenshot gallery.
/item-versionsVersions that have extracted item data available.
/diffItem diff between two versions. Query: ?from=&to=
/statsLive current stats: { used_by_servers_count, players_using_count, dependencies_count, dependents_count }. Server counts/player sums only include servers seen online in the last hour.
/stats/growthHistorical stats snapshots (3-hourly, 180-day retention). Query: ?days=1..180 (default 30). Returns [{ time, used_by_servers_count, players_using_count, dependencies_count, dependents_count }].
/stats/growth/rangeOldest available stats snapshot for this mod (or null if none yet). Returns { oldest }.

Mod Lists

CRUD
MethodPathAuthNotes
GET /api/v1/lists Public lists. Add ?public=1. Or /lists/mine (Auth) for your own.
POST /api/v1/listsAuth Body: { "name", "description", "is_public" }
GET /api/v1/lists/:id List detail + items, tags, dependency tree, missing deps.
PUT /api/v1/lists/:idOwner Update name / description / visibility.
DELETE /api/v1/lists/:idPrimary Permanently deletes list, items, versions, audit log.
PATCH /api/v1/lists/:id/communityOwner Assign list to community: {"community_id": "uuid"}
PATCH /api/v1/lists/:id/folderOwner Assign list to folder: {"folder_id": "uuid"}
Mod Management
MethodPathAuthNotes
POST /api/v1/lists/:id/modsO/C Body: { "workshop_id": "..." }. Auto-scrapes unknown mods.
DELETE /api/v1/lists/:id/mods/:workshopIDO/C Remove a mod from the list.
PUT /api/v1/lists/:id/mods/:workshopID/versionO/C Pin/unpin version. Body: { "version": "1.2.3" } or { "version": null }.
POST /api/v1/lists/:id/mods/reorderO/C Save manual sort order. Body: { "order": ["workshopID", ...] }
POST /api/v1/lists/:id/rescrapeO/C Enqueues a background rescrape for all mods in the list.
Templates
MethodPathAuthNotes
GET /api/v1/lists/:id/template-linksO/C Lists templates this list is subscribed to.
DELETE /api/v1/lists/:id/template-links/:templateIDO/C Removes a template subscription.
POST /api/v1/templates/:id/pushOwner Pushes template updates to all subscribed lists.
Collaborators & Co-Owners

Collaborators can add/remove mods based on their per-list permissions. Co-owners have full management rights (same as the primary owner), except they cannot delete the list or add/remove other co-owners.

COLLABORATORS
MethodPathAuthNotes
GET /api/v1/lists/:id/collaboratorsO/C All collaborators with their permission flags.
POST /api/v1/lists/:id/collaboratorsOwner Add collaborator. Body: { "search": "name_or_email" }
DELETE /api/v1/lists/:id/collaborators/:userIDOwner Remove collaborator.
PUT /api/v1/lists/:id/collaborators/:userID/permissionsOwner Update per-user flags. Body: { "can_add": true, "can_remove": true, "can_deploy": false }
POST /api/v1/lists/:id/share-token/resetOwner Regenerate the public share token. Returns { "share_token": "..." }
POST /api/v1/lists/:id/suggestion-token/resetOwner Regenerate the suggestion link token. Returns { "suggestion_token": "..." }
CO-OWNERS
MethodPathAuthNotes
GET /api/v1/lists/:id/ownersOwner List all co-owners. Returns { "owners": [{ "user_id", "display_name", "added_at" }] }
POST /api/v1/lists/:id/ownersPrimary Add co-owner. Body: { "search": "name_or_email" }
DELETE /api/v1/lists/:id/owners/:userIDPrimary Remove co-owner.
Permission Groups on a List

Assign a permission group to a list so all group members gain access. Per-list overrides can be set to differ from the group's defaults.

MethodPathAuthNotes
GET /api/v1/lists/:id/groupsOwner All groups assigned to this list, with their effective permission flags.
POST /api/v1/lists/:id/groupsOwner Assign a group. Body: { "group_id": "...", "can_add": null, "can_remove": null, "can_deploy": null } — null means inherit from group defaults.
PATCH /api/v1/lists/:id/groups/:groupIDOwner Update per-list permission overrides. Body: same as POST (null = reset to group default).
DELETE /api/v1/lists/:id/groups/:groupIDOwner Remove group from this list. Group members lose access.
Tags

Users manage their own tag library and attach tags to lists for filtering.

MethodPathAuthNotes
GET /api/v1/tags All tags in the system (public).
GET /api/v1/tags/mineAuth Your personal tags.
POST /api/v1/tags/mineAuth Create tag. Body: { "name": "...", "color": "#hex" }
DELETE /api/v1/tags/mine/:tagIDAuth Delete your tag.
GET /api/v1/lists/:id/tags Tags assigned to a list.
POST /api/v1/lists/:id/tagsOwner Assign tag to list. Body: { "tag_id": "..." }
DELETE /api/v1/lists/:id/tags/:tagIDOwner Remove tag from list.
Pins & Templates
PINS
MethodPathAuthNotes
GET /api/v1/lists/pinsAuth Your pinned lists.
POST /api/v1/lists/:id/pinAuth Toggle pin on a list. Returns { "pinned": true|false }
TEMPLATES
MethodPathAuthNotes
GET /api/v1/templates All available starter templates.
POST /api/v1/templatesAuth Create template from an existing list. Body: { "list_id": "...", "name": "..." }
DELETE /api/v1/templates/:idAdmin Delete a template.
POST /api/v1/lists/:id/import-template/:tidO/C Apply a template to a list (adds all template mods).
Deploy Approval

When require_deploy_approval is enabled on a list, collaborators' deployments queue as deploy-requests that an owner must approve or reject.

MethodPathAuthNotes
PUT /api/v1/lists/:id/require-deploy-approvalOwner Enable/disable approval gate. Body: { "require_deploy_approval": true }
GET /api/v1/lists/:id/deploy-requestsOwner Pending and resolved deploy-requests for a list.
PATCH /api/v1/deploy-requests/:idOwner Approve or reject. Body: { "status": "approved"|"rejected", "note": "..." }
Moderation

Block specific users from submitting suggestions to a list.

MethodPathAuthNotes
GET /api/v1/lists/:id/blocksOwner List all blocked users for this list.
POST /api/v1/lists/:id/blocksOwner Block a user. Body: { "user_id": "..." }
DELETE /api/v1/lists/:id/blocks/:userIDOwner Unblock a user.
Import from server.json

Two-step workflow: preview the diff, then apply atomically. Both endpoints accept the same body.

POST /api/v1/lists/:id/import-preview O/C

Query: ?check_order=true to compare and return order changes.

REQUEST — any of these formats
// Full server.json
{ "game": { "mods": [{...}] } }

// Simplified
{ "mods": [{ "modId": "...", "name": "...", "version": "..." }] }

// Fragment
"mods": [{ "modId": "...", ... }]

// Array fragment
[{ "modId": "...", ... }]
RESPONSE
{
  "added":   [{ "workshop_id", "name", "version", "size_bytes", "in_catalog" }],
  "removed": [{ "workshop_id", "name" }],
  "version_changed": [{ "workshop_id", "name", "old_version", "new_version" }],
  "order_changed": [{ "workshop_id", "name", "old_index", "new_index" }],
  "unchanged": [...],
  "not_in_catalog": [{ "mod_id", "name", "version" }]
}
POST /api/v1/lists/:id/import-apply O/C

Same body as import-preview. Applies all changes atomically and records one audit log entry for the entire import. Pass ?check_order=true to also reorder the mods based on the JSON array.

{ "ok": true, "added": 5, "removed": 2, "version_changed": 1 }
Snapshots / Versioning

Snapshots are named point-in-time copies of the full mod list. They can be diffed against each other or against the current live state.

MethodPathAuthNotes
GET /api/v1/lists/:id/versions All snapshots, newest first. Includes snapshot_json array.
POST /api/v1/lists/:id/versionsO/C Create snapshot. Body: { "version_name", "tag", "notes", "is_release" } — all optional.
GET /api/v1/lists/:id/versions/live Current list as a snapshot object (for diff comparison).
GET /api/v1/lists/:id/versions/:versionID Single snapshot detail.
PATCH /api/v1/lists/:id/versions/:versionIDO/C Update version_name, tag, notes, is_release.
DELETE /api/v1/lists/:id/versions/:versionIDO/C Delete snapshot permanently.
Snapshot JSON format
[{ "modId": "5965550FD8C7F516", "name": "RHS Status Quo", "version": "0.9.1" }, ...]
Audit Log

Every mutation is logged. Individual entries can be individually undone.

MethodPathAuthNotes
GET /api/v1/lists/:id/auditO/C Last 100 entries, newest first. Each has action, mod_name, old_value, new_value, reverted.
POST /api/v1/lists/:id/audit/:entryID/revertO/C Undo a single entry. Idempotent. Returns { "ok": true }.
Action types
actionold_valuenew_value
add_mod
remove_mod{ "version": "..." }
update_version{ "version": "..." }{ "version": "..." }
import{ "removed": [...], "version_changed": [...] }{ "added": [...], "version_changed": [...] }
Export
MethodPathNotes
GET /api/v1/lists/:id/export?type=fixed Download server.json with pinned versions. type=latest uses latest available.
GET /api/v1/lists/:id/export/arma?type=fixed Export in native Arma Reforger server.json format.

Suggestions

Community members can suggest mods to add to a list. Owners review and accept/reject. Voting is open to all logged-in users.

MethodPathAuthNotes
GET /api/v1/lists/:id/suggestionsO/C All pending/reviewed suggestions for a list.
POST /api/v1/lists/:id/suggestionsAuth Suggest a mod. Body: { "workshop_id", "reason", "form_answers": [...] }
POST /api/v1/lists/:id/suggestions/:suggID/voteAuth Upvote or retract vote. Body: { "vote": 1 } (1 = up, 0 = retract).
PATCH /api/v1/lists/:id/suggestions/:suggIDO/C Update suggestion status. Body: { "status": "accepted"|"rejected", "note": "..." }. Accepting immediately adds the mod.
DELETE /api/v1/lists/:id/suggestions/:suggIDO/C Delete a suggestion.
Suggestion Form Fields

Customize the suggestion form with extra questions (text, checkbox, select) shown to users when they submit a suggestion.

MethodPathAuthNotes
GET /api/v1/lists/:id/form-fields All custom fields for the suggestion form.
POST /api/v1/lists/:id/form-fieldsOwner Create field. Body: { "label", "type": "text"|"checkbox"|"select", "required": false, "options": [...] }
PUT /api/v1/lists/:id/form-fields/:fieldIDOwner Update field. Same body as POST.
DELETE /api/v1/lists/:id/form-fields/:fieldIDOwner Delete field.

Organization (Folders & Communities)

FOLDERS
MethodPathAuthNotes
GET /api/v1/foldersAuth Lists all folders for the authenticated user.
POST /api/v1/foldersAuth Creates a new folder. Body: { "name": "..." }
COMMUNITIES
MethodPathAuthNotes
GET /api/v1/communitiesAuth Lists all communities the user is a member of.
POST /api/v1/communitiesAuth Creates a new community. Body: { "name": "...", "description": "..." }

Permission Groups

Permission groups let you manage collaborator access across multiple lists at once. Create a group, add members, then assign it to any list. Co-owners of a group can add and remove members. Only the primary group owner can rename the group or manage co-owners.

GROUP CRUD
MethodPathAuthNotes
GET /api/v1/groupsAuth Your groups (primary owner + co-owned). Each object has is_primary_owner: bool.
POST /api/v1/groupsAuth Create group. Body: { "name", "description", "can_add", "can_remove", "can_deploy" }
PUT /api/v1/groups/:groupIDPrimary Update name / description / default permissions. Primary owner only.
DELETE /api/v1/groups/:groupIDPrimary Delete group. Members lose access on all assigned lists.
POST /api/v1/groups/:groupID/assign_communityPrimary Assigns group to community. Body: { "community_id": "uuid" }
GROUP MEMBERS
MethodPathAuthNotes
GET /api/v1/groups/:groupID/membersOwner All members. Returns { "members": [{ "user_id", "display_name", "added_at" }] }
POST /api/v1/groups/:groupID/membersOwner Add member. Body: { "search": "name_or_email" }
DELETE /api/v1/groups/:groupID/members/:userIDOwner Remove member.
GROUP CO-OWNERS
MethodPathAuthNotes
GET /api/v1/groups/:groupID/ownersOwner All co-owners. Returns { "owners": [{ "user_id", "display_name", "added_at" }] }
POST /api/v1/groups/:groupID/ownersPrimary Add co-owner. Body: { "search": "name_or_email" }
DELETE /api/v1/groups/:groupID/owners/:userIDPrimary Remove co-owner. Primary owner only.

Game Servers

Register your Arma Reforger game servers and deploy mod lists via Pterodactyl Panel or SFTP. Credentials are stored AES-256-GCM encrypted.

SERVER CRUD
MethodPathNotes
GET /api/v1/servers Your registered game servers.
POST /api/v1/servers Register. Body: { "name", "connection_type": "pterodactyl"|"sftp", "file_path", "linked_list_id", "auto_deploy" }
GET /api/v1/servers/:id Server detail + last test status.
PUT /api/v1/servers/:id Update name / file path / linked list / auto-deploy.
DELETE /api/v1/servers/:id Delete server + credentials.
POST /api/v1/servers/:id/credentials Auth
PTERODACTYL
{
  "panel_url": "https://panel.example.com",
  "api_key": "ptlc_...",
  "server_uuid": "abc123"
}
SFTP
{
  "host": "192.168.1.10",
  "port": 22,
  "username": "root",
  "password": "..."
}
DEPLOYMENT & CONTROL
MethodPathNotes
POST /api/v1/servers/:id/test Queue a connection test. Returns { "deployment_id" }. Poll /deployments for result.
POST /api/v1/servers/:id/deploy Trigger deployment of the linked list. Body: { "list_id": "..." } (optional override).
POST /api/v1/servers/:id/deploy-request Submit a deploy-request (if the list has approval gate enabled). Returns { "request_id" }.
GET /api/v1/servers/:id/deployments Deployment history. Each entry: status, item_count, snapshot_json, error_message.
Deployments run in a dedicated deploy-worker. Status: pendingrunningsuccess | failed.

Arma Reforger Live Servers

Read-only public endpoints for discovered Arma Reforger servers. No authentication required. Default limit 100, max 200.

SERVER LIST & DETAIL
MethodPathNotes
GET /api/v1/arma-servers Paginated list of live servers. Query params: limit (default 100, max 200), offset, search (full-text, multiple words), sort_by (recent | popularity | players_desc | players_asc | mod_size_desc | mod_size_asc | name_asc | name_desc), mod_ids (comma-separated workshop IDs), min_players, max_mod_size (bytes), official (bool), password_protected (bool), tags (comma-separated).
GET /api/v1/arma-servers/:id Server detail. Returns { server, mods[], mod_items[] }. mods[] is the full current mod list (unpaginated) and scanned items (weapons, vehicles, gear) — used internally for the "Copy Modlist" diff preview. For a paginated, display-friendly mod list use /mods below.
GET /api/v1/arma-servers/:id/mods Paginated current mod list. Query: page (default 1), limit (default 10, max 500). Returns { items[], total, total_size_bytes, page, pages, limit }. total_size_bytes is the sum across all mods, not just the current page.
GET /api/v1/arma-servers/:id/stats Player & queue count history. Query: ?days=1|7|14|30|90|180|365 (default 7). Resolution is auto-selected server-side: raw 5-min data for 24h, hourly buckets up to 14 days, 3-hour buckets beyond. Returns [{ time, player_count, queue_players_count, wait_time_estimation }].
GET /api/v1/arma-servers/:id/stats/range Oldest timestamp with data for this server (or null if none yet). Used by the frontend to only offer time ranges fully backed by data. Returns { oldest }.
GET /api/v1/arma-servers/:id/mod-changelog Paginated history of mod additions, removals, and version changes for this server. Query: page (default 1), limit (default 10, max 500). Returns { items: [{ timestamp, action, workshop_id, mod_name, old_version, new_version, size_bytes }], total, page, pages, limit }.
MOD ↔ SERVER RELATIONS
MethodPathNotes
GET /api/v1/mods/:workshopID/servers All live servers currently using this mod. Sorted by player count descending.
POST /api/v1/modlists/copy-from-server/:id Auth Copy a server's current mod list into a new or existing list. Body: { "list_name": "...", "is_public": false } to create new, or { "list_id": "uuid" } to overwrite existing (must be owner). Returns { "list_id" }.
POST /api/v1/arma-servers/:id/community Auth Assign or unassign the server to one of your communities. Body: { "community_id": "uuid" } or { "community_id": "" } to unassign.
STATISTICS
MethodPathNotes
GET /api/v1/stats/top-servers Top 10 servers by average player count over the last 7 days. Returns [{ id, name, avg_players }].
GET /api/v1/stats/top-mods Top 10 mods by number of servers currently using them. Returns [{ workshop_id, name, server_count }].
GET /api/v1/stats/global-players Global player & server count over time. Query: ?days=1|7|14|30|90|180|365 (default 7). Same auto-resolution as server stats (raw / hourly / 3-hour buckets). Returns [{ time, total_players, total_servers_online }].
GET /api/v1/stats/global-players/range Oldest timestamp with global stats data (or null). Returns { oldest }.
GET /api/v1/stats/community-players/:community_id Combined player & queue count over time across all servers of a community. Query: ?days=1|7|14|30|90|180|365 (default 7), same auto-resolution as above. Returns [{ time, total_players, total_queue, online_servers }].
GET /api/v1/stats/community-players/:community_id/range Oldest timestamp with data across the community's servers (or null). Returns { oldest }.
Example: GET /api/v1/arma-servers
REQUEST
GET /api/v1/arma-servers
  ?search=tactical
  &mod_ids=A1B2C3,D4E5F6
  &min_players=5
  &sort_by=players
  &limit=50
RESPONSE
[
  {
    "id": "uuid",
    "name": "Tactical Ops",
    "host_address": "...",
    "player_count": 32,
    "player_count_limit": 64,
    "queue_players_count": 4,
    "scenario_name": "...",
    "game_version": "1.6.0",
    "password_protected": false,
    "last_updated": "2026-08-02T..."
  }
]

Webhooks

Receive real-time notifications when mods are added/removed or new versions are available. Supports Discord and custom HTTP endpoints.

MethodPathNotes
GET/api/v1/settings/webhooksYour webhooks.
POST/api/v1/settings/webhooksCreate. Body: { "url", "type": "discord"|"custom", "events": [...], "scope": "global"|"list", "list_id" }
PUT/api/v1/settings/webhooks/:idUpdate URL, events, or scope.
DELETE/api/v1/settings/webhooks/:idDelete webhook.
POST/api/v1/settings/webhooks/:id/testSend a test payload to verify the endpoint.

Notifications

MethodPathNotes
GET/api/v1/notificationsInbox. Query: ?unread=1, ?limit=.
GET/api/v1/notifications/unread-countReturns { "count": N }. Not rate-limited — safe for frequent polling.
PATCH/api/v1/notifications/:id/readMark single notification as read.
POST/api/v1/notifications/read-allMark all as read.
GET/api/v1/settings/notificationsNotification preferences per event type.
PUT/api/v1/settings/notificationsUpdate preferences. Body: { "events": { "mod_updated": true, ... } }

Jobs & Scrapers

Background job management. Most endpoints require Admin role.

MethodPathAuthNotes
POST/api/v1/jobs/scraper/detailScrape a specific mod. Body: { "workshop_id": "..." }. Rate limited: 10/hour per IP.
POST/api/v1/jobs/scraperAuthTrigger full workshop discovery + detail scrape.

Prometheus Metrics

Per-entity Prometheus exposition endpoints — one scrape target per mod, server, or community. No authentication required. Content type is standard Prometheus text exposition format (text/plain; version=0.0.4), so these can be added directly as static scrape_configs targets. Unknown IDs return 404.

MethodPathMetrics exposed
GET /mod/:workshopID/metrics modiscover_mod_info (labels: workshop_id, name, author), modiscover_mod_size_bytes, modiscover_mod_dependencies, modiscover_mod_dependents, modiscover_mod_used_by_servers, modiscover_mod_players_using.
GET /servers/:id/metrics modiscover_server_info (labels: server_id, name, host_address, scenario_name, game_version, official, password_protected), modiscover_server_online (1 if the server reported in within the last hour), modiscover_server_players, modiscover_server_queue_players, modiscover_server_wait_time_seconds, modiscover_server_player_limit, modiscover_server_mods_count, modiscover_server_mods_size_bytes.
GET /community/:slug/metrics modiscover_community_info (labels: community_id, slug, name), modiscover_community_servers_total, modiscover_community_servers_online, modiscover_community_players_total (sum across online servers), modiscover_community_queue_total, modiscover_community_public_lists_total.

Example: curl https://better-arma-workshop-add-admin-list.workshop.zb-server.de/servers/<server-id>/metrics. The platform-wide process/runtime metrics endpoint (Go GC, HTTP handler stats, etc.) is separately available at /metrics.

Error Codes

StatusMeaningExample body
200OK{ "ok": true }
204No Content — successful delete/update
400Bad Request — invalid input{ "error": "invalid JSON" }
401Unauthorized — missing/expired token{ "error": "unauthorized" }
403Forbidden — valid token, wrong role{ "error": "no permission" }
404Not Found{ "error": "list not found" }
409Conflict — duplicate, limit reached{ "error": "maximum number of mods (1000) reached" }
429Rate Limited{ "error": "rate limit exceeded" }
500Internal Server Error{ "error": "..." }
We only use strictly necessary cookies to securely maintain your login session. No tracking or advertising cookies are used. For more information, please see our Privacy Policy.
This site can embed mod preview images directly from ar-gcp-cdn.bistudio.com (Bohemia Interactive CDN) — without downloading to our servers. Load external content?