swagger: '2.0'
info:
    title: 'AdGuard Home'
    description: 'AdGuard Home REST API. Admin web interface is built on top of this REST API.'
    version: 0.92.0
schemes:
    - http
basePath: /control
produces:
    - application/json
tags:
    -
        name: global
        description: 'AdGuard Home server general settings and controls'
    -
        name: log
        description: 'AdGuard Home query log'
    -
        name: stats
        description: 'AdGuard Home statistics'
    -
        name: i18n
        description: 'Application localization'
    -
        name: filtering
        description: 'Rule-based filtering'
    -
        name: safebrowsing
        description: 'Blocking malware/phishing sites'
    -
        name: parental
        description: 'Blocking adult and explicit materials'
    -
        name: safesearch
        description: 'Enforce family-friendly results in search engines'
    -
        name: dhcp
        description: 'Built-in DHCP server controls'
paths:

    # API TO-DO LIST
    # TODO: Use JSON where it is possible
    # TODO: Use lower_case for all objects' properties
    # TODO: Move to definitions what's missing from there

    # --------------------------------------------------
    # General settings and controls
    # --------------------------------------------------

    /status:
        get:
            tags:
                - global
            operationId: status
            summary: 'Get DNS server current status and general settings'
            produces:
                - application/json
            responses:
                200:
                    description: OK
                    schema:
                        $ref: "#/definitions/ServerStatus"

    /enable_protection:
        post:
            tags:
                - global
            operationId: enableProtection
            summary: "Enable protection (turns on dnsfilter module in coredns)"
            responses:
                200:
                    description: OK

    /disable_protection:
        post:
            tags:
                - global
            operationId: disableProtection
            summary: "Disable protection (turns off filtering, sb, parental, safesearch temporarily by disabling dnsfilter module in coredns)"
            responses:
                200:
                    description: OK

    /set_upstream_dns:
        post:
            tags:
                - global
            operationId: setUpstreamDNS
            summary: 'Set upstream DNS for coredns, empty value will reset it to default values'
            consumes:
                - text/plain
            parameters:
                -   in: body
                    name: upstream
                    description: 'Upstream servers, separated by newline or space, port is optional after colon'
                    schema:
                        # TODO: use JSON
                        type: string
                        example: |
                            1.1.1.1
                            1.0.0.1
                            8.8.8.8 8.8.4.4
                            192.168.1.104:53535
            responses:
                200:
                    description: OK

    /test_upstream_dns:
        post:
            tags:
                - global
            operationId: testUpstreamDNS
            summary: 'Test upstream DNS'
            consumes:
                - text/plain
            parameters:
                -   in: body
                    name: upstream
                    description: 'Upstream servers, separated by newline or space, port is optional after colon'
                    schema:
                        # TODO: use JSON
                        type: string
                        example: |
                            1.1.1.1
                            1.0.0.1
                            8.8.8.8 8.8.4.4
                            192.168.1.104:53535
            responses:
                200:
                    description: 'Status of testing each requested server, with "OK" meaning that server works, any other text means an error.'
                    examples:
                        application/json:
                            1.1.1.1: OK
                            1.0.0.1: OK
                            8.8.8.8: OK
                            8.8.4.4: OK
                            "192.168.1.104:53535": "Couldn't communicate with DNS server"

    /version.json:
        get:
            tags:
                - global
            operationId: getVersionJson
            summary: 'Gets information about the latest available version of AdGuard'
            produces:
                - 'application/json'
            responses:
                200:
                    description: 'Version info'
                    schema:
                        $ref: "#/definitions/VersionInfo"
                500:
                    description: 'Cannot write answer'
                502:
                    description: 'Cannot retrieve the version.json file contents'

    # --------------------------------------------------
    # Query log methods
    # --------------------------------------------------

    /querylog:
        get:
            tags:
                - log
            operationId: queryLog
            summary: 'Get DNS server query log'
            parameters:
                - in: query
                  name: download
                  type: boolean
                  description: 'If any value is set, make the browser download the query instead of displaying it by setting Content-Disposition header'
            responses:
                200:
                    description: OK
                    schema:
                        $ref: '#/definitions/QueryLog'
    /querylog_enable:
        post:
            tags:
                - log
            operationId: querylogEnable
            summary: 'Enable querylog'
            responses:
                200:
                    description: OK
    /querylog_disable:
        post:
            tags:
                - log
            operationId: querylogDisable
            summary: 'Disable filtering'
            responses:
                200:
                    description: OK

    # --------------------------------------------------
    # General statistics methods
    # --------------------------------------------------

    /stats_top:
        get:
            tags:
                - stats
            operationId: statusTop
            summary: 'Get DNS server top client, domain and blocked statistics'
            responses:
                200:
                    description: OK
                    schema:
                        $ref: "#/definitions/StatsTop"

    /stats:
        get:
            tags:
                - stats
            operationId: stats
            summary: 'Get DNS server statistics'
            responses:
                200:
                    description: 'Returns general statistics for the last 24 hours'
                    schema:
                        $ref: "#/definitions/Stats"

    /stats_history:
        get:
            tags:
                - stats
            operationId: stats_history
            summary: 'Get historical DNS server statistics for the last 24 hours'
            parameters:
                -
                    name: start_time
                    in: query
                    type: string
                    description: 'Start time in ISO8601 (example: `2018-05-04T17:55:33+00:00`)'
                    required: true
                -
                    name: end_time
                    in: query
                    type: string
                    description: 'End time in ISO8601 (example: `2018-05-04T17:55:33+00:00`)'
                    required: true
                -
                    name: time_unit
                    in: query
                    type: string
                    description: 'Time unit (`minutes` or `hours`)'
                    required: true
                    enum:
                        - minutes
                        - hours
            responses:
                501:
                    description: 'Requested time window is outside of supported range. It will be supported later, but not now.'
                200:
                    description: 'Returns historical stats for the specified time interval.'
                    schema:
                        $ref: '#/definitions/StatsHistory'

    /stats_reset:
        post:
            tags:
                - stats
            operationId: statsReset
            summary: "Reset all statistics to zeroes"
            responses:
                200:
                    description: OK

    # --------------------------------------------------
    # DHCP server methods
    # --------------------------------------------------

    /dhcp/status:
        get:
            tags:
                - dhcp
            operationId: dhcpStatus
            summary: "Gets the current DHCP settings and status"
            responses:
                200:
                    description: OK
                    schema:
                        $ref: "#/definitions/DhcpStatus"

    /dhcp/set_config:
        post:
            tags:
                - dhcp
            operationId: dhcpSetConfig
            summary: "Updates the current DHCP server configuration"
            consumes:
            - application/json
            parameters:
            - in: "body"
              name: "body"
              description: "DHCP configuration JSON"
              required: true
              schema:
                $ref: "#/definitions/DhcpConfig"
            responses:
                200:
                    description: OK

    /dhcp/find_active_dhcp:
      post:
        tags:
            - dhcp
        operationId: checkActiveDhcp
        summary: "Searches for an active DHCP server on the network"
        responses:
          200:
            description: OK
            schema:
                $ref: "#/definitions/DhcpSearchResult"

    # --------------------------------------------------
    # Filtering status methods
    # --------------------------------------------------

    /filtering/status:
        get:
            tags:
                - filtering
            operationId: filteringStatus
            summary: 'Get status of rules-based filter'
            responses:
                200:
                    description: OK
                    schema:
                        $ref: "#/definitions/FilteringStatus"

    /filtering/enable:
        post:
            tags:
                - filtering
            operationId: filteringEnable
            summary: 'Enable filtering'
            responses:
                200:
                    description: OK

    /filtering/disable:
        post:
            tags:
                - filtering
            operationId: filteringDisable
            summary: 'Disable filtering'
            responses:
                200:
                    description: OK

    /filtering/add_url:
        put:
            tags:
                - filtering
            operationId: filteringAddURL
            summary: 'Add filter URL'
            consumes:
            - text/plain
            parameters:
              - in: body
                name: url
                description: 'URL containing filtering rules'
                required: true
                schema:
                    type: string
                    example: 'url=https://filters.adtidy.org/windows/filters/15.txt'
            responses:
                200:
                    description: OK

    /filtering/remove_url:
        delete:
            tags:
                - filtering
            operationId: filteringRemoveURL
            summary: 'Remove filter URL'
            consumes:
            - text/plain
            parameters:
              - in: body
                name: url
                description: 'Previously added URL containing filtering rules'
                required: true
                schema:
                  type: string
                  example: 'url=https://filters.adtidy.org/windows/filters/15.txt'
            responses:
                200:
                    description: OK

    /filtering/enable_url:
        post:
            tags:
                - filtering
            operationId: filteringEnableURL
            summary: 'Enable filter URL'
            consumes:
            - text/plain
            parameters:
              - in: body
                name: url
                description: 'Previously added URL containing filtering rules'
                required: true
                schema:
                  type: string
                  example: 'url=https://filters.adtidy.org/windows/filters/15.txt'
            responses:
                200:
                    description: OK

    /filtering/disable_url:
        post:
            tags:
                - filtering
            operationId: filteringDisableURL
            summary: 'Disable filter URL'
            consumes:
            - text/plain
            parameters:
              - in: body
                name: url
                description: 'Previously added URL containing filtering rules'
                required: true
                schema:
                    type: string
                    example: 'url=https://filters.adtidy.org/windows/filters/15.txt'
            responses:
                200:
                    description: OK

    /filtering/refresh:
        post:
            tags:
                - filtering
            operationId: filteringRefresh
            summary: |
                Reload filtering rules from URLs

                This might be needed if new URL was just added and you dont want to wait for automatic refresh to kick in.

                This API request is ratelimited, so you can call it freely as often as you like, it wont create unneccessary burden on servers that host the URL.

                This should work as intended, a `force` parameter is offered as last-resort attempt to make filter lists fresh.

                If you ever find yourself using `force` to make something work that otherwise wont, this is a bug and report it accordingly.

            parameters:
                -
                    name: force
                    in: query
                    type: boolean
                    description: 'If any value is set, ignore cache and force re-download of all filters'
            responses:
                200:
                    description: OK with how many filters were actually updated

    /filtering/set_rules:
        put:
            tags:
                - filtering
            operationId: filteringSetRules
            summary: 'Set user-defined filter rules'
            consumes:
                - text/plain
            parameters:
                -   in: body
                    name: rules
                    description: 'All filtering rules, one line per rule'
                    schema:
                        # TODO: move to definitions
                        type: string
                        example: '@@||yandex.ru^|'
            responses:
                200:
                    description: OK

    # --------------------------------------------------
    # Safebrowsing methods
    # --------------------------------------------------

    /safebrowsing/enable:
        post:
            tags:
                - safebrowsing
            operationId: safebrowsingEnable
            summary: 'Enable safebrowsing'
            responses:
                200:
                    description: OK

    /safebrowsing/disable:
        post:
            tags:
                - safebrowsing
            operationId: safebrowsingDisable
            summary: 'Disable safebrowsing'
            responses:
                200:
                    description: OK

    /safebrowsing/status:
        get:
            tags:
                - safebrowsing
            operationId: safebrowsingStatus
            summary: 'Get safebrowsing status'
            responses:
                200:
                    description: OK
                    examples:
                        application/json:
                            enabled: false

    # --------------------------------------------------
    # Parental control methods
    # --------------------------------------------------

    /parental/enable:
        post:
            tags:
                - parental
            operationId: parentalEnable
            summary: 'Enable parental filtering'
            consumes:
            - text/plain
            parameters:
                -   in: body
                    name: sensitivity
                    description: |
                        Age sensitivity for parental filtering,
                        EARLY_CHILDHOOD is 3
                        YOUNG is 10
                        TEEN is 13
                        MATURE is 17

                    required: true
                    schema:
                      type: string
                      enum:
                        - EARLY_CHILDHOOD
                        - YOUNG
                        - TEEN
                        - MATURE
                      example: 'sensitivity=TEEN'
            responses:
                200:
                    description: OK

    /parental/disable:
        post:
            tags:
                - parental
            operationId: parentalDisable
            summary: 'Disable parental filtering'
            responses:
                200:
                    description: OK

    /parental/status:
        get:
            tags:
                - parental
            operationId: parentalStatus
            summary: 'Get parental filtering status'
            responses:
                200:
                    description: OK
                    examples:
                        application/json:
                            enabled: true
                            sensitivity: 13

    # --------------------------------------------------
    # Safe search methods
    # --------------------------------------------------

    /safesearch/enable:
        post:
            tags:
                - safesearch
            operationId: safesearchEnable
            summary: 'Enable safesearch'
            responses:
                200:
                    description: OK

    /safesearch/disable:
        post:
            tags:
                - safesearch
            operationId: safesearchDisable
            summary: 'Disable safesearch'
            responses:
                200:
                    description: OK

    /safesearch/status:
        get:
            tags:
                - safesearch
            operationId: safesearchStatus
            summary: 'Get safesearch status'
            responses:
                200:
                    description: OK
                    examples:
                        application/json:
                            enabled: false

    # --------------------------------------------------
    # I18N methods
    # --------------------------------------------------

    /i18n/change_language:
        post:
            tags:
                - i18n
            operationId: changeLanguage
            summary: "Change current language. Argument must be an ISO 639-1 two-letter code"
            consumes:
                - text/plain
            parameters:
                - in: body
                  name: language
                  description: "New language. It must be known to the server and must be an ISO 639-1 two-letter code"
                  schema:
                    # TODO: use JSON?
                    type: string
                    example: en
            responses:
                200:
                    description: OK

    /i18n/current_language:
        get:
            tags:
                - i18n
            operationId: currentLanguage
            summary: "Get currently set language. Result is ISO 639-1 two-letter code. Empty result means default language."
            responses:
                200:
                    description: OK
                    examples:
                        text/plain:
                            en

definitions:
    ServerStatus:
        type: "object"
        description: "AdGuard Home server status and configuration"
        required:
            - "dns_address"
            - "dns_port"
            - "protection_enabled"
            - "querylog_enabled"
            - "running"
            - "bootstrap_dns"
            - "upstream_dns"
            - "version"
            - "language"
        properties:
            dns_address:
                type: "string"
                example: "127.0.0.1"
            dns_port:
                type: "integer"
                format: "int32"
                example: 53
                minimum: 1
                maximum: 65535
            protection_enabled:
                type: "boolean"
            querylog_enabled:
                type: "boolean"
            running:
                type: "boolean"
            bootstrap_dns:
                type: "string"
                example: "8.8.8.8:53"
            upstream_dns:
                type: "array"
                items:
                    type: "string"
                example:
                  - "tls://1.1.1.1"
                  - "tls://1.0.0.1"
            version:
                type: "string"
                example: "0.1"
            language:
                type: "string"
                example: "en"
    Filter:
        type: "object"
        description: "Filter subscription info"
        required:
            - "enabled"
            - "id"
            - "lastUpdated"
            - "name"
            - "rulesCount"
            - "url"
        properties:
            enabled:
                type: "boolean"
            id:
                type: "integer"
                example: 1234
            lastUpdated:
                type: "string"
                format: "date-time"
                example: "2018-10-30T12:18:57.223101822+03:00"
            name:
                type: "string"
                example: "AdGuard Simplified Domain Names filter"
            rulesCount:
                type: "integer"
                example: 5912
            url:
                type: "string"
                example: "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt"
    FilteringStatus:
        type: "object"
        description: "Filtering settings"
        required:
            - "enabled"
            - "filters"
            - "user_rules"
        properties:
            enabled:
                type: "boolean"
            filters:
                type: "array"
                items:
                    $ref: "#/definitions/Filter"
            user_rules:
                type: "array"
                items:
                    type: "string"
                example:
                    - '||example.org^'
                    - '||example.com^'
    VersionInfo:
        type: "object"
        description: "Information about the latest available version of AdGuard Home"
        required:
            - "version"
            - "announcement"
            - "announcement_url"
            - "download_darwin_amd64"
            - "download_linux_amd64"
            - "download_linux_386"
            - "download_linux_arm"
            - "selfupdate_min_version"
        properties:
            version:
                type: "string"
                example: "v0.9"
            announcement:
                type: "string"
                example: "AdGuard Home v0.9 is now available!"
            announcement_url:
                type: "string"
                example: "https://github.com/AdguardTeam/AdGuardHome/releases/tag/v0.9"
            download_darwin_amd64:
                type: "string"
                example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_MacOS.zip"
            download_linux_amd64:
                type: "string"
                example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_linux_amd64.tar.gz"
            download_linux_386:
                type: "string"
                example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_linux_386.tar.gz"
            download_linux_arm:
                type: "string"
                example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_linux_arm.tar.gz"
            selfupdate_min_version:
                type: "string"
                example: "v0.0"
    Stats:
        type: "object"
        description: "General server stats for the last 24 hours"
        required:
            - "dns_queries"
            - "blocked_filtering"
            - "replaced_safebrowsing"
            - "replaced_parental"
            - "replaced_safesearch"
            - "avg_processing_time"
        properties:
            dns_queries:
                type: "integer"
                description: "Total number of DNS queries"
                example: 123
            blocked_filtering:
                type: "integer"
                description: "Number of requests blocked by filtering rules"
                example: 50
            replaced_safebrowsing:
                type: "integer"
                description: "Number of requests blocked by the safebrowsing module"
                example: 5
            replaced_parental:
                type: "integer"
                description: "Number of blocked adult websites"
                example: 15
            avg_processing_time:
                type: "number"
                format: "float"
                description: "Average time in milliseconds on processing a DNS"
                example: 0.34
    StatsTop:
        type: "object"
        description: "Server stats top charts"
        required:
            - "top_queried_domains"
            - "top_clients"
            - "top_blocked_domains"
        properties:
            top_queried_domains:
                type: "array"
                items:
                    type: "object"
                example:
                    example.org: 12312
                    example.com: 321
                    example.net: 5555
            top_clients:
                type: "array"
                items:
                    type: "object"
                example:
                    127.0.0.1: 12312
                    192.168.0.1: 13211
                    192.168.0.3: 13211
            top_blocked_domains:
                type: "array"
                items:
                    type: "object"
                example:
                    example.org: 12312
                    example.com: 321
                    example.net: 5555
    StatsHistory:
        type: "object"
        description: "Historical stats of the DNS server. Example below is for 5 minutes. Values are from oldest to newest."
        required:
            - "dns_queries"
            - "blocked_filtering"
            - "replaced_safebrowsing"
            - "replaced_parental"
            - "replaced_safesearch"
            - "avg_processing_time"
        properties:
            dns_queries:
                type: "array"
                items:
                    type: "integer"
                example:
                    - 1201
                    - 1501
                    - 1251
                    - 1231
                    - 120
            blocked_filtering:
                type: "array"
                items:
                    type: "integer"
                example:
                    - 421
                    - 124
                    - 5
                    - 12
                    - 43
            replaced_safebrowsing:
                type: "array"
                items:
                    type: "integer"
                example:
                    - 1
                    - 0
                    - 5
                    - 0
                    - 0
            replaced_parental:
                type: "array"
                items:
                    type: "integer"
                example:
                    - 120
                    - 10
                    - 5
                    - 12
                    - 1
            replaced_safesearch:
                type: "array"
                items:
                    type: "integer"
                example:
                    - 1
                    - 0
                    - 0
                    - 0
                    - 5
            avg_processing_time:
                type: "array"
                items:
                    type: "number"
                    format: "float"
                example:
                    - 1.25
                    - 5.12
                    - 4.12
                    - 123.12
                    - 0.12
    DhcpConfig:
        type: "object"
        description: "Built-in DHCP server configuration"
        required:
            - "enabled"
            - "gateway_ip"
            - "subnet_mask"
            - "range_start"
            - "range_end"
            - "lease_duration"
        properties:
            enabled:
                type: "boolean"
            gateway_ip:
                type: "string"
                example: "192.168.1.1"
            subnet_mask:
                type: "string"
                example: "255.255.255.0"
            range_start:
                type: "string"
                example: "192.168.1.2"
            range_end:
                type: "string"
                example: "192.168.10.50"
            lease_duration:
                type: "string"
                example: "12h"
    DhcpLease:
        type: "object"
        description: "DHCP lease information"
        required:
            - "mac"
            - "ip"
            - "hostname"
            - "expires"
        properties:
            mac:
                type: "string"
                example: "001109b3b3b8"
            ip:
                type: "string"
                example: "192.168.1.22"
            hostname:
                type: "string"
                example: "dell"
            expires:
                type: "string"
                format: "date-time"
                example: "2017-07-21T17:32:28Z"
    DhcpStatus:
        type: "object"
        description: "Built-in DHCP server configuration and status"
        required:
            - "config"
            - "leases"
        properties:
            config:
                $ref: "#/definitions/DhcpConfig"
            leases:
                type: "array"
                items:
                    $ref: "#/definitions/DhcpLease"
    DhcpSearchResult:
        type: "object"
        description: "Information about a DHCP server discovered in the current network"
        required:
            - "found"
        properties:
            found:
                type: "boolean"
            gateway_ip:
                type: "string"
                example: "192.168.1.1"
    DnsAnswer:
        type: "object"
        description: "DNS answer section"
        properties:
            ttl:
                type: "integer"
                example: 55
            type:
                type: "string"
                example: "A"
            value:
                type: "string"
                example: "217.69.139.201"
    DnsQuestion:
        type: "object"
        description: "DNS question section"
        properties:
            class:
                type: "string"
                example: "IN"
            host:
                type: "string"
                example: "example.org"
            type:
                type: "string"
                example: "A"
    QueryLogItem:
        type: "object"
        description: "Query log item"
        properties:
            answer:
                type: "array"
                items:
                    $ref: "#/definitions/DnsAnswer"
            client:
                type: "string"
                example: "192.168.0.1"
            elapsedMs:
                type: "string"
                example: "54.023928"
            question:
                $ref: "#/definitions/DnsQuestion"
            filterId:
                type: "integer"
                example: 123123
                description: "In case if there's a rule applied to this DNS request, this is ID of the filter that rule belongs to."
            rule:
                type: "string"
                example: "||example.org^"
                description: "Filtering rule applied to the request (if any)"
            reason:
                type: "string"
                description: "DNS filter status"
                enum:
                - "NotFilteredNotFound"
                - "NotFilteredWhiteList"
                - "NotFilteredError"
                - "FilteredBlackList"
                - "FilteredSafeBrowsing"
                - "FilteredParental"
                - "FilteredInvalid"
                - "FilteredSafeSearch"
            status:
                type: "string"
                description: "DNS response status"
                example: "NOERROR"
            time:
                type: "string"
                description: "DNS request processing start time"
                example: "2018-11-26T00:02:41+03:00"
    QueryLog:
        type: "array"
        description: "Query log"
        items:
            $ref: "#/definitions/QueryLogItem"