| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822 |
- openapi: '3.0.3'
- info:
- title: IRDB — IP Reputation Database
- version: '1.0.0'
- description: |
- Self-hosted IP reputation service: ingest abuse reports, distribute tailored block lists.
- ## Versioning
- Single major version `v1`. Changes within `v1` are additive only — new endpoints, new optional fields, new optional query params. Breaking changes ship as `v2`.
- ## Endpoint groups
- - **Public**: machine clients (reporters, consumers).
- - **Admin**: UI BFF + admin-kind tokens. RBAC enforced server-side.
- - **Auth**: UI BFF only — bridges browser auth to user records. Marked `x-internal: true`.
- - **Internal jobs**: not in this spec. Scheduler-only, network-restricted.
- ## Authentication
- Bearer token in the `Authorization` header. Four token kinds: `reporter`, `consumer`, `admin`, `service`. See `doc/auth-flows.md`.
- ## Errors
- Uniform envelope: `{"error":"<code>","details":{...}}`. Validation errors include `details`. Authentication failures return `401` `unauthorized`. Authorization failures return `403`.
- ## Rate limiting
- Public endpoints: 60 req/s/token (configurable). On exhaustion: `429` with `Retry-After: 1`.
- license:
- name: TBD
- servers:
- - url: http://localhost:8081
- description: Default compose deployment
- - url: https://reputation-api.example.com
- description: Production (replace hostname)
- tags:
- - name: Public
- description: 'Machine clients: reporters and blocklist consumers.'
- - name: Admin
- description: UI BFF + admin-kind tokens.
- - name: Auth
- description: UI BFF only. Service token required, no impersonation.
- security:
- - BearerAuth: []
- paths:
- '/api/v1/report':
- post:
- tags:
- - Public
- summary: Submit an abuse report
- description: |
- Token kind: `reporter`. Rate limit: 60 req/s per token (configurable).
- Returns `202 Accepted` on success.
- security:
- - BearerAuth: []
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/ReportRequest'
- responses:
- '202':
- description: Report accepted
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/ReportResponse'
- '400':
- description: Validation failed
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Error'
- '401':
- description: Bad / wrong-kind token
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Error'
- '429':
- description: Rate limited
- headers:
- Retry-After:
- schema:
- type: integer
- description: Seconds to wait before retrying.
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Error'
- '/api/v1/blocklist':
- get:
- tags:
- - Public
- summary: Pull a tailored blocklist
- description: |
- Token kind: `consumer`. The consumer's bound policy decides which IPs/CIDRs land in the output.
- Cached internally for 30 s per consumer. Honour `If-None-Match` to skip retransfer.
- `?format=json` returns structured rows; default is `text/plain`, one entry per line.
- security:
- - BearerAuth: []
- parameters:
- - name: format
- in: query
- schema:
- type: string
- enum:
- - text
- - json
- default: text
- - name: If-None-Match
- in: header
- schema:
- type: string
- responses:
- '200':
- description: Current blocklist
- headers:
- ETag:
- schema:
- type: string
- X-Blocklist-Generated-At:
- schema:
- type: string
- format: date-time
- X-Blocklist-Entries:
- schema:
- type: integer
- X-Blocklist-Policy:
- schema:
- type: string
- content:
- 'text/plain':
- schema:
- type: string
- example: |
- 203.0.113.42
- 198.51.100.0/24
- 'application/json':
- schema:
- '$ref': '#/components/schemas/BlocklistJson'
- '304':
- description: Not modified — body matches `If-None-Match`
- '401':
- description: Bad / wrong-kind token
- '/api/v1/admin/me':
- get:
- tags:
- - Admin
- summary: Current acting identity
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: Identity info
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/User'
- '/api/v1/admin/ips':
- get:
- tags:
- - Admin
- summary: Search IPs
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: q
- in: query
- schema:
- type: string
- - name: category
- in: query
- schema:
- type: string
- - name: min_score
- in: query
- schema:
- type: number
- format: float
- - name: max_score
- in: query
- schema:
- type: number
- format: float
- - name: country
- in: query
- schema:
- type: string
- - name: asn
- in: query
- schema:
- type: integer
- - name: status
- in: query
- schema:
- type: string
- enum:
- - scored
- - manual
- - allowlisted
- - clean
- - '$ref': '#/components/parameters/Page'
- - '$ref': '#/components/parameters/PageSize'
- responses:
- '200':
- description: Page of IPs
- content:
- 'application/json':
- schema:
- type: object
- properties:
- page:
- type: integer
- minimum: 1
- example: 1
- page_size:
- type: integer
- minimum: 1
- maximum: 200
- example: 50
- total:
- type: integer
- minimum: 0
- example: 1284
- items:
- type: array
- items:
- type: object
- '/api/v1/admin/ips/countries':
- get:
- tags:
- - Admin
- summary: Country code dropdown source
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: '`[{code, count}]`'
- content:
- 'application/json':
- schema:
- type: object
- properties:
- items:
- type: array
- items:
- type: object
- properties:
- code:
- type: string
- count:
- type: integer
- '/api/v1/admin/ips/{ip}':
- get:
- tags:
- - Admin
- summary: IP detail
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: ip
- in: path
- required: true
- schema:
- type: string
- responses:
- '200':
- description: IP detail
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/IpDetail'
- '404':
- description: Invalid IP / not found
- '/api/v1/admin/stats/dashboard':
- get:
- tags:
- - Admin
- summary: Dashboard stats (30s cached)
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: Dashboard payload
- content:
- 'application/json':
- schema:
- type: object
- '/api/v1/admin/manual-blocks':
- get:
- tags:
- - Admin
- summary: List manual blocks
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create manual block
- description: Operator+ role required. `kind=ip` requires `ip`; `kind=subnet` requires `cidr`.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- properties:
- kind:
- type: string
- enum:
- - ip
- - subnet
- ip:
- type: string
- cidr:
- type: string
- reason:
- type: string
- expires_at:
- type: string
- format: date-time
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/ManualBlock'
- '/api/v1/admin/manual-blocks/{id}':
- get:
- tags:
- - Admin
- summary: Show manual block
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: manual block
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/ManualBlock'
- delete:
- tags:
- - Admin
- summary: Delete manual block
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '/api/v1/admin/allowlist':
- get:
- tags:
- - Admin
- summary: List allowlist
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create allowlist entry
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- properties:
- kind:
- type: string
- enum:
- - ip
- - subnet
- ip:
- type: string
- cidr:
- type: string
- reason:
- type: string
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/AllowlistEntry'
- '/api/v1/admin/allowlist/{id}':
- get:
- tags:
- - Admin
- summary: Show allowlist entry
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: allowlist entry
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/AllowlistEntry'
- delete:
- tags:
- - Admin
- summary: Delete allowlist entry
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '/api/v1/admin/reporters':
- get:
- tags:
- - Admin
- summary: List reporters
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create reporter
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Reporter'
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Reporter'
- '/api/v1/admin/reporters/{id}':
- get:
- tags:
- - Admin
- summary: Show reporter
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: reporter
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Reporter'
- patch:
- tags:
- - Admin
- summary: Update reporter
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- requestBody:
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Reporter'
- responses:
- '200':
- description: Updated
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Reporter'
- delete:
- tags:
- - Admin
- summary: Soft-delete reporter
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '409':
- description: Has reports — flagged inactive instead.
- '/api/v1/admin/consumers':
- get:
- tags:
- - Admin
- summary: List consumers
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create consumer
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Consumer'
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Consumer'
- '/api/v1/admin/consumers/{id}':
- get:
- tags:
- - Admin
- summary: Show consumer
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: consumer
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Consumer'
- patch:
- tags:
- - Admin
- summary: Update consumer
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- requestBody:
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Consumer'
- responses:
- '200':
- description: Updated
- delete:
- tags:
- - Admin
- summary: Soft-delete consumer
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '/api/v1/admin/tokens':
- get:
- tags:
- - Admin
- summary: List tokens
- description: Service tokens are filtered out unconditionally.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create token
- description: Returns the raw token ONCE in `raw_token`. Service tokens are not creatable here.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- properties:
- kind:
- type: string
- enum:
- - reporter
- - consumer
- - admin
- reporter_id:
- type: integer
- consumer_id:
- type: integer
- role:
- type: string
- enum:
- - viewer
- - operator
- - admin
- expires_at:
- type: string
- format: date-time
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/TokenCreated'
- '/api/v1/admin/tokens/{id}':
- delete:
- tags:
- - Admin
- summary: Revoke token
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Revoked
- '/api/v1/admin/tokens/{id}/purge':
- delete:
- tags:
- - Admin
- summary: Permanently delete a revoked token
- description: |
- Hard-deletes the row. Requires the token to be already revoked
- (`revoked_at` set); active tokens return 409 to keep "revoke first,
- then prune" the only path that removes data. Service tokens cannot
- be deleted.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '403':
- description: Service token; not deletable via API
- '404':
- description: Not found
- '409':
- description: Token still active; revoke it first
- '/api/v1/admin/categories':
- get:
- tags:
- - Admin
- summary: List categories
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create category
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Category'
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Category'
- '/api/v1/admin/categories/{id}':
- get:
- tags:
- - Admin
- summary: Show category
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: category
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Category'
- patch:
- tags:
- - Admin
- summary: Update category
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- requestBody:
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Category'
- responses:
- '200':
- description: Updated
- delete:
- tags:
- - Admin
- summary: Hard-delete category (refused if in use)
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '409':
- description: Category in use; soft-delete via PATCH `is_active=false`.
- '/api/v1/admin/policies':
- get:
- tags:
- - Admin
- summary: List policies
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: list
- post:
- tags:
- - Admin
- summary: Create policy
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Policy'
- responses:
- '201':
- description: Created
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Policy'
- '/api/v1/admin/policies/{id}':
- get:
- tags:
- - Admin
- summary: Show policy
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: policy
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Policy'
- patch:
- tags:
- - Admin
- summary: Update policy (replaces thresholds wholesale when present)
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- requestBody:
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/Policy'
- responses:
- '200':
- description: Updated
- delete:
- tags:
- - Admin
- summary: Delete policy (refused if used by consumers)
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '204':
- description: Deleted
- '409':
- description: Policy in use
- '/api/v1/admin/policies/{id}/preview':
- get:
- tags:
- - Admin
- summary: Preview policy (count + sample)
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: Preview
- '/api/v1/admin/audit-log':
- get:
- tags:
- - Admin
- summary: Filtered audit log
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: actor_kind
- in: query
- schema:
- type: string
- enum:
- - user
- - admin-token
- - reporter
- - consumer
- - system
- - name: actor_id
- in: query
- schema:
- type: integer
- - name: action
- in: query
- schema:
- type: string
- - name: entity_type
- in: query
- schema:
- type: string
- - name: entity_id
- in: query
- schema:
- type: string
- - name: from
- in: query
- schema:
- type: string
- format: date-time
- - name: to
- in: query
- schema:
- type: string
- format: date-time
- - '$ref': '#/components/parameters/Page'
- - '$ref': '#/components/parameters/PageSize'
- responses:
- '200':
- description: Audit page
- content:
- 'application/json':
- schema:
- type: object
- properties:
- page:
- type: integer
- minimum: 1
- example: 1
- page_size:
- type: integer
- minimum: 1
- maximum: 200
- example: 50
- total:
- type: integer
- minimum: 0
- example: 1284
- items:
- type: array
- items:
- '$ref': '#/components/schemas/AuditEntry'
- '/api/v1/admin/jobs/status':
- get:
- tags:
- - Admin
- summary: Jobs status (Viewer)
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: Jobs status
- content:
- 'application/json':
- schema:
- type: object
- properties:
- now:
- type: string
- format: date-time
- jobs:
- type: object
- additionalProperties:
- '$ref': '#/components/schemas/JobStatus'
- '/api/v1/admin/jobs/trigger/{name}':
- post:
- tags:
- - Admin
- summary: Manually trigger a job (Admin)
- description: 'Whitelisted params: `full`, `max_rows`, `reenrich`. Other body fields are dropped.'
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- - name: name
- in: path
- required: true
- schema:
- type: string
- requestBody:
- content:
- 'application/json':
- schema:
- type: object
- properties:
- full:
- type: boolean
- max_rows:
- type: integer
- reenrich:
- type: boolean
- responses:
- '200':
- description: Job ran
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/JobOutcome'
- '404':
- description: Unknown job
- '409':
- description: Lock held; status=`skipped_locked`
- '412':
- description: refresh-geoip without credential
- '/api/v1/admin/config':
- get:
- tags:
- - Admin
- summary: Effective config (secrets masked)
- description: Admin only.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: Config sections
- content:
- 'application/json':
- schema:
- type: object
- properties:
- sections:
- type: object
- additionalProperties:
- type: object
- '/api/v1/admin/app-settings':
- get:
- tags:
- - Admin
- summary: Runtime feature flags (Admin)
- description: |
- Returns the runtime-mutable feature flags. Currently exposes the
- audit-emission toggles for high-volume public endpoints
- (`audit_report_received_enabled`, `audit_blocklist_request_enabled`).
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: Current toggle state
- content:
- 'application/json':
- schema:
- type: object
- additionalProperties:
- type: boolean
- patch:
- tags:
- - Admin
- summary: Update runtime feature flags (Admin)
- description: |
- Updates one or more runtime feature flags. Body keys not listed are left
- untouched. Returns the post-update snapshot.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- properties:
- audit_report_received_enabled:
- type: boolean
- audit_blocklist_request_enabled:
- type: boolean
- responses:
- '200':
- description: Updated snapshot
- content:
- 'application/json':
- schema:
- type: object
- additionalProperties:
- type: boolean
- '400':
- description: Validation error
- '/api/v1/admin/maintenance/purge':
- post:
- tags:
- - Admin
- summary: Wipe operational data (Admin)
- description: |
- Deletes reports, scores, enrichment, manual blocks, allowlist, audit log, job history, reporters, consumers, policies, and non-service tokens. Preserves users, OIDC role mappings, abuse categories, and the `service`-kind token.
- Requires `confirm: "PURGE"` in the body — any other value returns 400.
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- required:
- - confirm
- properties:
- confirm:
- type: string
- enum:
- - PURGE
- responses:
- '200':
- description: Purge succeeded
- content:
- 'application/json':
- schema:
- type: object
- properties:
- status:
- type: string
- example: purged
- deleted:
- type: object
- additionalProperties:
- type: integer
- '400':
- description: Missing or wrong `confirm` value
- '/api/v1/admin/maintenance/seed-demo':
- post:
- tags:
- - Admin
- summary: Load demo dataset (Admin)
- description: 'Populates reporters, consumers, IPs, reports, manual blocks, allowlist, and synthetic GeoIP for demos and screenshots. Triggers a full score recompute on completion. Idempotent: returns 409 if demo data is already present.'
- security:
- - BearerAuth: []
- parameters:
- - '$ref': '#/components/parameters/ActingUserId'
- responses:
- '200':
- description: Demo data inserted
- content:
- 'application/json':
- schema:
- type: object
- properties:
- status:
- type: string
- example: seeded
- summary:
- type: object
- additionalProperties:
- type: integer
- recompute:
- '$ref': '#/components/schemas/JobOutcome'
- '409':
- description: Demo data already present
- '412':
- description: No categories configured
- '/api/v1/auth/users/upsert-oidc':
- post:
- tags:
- - Auth
- summary: Upsert an OIDC-authenticated user
- description: |
- **UI BFF only.** Service-token-required, no impersonation header.
- Resolves the user record + role (via `oidc_role_mappings`) for a freshly-validated ID token.
- x-internal: true
- security:
- - BearerAuth: []
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- properties:
- subject:
- type: string
- email:
- type: string
- display_name:
- type: string
- groups:
- type: array
- items:
- type: string
- responses:
- '200':
- description: User record
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/User'
- '/api/v1/auth/users/upsert-local':
- post:
- tags:
- - Auth
- summary: Upsert the local-admin user
- description: '**UI BFF only.** Called after the UI validates the local-admin password.'
- x-internal: true
- security:
- - BearerAuth: []
- requestBody:
- required: true
- content:
- 'application/json':
- schema:
- type: object
- properties:
- username:
- type: string
- responses:
- '200':
- description: User record
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/User'
- '/api/v1/auth/users/{id}':
- get:
- tags:
- - Auth
- summary: Refetch a user record
- description: '**UI BFF only.** Used to refresh role / display_name during a session.'
- x-internal: true
- security:
- - BearerAuth: []
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: User record
- content:
- 'application/json':
- schema:
- '$ref': '#/components/schemas/User'
- components:
- securitySchemes:
- BearerAuth:
- type: http
- scheme: bearer
- description: |
- Token in the form `irdb_<kind>_<32 base32 chars>`.
- See `doc/auth-flows.md` for the four token kinds.
- parameters:
- Page:
- name: page
- in: query
- schema:
- type: integer
- minimum: 1
- default: 1
- PageSize:
- name: page_size
- in: query
- schema:
- type: integer
- minimum: 1
- maximum: 200
- default: 50
- ActingUserId:
- name: X-Acting-User-Id
- in: header
- description: |
- Required when authenticating with a `service` token.
- The api applies RBAC for the named user. Ignored on other token kinds.
- schema:
- type: integer
- schemas:
- Error:
- type: object
- required:
- - error
- properties:
- error:
- type: string
- example: unauthorized
- details:
- type: object
- description: Field-level errors for `validation_failed`.
- additionalProperties:
- type: string
- ReportRequest:
- type: object
- required:
- - ip
- - category
- properties:
- ip:
- type: string
- example: '203.0.113.42'
- category:
- type: string
- example: brute_force
- metadata:
- type: object
- description: Free-form per-report data, max 4 KB after json_encode.
- additionalProperties: true
- ReportResponse:
- type: object
- properties:
- report_id:
- type: integer
- example: 12345
- ip:
- type: string
- example: '203.0.113.42'
- received_at:
- type: string
- format: date-time
- BlocklistEntry:
- type: object
- properties:
- ip_or_cidr:
- type: string
- example: '203.0.113.42'
- categories:
- type: array
- items:
- type: string
- score:
- type: number
- format: float
- example: 1.42
- reason:
- type: string
- enum:
- - scored
- - manual
- example: scored
- BlocklistJson:
- type: object
- properties:
- count:
- type: integer
- example: 42
- generated_at:
- type: string
- format: date-time
- policy:
- type: string
- example: moderate
- entries:
- type: array
- items:
- '$ref': '#/components/schemas/BlocklistEntry'
- Token:
- type: object
- properties:
- id:
- type: integer
- kind:
- type: string
- enum:
- - reporter
- - consumer
- - admin
- prefix:
- type: string
- example: irdb_adm
- reporter_id:
- type: integer
- nullable: true
- consumer_id:
- type: integer
- nullable: true
- role:
- type: string
- nullable: true
- enum:
- - viewer
- - operator
- - admin
- - null
- expires_at:
- type: string
- format: date-time
- nullable: true
- revoked_at:
- type: string
- format: date-time
- nullable: true
- last_used_at:
- type: string
- format: date-time
- nullable: true
- TokenCreated:
- allOf:
- - '$ref': '#/components/schemas/Token'
- - type: object
- properties:
- raw_token:
- type: string
- description: Returned ONCE on creation — copy it now, never displayed again.
- example: irdb_adm_AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
- Reporter:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- example: web-prod-01
- description:
- type: string
- nullable: true
- trust_weight:
- type: number
- format: float
- minimum: 0
- maximum: 2
- is_active:
- type: boolean
- audit_enabled:
- type: boolean
- description: When false, suppresses `report.received` audit rows for this reporter even if the global toggle is on.
- Consumer:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- example: edge-fw-01
- description:
- type: string
- nullable: true
- policy_id:
- type: integer
- is_active:
- type: boolean
- audit_enabled:
- type: boolean
- description: When false, suppresses `blocklist.requested` audit rows for this consumer even if the global toggle is on.
- last_pulled_at:
- type: string
- format: date-time
- nullable: true
- Category:
- type: object
- properties:
- id:
- type: integer
- slug:
- type: string
- example: brute_force
- name:
- type: string
- description:
- type: string
- nullable: true
- decay_function:
- type: string
- enum:
- - linear
- - exponential
- decay_param:
- type: number
- format: float
- is_active:
- type: boolean
- Policy:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- example: moderate
- description:
- type: string
- nullable: true
- include_manual_blocks:
- type: boolean
- thresholds:
- type: object
- description: '`{category_slug: threshold}`'
- additionalProperties:
- type: number
- format: float
- ManualBlock:
- type: object
- properties:
- id:
- type: integer
- kind:
- type: string
- enum:
- - ip
- - subnet
- ip:
- type: string
- nullable: true
- cidr:
- type: string
- nullable: true
- reason:
- type: string
- nullable: true
- expires_at:
- type: string
- format: date-time
- nullable: true
- created_at:
- type: string
- format: date-time
- AllowlistEntry:
- type: object
- properties:
- id:
- type: integer
- kind:
- type: string
- enum:
- - ip
- - subnet
- ip:
- type: string
- nullable: true
- cidr:
- type: string
- nullable: true
- reason:
- type: string
- nullable: true
- created_at:
- type: string
- format: date-time
- IpDetail:
- type: object
- properties:
- ip:
- type: string
- is_ipv4:
- type: boolean
- scores:
- type: array
- items:
- type: object
- properties:
- category:
- type: string
- score:
- type: number
- format: float
- last_report_at:
- type: string
- format: date-time
- nullable: true
- report_count_30d:
- type: integer
- enrichment:
- type: object
- properties:
- country_code:
- type: string
- nullable: true
- asn:
- type: integer
- nullable: true
- as_org:
- type: string
- nullable: true
- enriched_at:
- type: string
- format: date-time
- nullable: true
- status:
- type: string
- enum:
- - scored
- - manually_blocked
- - allowlisted
- - clean
- manual_block:
- type: object
- nullable: true
- allowlist:
- type: object
- nullable: true
- history:
- type: array
- items:
- type: object
- has_more:
- type: boolean
- AuditEntry:
- type: object
- properties:
- id:
- type: integer
- occurred_at:
- type: string
- format: date-time
- actor_kind:
- type: string
- enum:
- - user
- - admin-token
- - reporter
- - consumer
- - system
- actor_id:
- type: string
- nullable: true
- action:
- type: string
- example: manual_block.created
- entity_type:
- type: string
- nullable: true
- entity_id:
- type: string
- nullable: true
- entity_label:
- type: string
- nullable: true
- description: Human-readable identifier for the target (name, slug, IP, CIDR, prefix). Frozen at write time.
- details:
- type: object
- nullable: true
- additionalProperties: true
- description: 'For update events, contains a `changes` map of `{field: {from, to}}` for every modified field.'
- source_ip:
- type: string
- nullable: true
- JobStatus:
- type: object
- properties:
- name:
- type: string
- default_interval_seconds:
- type: integer
- max_runtime_seconds:
- type: integer
- overdue:
- type: boolean
- last_run:
- type: object
- nullable: true
- properties:
- id:
- type: integer
- status:
- type: string
- enum:
- - success
- - failure
- - skipped_locked
- - running
- items_processed:
- type: integer
- triggered_by:
- type: string
- enum:
- - schedule
- - manual
- - api
- started_at:
- type: string
- format: date-time
- nullable: true
- finished_at:
- type: string
- format: date-time
- nullable: true
- error_message:
- type: string
- nullable: true
- JobOutcome:
- type: object
- properties:
- job:
- type: string
- status:
- type: string
- enum:
- - success
- - failure
- - skipped_locked
- - running
- items_processed:
- type: integer
- duration_ms:
- type: integer
- run_id:
- type: integer
- nullable: true
- error:
- type: string
- nullable: true
- User:
- type: object
- properties:
- id:
- type: integer
- email:
- type: string
- nullable: true
- display_name:
- type: string
- role:
- type: string
- enum:
- - viewer
- - operator
- - admin
- source:
- type: string
- enum:
- - oidc
- - local
- - admin-token
- is_local:
- type: boolean
- Pagination:
- type: object
- properties:
- page:
- type: integer
- minimum: 1
- example: 1
- page_size:
- type: integer
- minimum: 1
- maximum: 200
- example: 50
- total:
- type: integer
- minimum: 0
- example: 1284
|