{"openapi":"3.1.0","info":{"title":"ArSite Developer API","version":"1.0.0","description":"Programmatic access to the ArSite platform — list modules, inspect usage, and invoke published modules through the gateway.\n\n**Authentication.** Most endpoints require a Bearer token. There are two ways to obtain one:\n\n- **API keys** — long-lived per-user (optionally tenant-scoped) tokens prefixed `arsite_sk_`. Generate at `/dashboard/api-keys`.\n- **OAuth client credentials** — short-lived (1h) access tokens for backend tooling. Exchange your developer `client_id` + `client_secret` at `/api/oauth/token`.\n\n**Rate limits.** Per-key sliding-window. Default 1,000 req/hr; exceeding returns `429` with `Retry-After`.","contact":{"name":"ArSite Support","url":"https://arsite.ca/developer"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://arsite.ca","description":"Production"},{"url":"http://localhost:3000","description":"Local development"}],"tags":[{"name":"Health","description":"Platform liveness checks (no auth)."},{"name":"OAuth","description":"Token exchange for developer client credentials."},{"name":"Modules","description":"List + inspect published marketplace modules."},{"name":"Usage","description":"Per-key API call usage."},{"name":"Module passthrough","description":"Invoke a subscribed module via the ArSite gateway. Auth, entitlement, metering, and HMAC signing are handled for you; the response is streamed from the module developer’s upstream API."}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/health":{"get":{"tags":["Health"],"summary":"Platform health","description":"Returns a 200 if the platform is up. No auth required.","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"timestamp":{"type":"string","format":"date-time"}}}}}}}}},"/api/oauth/token":{"post":{"tags":["OAuth"],"summary":"Exchange credentials for an access token","description":"Supports two grant types:\n\n- `client_credentials` — for first-party developer tooling. Returns an access token only.\n- `refresh_token` — rotates the refresh token and returns a fresh access token.\n\nAccess tokens are JWTs with scopes `api:invoke read:modules` and a 1-hour TTL.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ClientCredentialsRequest"},{"$ref":"#/components/schemas/RefreshTokenRequest"}]},"examples":{"client_credentials":{"summary":"client_credentials grant","value":{"grant_type":"client_credentials","client_id":"arsite_cid_…","client_secret":"arsite_cs_…"}},"refresh_token":{"summary":"refresh_token grant","value":{"grant_type":"refresh_token","client_id":"arsite_cid_…","refresh_token":"eyJ…"}}}}}},"responses":{"200":{"description":"Token issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Invalid or missing parameters."},"401":{"description":"Bad client credentials or invalid refresh token."},"403":{"description":"Developer account is not active."}}}},"/api/v1/apps":{"get":{"tags":["Modules"],"summary":"List published modules","description":"Returns all modules currently in the `published` state with at least one active pricing tier. Includes basic metadata only; use `/api/v1/apps/{appId}` for the full record.","parameters":[{"name":"category","in":"query","description":"Filter by marketplace category.","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"modules":{"type":"array","items":{"$ref":"#/components/schemas/AppSummary"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"401":{"description":"Missing or invalid Bearer token."},"429":{"description":"Rate limit exceeded."}}}},"/api/v1/apps/{appId}":{"get":{"tags":["Modules"],"summary":"Get module details","parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"},"example":"datafun-catalog"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppDetail"}}}},"401":{"description":"Missing or invalid Bearer token."},"404":{"description":"Module not found or not published."}}}},"/api/v1/usage":{"get":{"tags":["Usage"],"summary":"Get current-cycle usage for the calling API key","description":"Aggregates `usage_events` for the tenant + key in the current billing cycle.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"callsThisMonth":{"type":"integer"},"callsToday":{"type":"integer"},"lastCallAt":{"type":"string","format":"date-time","nullable":true},"cycleStart":{"type":"string","format":"date-time"},"cycleEnd":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Missing or invalid Bearer token."}}}},"/api/v1/apps/{appId}/{path}":{"get":{"tags":["Module passthrough"],"summary":"Invoke a module endpoint via the ArSite gateway","description":"Forwards the request to the module developer’s upstream API. The API key must be scoped to `{appId}` (or unscoped) and the calling tenant must have an active subscription.\n\nResponse shape is module-specific — refer to each module’s `/api/v1/apps/{appId}/openapi.json` for its own contract.\n\nSame path supports POST / PUT / PATCH / DELETE; routes the module declares in its manifest.","parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"},"example":"datafun-catalog"},{"name":"path","in":"path","required":true,"schema":{"type":"string"},"example":"v1/search","description":"Module-specific subpath. May contain slashes."}],"responses":{"200":{"description":"Module response (shape is module-specific)."},"401":{"description":"Missing or invalid Bearer token."},"403":{"description":"Not subscribed or key not scoped to this module."},"404":{"description":"Module or sub-path not declared."},"429":{"description":"Quota exceeded."},"504":{"description":"Upstream timeout (developer’s backend slow/unreachable)."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key (arsite_sk_…) or OAuth access token (JWT)","description":"API keys are issued at `/dashboard/api-keys`; OAuth access tokens come from `/api/oauth/token`. Both are passed as `Authorization: Bearer …`."}},"schemas":{"ClientCredentialsRequest":{"type":"object","required":["grant_type","client_id","client_secret"],"properties":{"grant_type":{"type":"string","enum":["client_credentials"]},"client_id":{"type":"string","example":"arsite_cid_…"},"client_secret":{"type":"string","example":"arsite_cs_…"}}},"RefreshTokenRequest":{"type":"object","required":["grant_type","client_id","refresh_token"],"properties":{"grant_type":{"type":"string","enum":["refresh_token"]},"client_id":{"type":"string","example":"arsite_cid_…"},"refresh_token":{"type":"string","example":"eyJ…"}}},"TokenResponse":{"type":"object","required":["access_token","token_type","expires_in"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string","description":"Only returned on refresh_token grant."},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","example":3600}}},"AppSummary":{"type":"object","properties":{"appId":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"iconUrl":{"type":"string","nullable":true},"pricingModel":{"type":"string","enum":["free","freemium","subscription","per_seat","usage_based","one_time"]},"installCount":{"type":"integer"},"averageRating":{"type":"number","nullable":true}}},"AppDetail":{"allOf":[{"$ref":"#/components/schemas/AppSummary"},{"type":"object","properties":{"description":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"screenshots":{"type":"array","items":{"type":"string"}},"tiers":{"type":"array","items":{"type":"object","properties":{"tierKey":{"type":"string"},"name":{"type":"string"},"priceCents":{"type":"integer"},"currency":{"type":"string","example":"USD"},"interval":{"type":"string","nullable":true,"example":"month"},"includedMonthlyUnits":{"type":"number","nullable":true}}}},"publishedAt":{"type":"string","format":"date-time"},"version":{"type":"string"}}}]}}}}