API v1

Arma Reforger Mods API

An unofficial, cached JSON data source for Arma Reforger Workshop mod metadata. Built for bots, panels, dashboards, and server tooling.

Base URL:https://api.reforgermods.net

Use /v1 for all new integrations. Older unversioned routes remain available as deprecated aliases, but they will not receive new fields.

Data is normalized from publicly accessible Arma Reforger Workshop pages. Workshop fields, availability, and page structure can change without notice, so the API is not an authoritative source for ownership, entitlement, moderation, platform accounts, or real-time Workshop state.

Authentication & Identification

The public tier requires no API key. Send an identifying User-Agent or X-API-Client header so traffic can be supported without blocking legitimate tools.

Paid API keys can be sent with either X-API-Key or Authorization: Bearer. Paid limits are shared across all active keys on the same account, so creating additional keys does not multiply throughput.

Required header
User-Agent: my-discord-bot/2.1 (contact: [email protected])
Paid API key header
Authorization: Bearer rfm_live_...
X-API-Key: rfm_live_...

Rate Limits

Limits apply per resolved client IP on the public tier and per billing account on paid API key tiers. Every response includes rate-limit headers, and paid requests also include X-API-Plan.

60/minDefault limit per resolved client IP
300/minDeveloper plan account limit
1,200/minPro plan account limit
20 / 30 / 120Free, Developer, and Pro burst allowances

Call GET /v1/rate-limits with your API key to inspect the current plan, request limit, burst allowance, and whether the limit is shared by account or client IP.

On 429 Too Many Requests or 503 Service Unavailable, wait for Retry-After and retry later. Batch and cache on your side instead of polling, and do not request variations of the same query to bypass caching; there is no public cache-bypass or force-refresh parameter.

Caching & Refresh Jobs

Mod data is served from cache. If an ID or list has not been fetched recently, the API starts a refresh job and responds immediately instead of making your request wait on a live Workshop fetch.

Cold cache response
HTTP/1.1 202 Accepted
Retry-After: 3
Location: /v1/refresh/jobs/job_8841

{ "status": "refreshing", "jobId": "job_8841" }
200Fresh or stale cache hit.
202Refresh job started, retry after delay.
304ETag matched with If-None-Match.
404Resource not found in the Workshop.
429Rate limit exceeded, check Retry-After.

Cache lifetimes

ResourceFresh cacheStale fallback
Mod detail1 hour24 hours
Mod list and search10 minutes1 hour
Not found response10 minutesNone

Stale data may be served with X-Cache: STALE while a background refresh runs, so the API stays responsive when the upstream Workshop is slow or unavailable.

Response headers

HeaderMeaning
X-CacheHIT, STALE, or MISS
Retry-AfterHow long to wait before retrying
LocationRefresh-job URL on 202 Accepted
ETagValidator for conditional requests
X-RateLimit-*Current rate-limit state
X-Request-IdRequest identifier for support and debugging

Conditional requests

Responses include an ETag. Send it back in If-None-Match to get a free 304 Not Modified when nothing changed:

Conditional request
curl -H 'If-None-Match: W/"a1b2c3d4e5f6a7b8c9d0e1f2"' \
  "https://api.reforgermods.net/v1/mods?search=radio"
GET

/v1/health

Returns process health only. It does not request Workshop data.

curl https://api.reforgermods.net/v1/health
200 OK
{
  "status": "success",
  "data": { "code": 200, "alive": true }
}
GET

/v1/mods

Search and list cached Workshop mod previews. Supports search, sort, tags, and category.

curl -H "User-Agent: my-bot/1.0" \
  "https://api.reforgermods.net/v1/mods?search=radio&sort=newest&limit=20"

Query parameters

NameValues
searchOptional search text
sortpopularity, newest, subscribers, or version_size
tagsOptional Workshop tag filter. Repeat to include multiple tags.
categoryAlias for a single tags value, used by the browser UI.

The response returns a page of mod preview objects with pagination metadata and links. See the full list response structure.

GET

/v1/mods/{page}

Fetch a specific positive page number using the same response schema as /v1/mods.

curl -H "X-API-Client: my-app/1.0" \
  "https://api.reforgermods.net/v1/mods/2?search=radio&sort=newest&tags=GAMEPLAY"
GET

/v1/mod/{id}

Fetch one mod by Workshop ID, including dependencies and scenario metadata when available.

curl -H "User-Agent: my-bot/1.0" \
  "https://api.reforgermods.net/v1/mod/5965550F24A0C152"
200 OK
{
  "status": "success",
  "data": {
    "name": "Example Mod",
    "author": "Example Author",
    "originalModURL": "https://reforger.armaplatform.com/workshop/5965550F24A0C152",
    "apiModURL": "https://api.reforgermods.net/v1/mod/5965550F24A0C152",
    "imageURL": "https://example.com/image.png",
    "rating": "92%",
    "version": "1.1.0",
    "gameVersion": "1.1.0.34",
    "size": "192.42 KB",
    "subscribers": 66677,
    "downloads": 791142,
    "created": "19.05.2022",
    "lastModified": "17.03.2024",
    "id": "5965550F24A0C152",
    "summary": "Short Workshop summary",
    "description": "Workshop description",
    "license": "Arma Public License (APL)",
    "tags": ["GAMEPLAY"],
    "dependencies": [
      {
        "name": "Example Dependency",
        "originalModURL": "https://reforger.armaplatform.com/workshop/{dep_id}",
        "apiModURL": "https://api.reforgermods.net/v1/mod/{dep_id}"
      }
    ],
    "scenarios": [
      {
        "name": "Example Scenario",
        "description": "Scenario summary",
        "scenarioID": "{EXAMPLE}Missions/Example.conf",
        "gamemode": "Game Master",
        "playerCount": 16,
        "imageURL": "https://example.com/scenario-image.png"
      }
    ]
  }
}

dependencies, scenarios, tags, and optional metadata may be empty when the Workshop does not provide them. Field-by-field types are documented in the mod object structure.

GET

/v1/rate-limits

Returns the rate-limit tier resolved for the request. Send an API key to check the paid plan attached to that key; omit the key to see the public client-IP tier.

curl -H "Authorization: Bearer rfm_live_..." \
  https://api.reforgermods.net/v1/rate-limits
200 OK
{
  "authenticated": true,
  "rate_limit": {
    "plan": "pro",
    "limit_per_minute": 1200,
    "burst": 120,
    "window": "1 minute",
    "shared_by": "account",
    "active_key_limit": 10
  }
}

Invalid, revoked, or inactive paid keys return the same authentication errors as other API routes.

GET

/v1/refresh/jobs/{id}

Inspect refresh progress after a 202 Accepted response. Most clients can simply wait for Retry-After and retry the original URL.

curl "https://api.reforgermods.net/v1/refresh/jobs/9f0b7d0f6fd4f88a8bb0e455f0b640247a93"
200 OK
{
  "id": "9f0b7d0f6fd4f88a8bb0e455f0b640247a93",
  "status": "queued",
  "resource_url": "/v1/mods?search=radio",
  "retry_after_seconds": 2
}

Possible statuses are queued, running, succeeded, failed, and expired. After a job succeeds, request resource_url again; refresh-job responses do not contain the finished mod or list payload. Do not poll jobs faster than the advertised retry_after_seconds.

List Response Structure

List and search endpoints (/v1/mods, /v1/mods/{page}, /v1/search) share one response shape: pagination metadata in meta, an array of mod preview objects in data, and page URLs in links.

List response
{
  "status": "success",
  "meta": {
    "totalPages": 2593,        // int
    "currentPage": 2,          // int
    "totalMods": 41478,        // int
    "shownMods": 16,           // int
    "modsIndexStart": 17,      // int
    "modsIndexEnd": 32         // int
  },
  "data": [ { ...mod preview objects... } ],
  "links": {
    "next": "https://api.reforgermods.net/v1/mods/3?search=radio",
    "prev": "https://api.reforgermods.net/v1/mods/1?search=radio"
  }
}

Mod Preview Object

List and search endpoints return mod previews. Previews do not include every field from the detail endpoint.

Fetch /v1/mod/{id} for the full mod object.

Mod preview object
{
  "name":           "Super Awesome Mod",                                   // string
  "author":         "Homer Simpson",                                       // string
  "imageURL":       "https://example.com/image.png",                       // string
  "originalModURL": "https://reforger.armaplatform.com/workshop/{mod_id}", // string
  "apiModURL":      "https://api.reforgermods.net/v1/mod/{mod_id}",        // string
  "size":           "192.42 KB",                                           // string
  "rating":         "92%",                                                 // string
  "ID":             "{mod_id}"                                             // string
}

Mod Object

Querying a single mod by ID returns the full mod object, including dependencies and scenarios when the Workshop provides them.

Mod object
{
  "name":           "Super Awesome Mod",                                    // string
  "author":         "Homer Simpson",                                        // string
  "originalModURL": "https://reforger.armaplatform.com/workshop/{mod_id}",  // string
  "apiModURL":      "https://api.reforgermods.net/v1/mod/{mod_id}",         // string
  "imageURL":       "https://example.com/image.png",                        // string
  "rating":         "92%",                                                  // string
  "version":        "1.1.0",                                                // string
  "gameVersion":    "1.1.0.34",                                             // string
  "size":           "192.42 KB",                                            // string
  "subscribers":    66677,                                                  // int
  "downloads":      791142,                                                 // int
  "created":        "19.05.2022",                                           // string
  "lastModified":   "17.03.2024",                                           // string
  "id":             "{mod_id}",                                             // string
  "summary":        "This is a super awesome mod",                          // string
  "description":    "Big awesome mod!",                                     // string
  "license":        "Arma Public License (APL)",                            // string
  "tags":           ["SUPER", "AWESOME"],                                   // string array
  "dependencies":   [ { ...dependency objects... } ],                       // object array
  "scenarios":      [ { ...scenario objects... } ]                          // object array
}

Dependency Object

Mods with dependencies list them as an array of dependency objects. Each links to the dependency on the official Workshop and on this API.

Dependency object
{
  "name":           "Mod Dependency",                                      // string
  "originalModURL": "https://reforger.armaplatform.com/workshop/{dep_id}", // string
  "apiModURL":      "https://api.reforgermods.net/v1/mod/{dep_id}"         // string
}

Scenario Object

Mods that ship playable scenarios list them as an array of scenario objects. The scenarioID is the value a server config.json uses for game.scenarioId.

Scenario object
{
  "name":        "Some Scenario",                               // string
  "description": "You will do awesome things in this scenario", // string
  "scenarioID":  "{mod_id}Missions/SomeScenario.conf",          // string
  "gamemode":    "Campaign",                                    // string
  "playerCount": 64,                                            // int
  "imageURL":    "https://example.com/image.png"                // string
}

Refresh Job Object

Returned by /v1/refresh/jobs/{id} while background refreshes run.

Refresh job object
{
  "id":                  "9f0b7d0f6fd4f88a8bb0e455f0b640247a93", // string
  "status":              "queued",                               // string: queued | running | succeeded | failed | expired
  "resource_url":        "/v1/mods?search=radio",                // string
  "retry_after_seconds": 2                                       // int
}

Errors

Errors use a consistent JSON response and every response includes X-Request-Id for support. Include that value when reporting an issue.

Error response
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests.",
    "requestId": "..."
  }
}
INVALID_PAGERequested page is invalid.
INVALID_MOD_IDMod ID is malformed.
INVALID_SEARCHSearch text is invalid.
NOT_FOUNDNo matching resource was found.
RATE_LIMITEDToo many requests.
REFRESH_JOB_NOT_FOUNDThe refresh job no longer exists.
REFRESH_QUEUE_FULLRefresh capacity unavailable.
REFRESH_SHUTTING_DOWNThe service is shutting down.