REST API overview SafeDNS Shield filtering configuration is managed through its REST API. The API address is deployment-specific. The default management API port is 8080, but the host, protocol, and port may be changed during deployment. Use the following placeholder throughout this guide: = http[s]://: For example: http://192.0.2.10:8080 Access is normally restricted to source addresses approved during deployment. Using the API Authentication All client-facing API requests require an HTTP bearer token. Authorization: Bearer Content-Type: application/json Example: curl \ --header "Authorization: Bearer " \ --header "Content-Type: application/json" \ "/profiles/" Use the token and management API address assigned to the Shield deployment. General behavior Successfully completed configuration changes take effect immediately. No service restart or separate activation request is required. Successful create operations normally return 201 Created. Successful update and retrieval operations normally return 200 OK. Successful deletion and initialization operations return 204 No Content with no response body. Invalid request data may return 422 Unprocessable Entity with validation details. IPv4 addresses are supplied as dotted-decimal strings in request bodies, but some resource paths identify an IPv4 address by its unsigned integer representation. The examples use trailing slashes where they appear in the API specification. Profiles and filtering A filtering profile combines category rules, application rules, block-page behavior, and several profile-level options. Profile fields Field Type Description id integer Client-supplied profile identifier. Required when creating a profile. page_id integer or null Identifier of the block page assigned to the profile. white_list_only boolean When enabled, only domains on the allowlist and explicitly allowed applications are permitted. Default: false. empty_dns_answer boolean When enabled, Shield returns an empty DNS answer for a blocked domain instead of directing the client to a block page. Default: false. appaware_priority_over_bwlists boolean When enabled, application rules take priority over explicit domain allow/deny-list rules. Default: false. A profile request also supports: Field Type Description cat_ids array of integers Complete collection of filtering category IDs assigned to the profile. apps array of objects Complete collection of application rules assigned to the profile. Each application rule contains: { "app_id": 12, "status": "deny" } Supported statuses are: deny — blocks domains associated with the application. allow — explicitly permits resolution of domains associated with the application, including when those domains would otherwise be blocked by the profile's category rules. Application IDs can be obtained from: GET /app_aware/application/ Category IDs are listed in the SafeDNS category reference. Replacement semantics When cat_ids or apps is included in: PATCH /profiles/{profile_id} it replaces the complete existing collection. It is not merged with the current configuration. Omitting cat_ids leaves the category collection unchanged. Sending "cat_ids": [] removes all category assignments. Omitting apps leaves the application-rule collection unchanged. Sending "apps": [] removes all application rules. Initial configuration example The /init/ operation creates the initial Shield configuration in one request. Method: POST URL: /init/ { "blockpages": [ { "id": 1, "type": 0 }, { "id": 2, "type": 1 } ], "profiles": [ { "profile": { "id": 1, "page_id": 1, "white_list_only": false, "empty_dns_answer": false, "appaware_priority_over_bwlists": false }, "cat_ids": [3, 4, 12], "apps": [ { "app_id": 1, "status": "deny" }, { "app_id": 12, "status": "deny" }, { "app_id": 93, "status": "deny" } ] } ], "bw_lists": [ { "profile_id": 1, "type": "deny", "domains": [ "example1.com", "example2.com", "example3.com" ] } ], "napts": [], "nets": [ { "ip": "100.100.100.100", "profile_id": 1, "prefix_len": 32 }, { "ip": "100.110.110.0", "profile_id": 1, "prefix_len": 24 }, { "ip": "100.120.0.0", "profile_id": 1, "prefix_len": 16 } ], "nets6": [] } All six top-level arrays are required. Include an empty array when a resource type is not used: blockpages profiles bw_lists napts nets nets6 The example creates: Two block-page records: Type 0: default block page. Type 1: custom block page. Profile 1, assigned to block page 1. Three blocked content/security categories. Three denied applications. Three explicitly denied domains. One IPv4 host assignment and two IPv4 subnet assignments. Custom block-page content is configured outside the Shield REST API. The API only creates and assigns the block-page record. A successful initialization returns: 204 No Content Profile configuration examples Modifying filtering categories To change categories assigned to a profile, send the complete desired category collection. The following request replaces the existing categories of profile 1 with six categories: Method: PATCH URL: /profiles/1 { "cat_ids": [3, 4, 12, 66, 70, 71] } Because apps and profile are omitted, only the category collection is changed. To remove all category assignments: { "cat_ids": [] } Replacing application rules for a profile Application rules can be replaced together through the profile endpoint. Method: PATCH URL: /profiles/1 { "apps": [ { "app_id": 1, "status": "deny" }, { "app_id": 12, "status": "allow" } ] } This request removes any other application rules previously assigned to profile 1. It denies application 1 and explicitly permits domains associated with application 12, even if category rules would otherwise block them. To remove all application rules: { "apps": [] } Managing individual application rules Retrieve the application catalogue Method: GET URL: /app_aware/application/ Example response: [ { "id": 1, "name": "Application name" } ] Retrieve all application rules for a profile Method: GET URL: /profile/1/app_aware Example response: [ { "profile_id": 1, "app_id": 12, "status": "allow" } ] Add one application rule Method: POST URL: /profile/1/app_aware { "app_id": 12, "status": "allow" } Add several application rules with the same status Method: POST URL: /profile/1/app_aware/batch { "app_ids": [1, 12, 93], "status": "deny" } Delete an application rule The final path value is the application ID. The current OpenAPI parameter name is app_aware_id, but it identifies the same value as app_id. Method: DELETE URL: /profile/1/app_aware/12 No request body is required. Adding a domain to the allowlist To exempt a domain from category-based blocking, add it to the allowlist of the relevant profile. Method: POST URL: /profile/1/bw_list { "type": "allow", "domain": "example4.com" } Adding domains to the denylist To block several domains directly, use the batch operation. Method: POST URL: /profile/1/bw_list/batch { "type": "deny", "domains": [ "example5.com", "example6.com", "example7.com", "example8.com", "example9.com" ] } Allow/deny-list storage limitation Shield stores allowlist and denylist domains as hashes. The API therefore cannot retrieve or enumerate the original domain names after they have been submitted. API clients should retain their own copy of configured allowlists and denylists when later inspection, reconciliation, or synchronization is required. Update and delete operations still accept the original domain name. Shield calculates its hash internally to locate the stored rule. Creating a new filtering profile Method: POST URL: /profiles/ { "profile": { "id": 2, "page_id": 1, "white_list_only": false, "empty_dns_answer": false, "appaware_priority_over_bwlists": false }, "cat_ids": [3, 4, 12, 13, 66, 70, 71], "apps": [ { "app_id": 1, "status": "deny" }, { "app_id": 12, "status": "deny" }, { "app_id": 93, "status": "deny" } ] } This creates profile 2, assigns block page 1, enables the listed filtering categories, and adds three denied application rules. Subscriber assignments Assigning an IPv4 address or subnet To assign an IPv4 host to profile 1, create a /32 network record. Method: POST URL: /net/ { "ip": "100.100.100.101", "profile_id": 1, "prefix_len": 32 } To assign a /24 subnet: { "ip": "100.100.101.0", "profile_id": 1, "prefix_len": 24 } Supported IPv4 prefix lengths are /10 through /32. Retrieve all IPv4 assignments Method: GET URL: /net/ Example response: [ { "ip": "100.100.100.101", "profile_id": 1, "prefix_len": 32 }, { "ip": "100.100.101.0", "profile_id": 1, "prefix_len": 24 } ] IPv4 integer representation Individual IPv4 resource paths identify an address by its unsigned 32-bit integer representation. For example: 100.100.100.101 = 1684300901 100.100.101.0 = 1684301056 Python conversion example: from ipaddress import IPv4Address int_ip = int(IPv4Address("100.100.100.101")) print(int_ip) # 1684300901 Reassign an IPv4 address or subnet Method: PATCH URL: /net/1684301056 { "ip": "100.100.101.0", "profile_id": 2, "prefix_len": 24 } Remove an IPv4 address or subnet Method: DELETE URL: /net/1684301056 No request body is required. Assigning an IPv6 address or subnet Method: POST URL: /net6/ { "ip": "2001:db8:100::", "profile_id": 1, "prefix_len": 64 } Supported IPv6 prefix lengths are /16 through /128. Retrieve all IPv6 assignments Method: GET URL: /net6/ Example response: [ { "ip": "2001:db8:100::", "profile_id": 1, "prefix_len": 64 } ] Identifying subscribers through NAPT port ranges NAPT records assign different source-port ranges on a shared IPv4 address to different filtering profiles. Port boundaries are inclusive. A range from 10000 to 19999 includes both port 10000 and port 19999. Create a NAPT assignment Method: POST URL: /napt/ { "ip": "203.0.113.10", "lower_port_bound": 10000, "upper_port_bound": 19999, "profile_id": 1 } Port values must be between 0 and 65535. The complete port range is 0 through 65535. Create several NAPT assignments Method: POST URL: /napt/batch [ { "ip": "203.0.113.10", "lower_port_bound": 10000, "upper_port_bound": 19999, "profile_id": 1 }, { "ip": "203.0.113.10", "lower_port_bound": 20000, "upper_port_bound": 29999, "profile_id": 2 } ] Retrieve all NAPT assignments for an IPv4 address The path uses the integer representation of the IPv4 address. Method: GET URL: /napt/3405803786 3405803786 is the integer representation of 203.0.113.10. Delete several NAPT assignments Unlike individual NAPT resource paths, the batch-deletion body uses dotted-decimal IPv4 strings. Method: DELETE URL: /napt/batch [ { "ip": "203.0.113.10", "lower_port_bound": 10000, "upper_port_bound": 19999 }, { "ip": "203.0.113.10", "lower_port_bound": 20000, "upper_port_bound": 29999 } ] profile_id is not included in the batch-deletion request. Profile schedules A schedule temporarily switches one profile to another during specified periods. The profile identified in the URL is the source profile. target_profile_id identifies the profile used during scheduled periods. A profile cannot target itself. Supported day formats Both weekday names and integers are accepted: Integer Weekday 0 Monday 1 Tuesday 2 Wednesday 3 Thursday 4 Friday 5 Saturday 6 Sunday Weekday names must be lowercase: monday, tuesday, wednesday, thursday, friday, saturday, sunday Examples in this guide use weekday names for readability. Times use HH:MM format and must fall on 30-minute boundaries, such as 08:00, 12:30, or 18:00. 00:00 represents the start of a day and 24:00 represents the end of a day. Create a schedule Method: POST URL: /profile/1/schedule { "target_profile_id": 2, "periods": [ { "start": { "day": "monday", "time": "18:00" }, "end": { "day": "tuesday", "time": "08:00" } }, { "start": { "day": 5, "time": "00:00" }, "end": { "day": 5, "time": "24:00" } } ] } This example switches profile 1 to profile 2 from Monday evening through Tuesday morning and for the whole of Saturday. Update a schedule Method: PATCH URL: /profile/1/schedule To change the target profile for all existing periods: { "target_profile_id": 3 } To replace all existing periods: { "periods": [ { "start": { "day": "friday", "time": "18:00" }, "end": { "day": "monday", "time": "08:00" } } ] } When periods is supplied, all previously configured periods are deleted and replaced by the submitted collection. Delete a schedule Method: DELETE URL: /profile/1/schedule No request body is required. Block pages Block-page records use two types: Type Meaning 0 Default block page 1 Custom block page Example creation request: Method: POST URL: /blockpage/ { "id": 2, "type": 1 } Custom block-page content is configured outside the Shield REST API.