A question that comes up regularly in the OpenKAT community: “Does OpenKAT have an API to add new (sub)domains or IP ranges programmatically?” The short answer is yes, but there are a couple of things worth knowing first. We’re actively involved in OpenKAT’s development and maintenance, and we use this API daily to spin up test environments. Here’s a practical guide based on a real, running stack.
Where objects live: Octopoes
In OpenKAT, everything you scan is an Object of Interest (OOI): a hostname, an IP address, an IP range, a URL or a network. These objects live in Octopoes, the graph database connector built on XTDB. Octopoes exposes a FastAPI REST API, and it ships with an interactive documentation page you can explore yourself:
http://<your-host>:8001/docsThis is where you add objects. The endpoints relevant for creating objects are:
| Method | Endpoint | Purpose |
|---|---|---|
POST | /{org}/declarations | Declare a single object (the normal way to add a host, IP or URL) |
POST | /{org}/declarations/save_many | Declare multiple objects in one request |
POST | /{org}/observations | Add objects as a scanner or normalizer result, with a source reference |
POST | /{org}/affirmations | Affirm a derived or assumed object |
PUT | /{org}/scan_profiles | Set the clearance level on an object |
{org} is your organisation code, the same code you see in the Rocky URL.
The key insight: adding an object is two steps
This is the part that trips people up. Adding an object through the API takes two separate calls:
- Declare the object. This creates it in Octopoes.
- Set a scan profile. This assigns a clearance level, which is what actually authorises the boefjes (the scanners) to run against it.
A bare declaration lands the object at clearance level 0, which means no boefje will ever scan it. The web interface and the CSV upload bundle these two steps together, but against the raw API you do them yourself.
Step 1: declare the object
curl -X POST 'http://localhost:8001/myorg/declarations?sync=true'
-H 'Content-Type: application/json'
-d '{
"ooi": {
"object_type": "Hostname",
"network": "Network|internet",
"name": "api-test.example.com"
},
"valid_time": "2026-06-18T20:00:00+00:00"
}'The request body fields:
ooi(required): the object itself (see the types below).valid_time(required): an ISO datetime that includes a timezone. OpenKAT is bitemporal, so every fact is valid from a point in time.end_valid_time,method,source_methodandtask_idare all optional.
The ?sync=true query parameter processes the declaration synchronously, so the object is immediately queryable.
Step 2: set the clearance level
Without this, the object stays at level 0 and nothing scans it:
curl -X PUT 'http://localhost:8001/myorg/scan_profiles?valid_time=2026-06-18T20%3A00%3A00%2B00%3A00'
-H 'Content-Type: application/json'
-d '{
"scan_profile_type": "declared",
"reference": "Hostname|internet|api-test.example.com",
"level": 4
}'Once the scan profile is set, the scheduler (which ticks roughly every minute) picks the object up and the enabled boefjes start running against it: DNS records, nmap, SSL checks, and so on.
Watch out: when you pass
valid_timeas a query parameter, it has to be URL-encoded. The+in the timezone offset (+00:00) turns into a space otherwise, and you get anHTTP 422validation error. In the JSON body, a plain ISO string is fine.
Object types for the common cases
The original question was about (sub)domains and IP ranges. Here are the OOI shapes for those:
// (sub)domain
{ "object_type": "Hostname", "network": "Network|internet", "name": "sub.example.com" }
// single IPv4 address
{ "object_type": "IPAddressV4", "network": "Network|internet", "address": "192.0.2.1" }
// IPv4 range / subnet
{ "object_type": "IPV4NetBlock", "network": "Network|internet",
"start_ip": "IPAddressV4|internet|192.0.2.0", "mask": 24 }
// URL
{ "object_type": "URL", "network": "Network|internet", "raw": "https://example.com/" }The same pattern applies to IPAddressV6 and IPV6NetBlock for IPv6.
Adding objects in bulk
For more than a handful of objects, you have two good options.
Via the API. POST /{org}/declarations/save_many accepts an array of declarations in a single request, which is far more efficient than looping one by one.
Via the Rocky web interface. Under Objects > Add > Upload CSV you can upload a CSV, and Rocky handles both the declaration and the scan profile for you. This is the user-friendly route and needs no scripting:
name,network
example.com,internet
sub.example.com,internetaddress,network
192.0.2.1,internetWhat about Rocky’s public API?
Rocky does expose a small REST API at /api/v1/, but it does not currently let you create objects. It only covers organisations (/api/v1/organization/), reports (/api/v1/report/) and report recipes (/api/v1/report-recipe/).
One thing that catches people out: the API is built on Django REST Framework’s SimpleRouter, which doesn’t register an API root view. Hitting /api/v1/ directly returns a 404, which is expected behaviour rather than a sign that something is broken. Go straight to a resource endpoint instead, and authenticate, because without credentials those endpoints return a 401.
So for adding objects programmatically today, the Octopoes declarations API and the CSV upload are your two routes. A dedicated public endpoint for adding objects isn’t part of Rocky’s API yet.
Doing it from Python
If you are scripting from within the OpenKAT ecosystem (a custom boefje, a management command, an internal integration), the cleanest approach is the connector that OpenKAT itself uses:
from datetime import datetime, timezone
from octopoes.connector.octopoes import OctopoesAPIConnector
from octopoes.api.models import Declaration
from octopoes.models.ooi.dns.zone import Hostname
connector = OctopoesAPIConnector("http://octopoes_api", client="myorg")
hostname = Hostname(network="Network|internet", name="api-test.example.com")
connector.save_declaration(
Declaration(ooi=hostname, valid_time=datetime.now(timezone.utc))
)This is exactly what OpenKAT’s own tooling does under the hood, and it handles the model serialisation for you.
Summary
| Goal | How |
|---|---|
| One object via API | POST /{org}/declarations then PUT /{org}/scan_profiles |
| Many objects via API | POST /{org}/declarations/save_many |
| Bulk as an end user | CSV upload in Rocky |
| From Python | OctopoesAPIConnector.save_declaration() |
So yes, OpenKAT lets you add hostnames, subdomains, IP addresses, IP ranges and URLs through an API. Just remember the two-step pattern: declare the object, then set a clearance level, and URL-encode your valid_time when it goes in a query string.
At Hasecon we are actively involved in OpenKAT’s development and maintenance, and we deploy and integrate it for clients across the Netherlands. Questions about automating OpenKAT or integrating it into your own tooling? Get in touch.
De echte OpenKAT herkennen: officiële bronnen en hoe u namaak vermijdt
Hoe herkent u de officiële OpenKAT en vermijdt u misleidende namaaksites? De echte bronnen, een verificatie-checklist en de belangrijkste waarschuwingssignalen op een rij.
Cyberbeveiligingswet aangenomen: wat bestuurders nu écht moeten regelen
Op 15 april 2026 stemde de Tweede Kamer in met de Cyberbeveiligingswet (Cbw) en de Wet weerbaarheid kritieke entiteiten (Wwke). De streefdate voor inwerkingtreding: tweede kwartaal 2026. Voor bestuurders betekent dat: minder dan een kwartaal om zorgplicht, meldplicht, registratieplicht én een opleidingsplicht op orde te hebben, met persoonlijke aansprakelijkheid als stok achter de deur. In dit artikel zetten we op een rij wat er écht verandert en hoe u met OpenKAT een groot deel van de technische zorgplicht aantoonbaar kunt afdekken.
Elastic SIEM Optimalisatie voor Moderne Beveiliging
In het hedendaagse digitale landschap vormt Elastic SIEM een cruciale schakel in cybersecurity. Deze krachtige Security Information and Event Management oplossing transformeert de manier waarop organisaties hun beveiligingsgegevens verzamelen, analyseren en beheren. Door realtime monitoring en geavanceerde analyses biedt het een robuuste verdedigingslinie tegen moderne cyberdreigingen. De Fundamenten van Elastic SIEM De robuuste architectuur van […]
OpenKAT en Elastic SIEM: Een Gouden Combinatie voor 360° Security
**In een tijdperk waarin digitale dreigingen voortdurend evolueren, is een robuuste en integrale aanpak van cybersecurity geen luxe meer, maar een absolute noodzaak. Voor IT-managers, security professionals en C-level executives in Nederland wordt de druk om te voldoen aan nieuwe wetgeving zoals de
