Skip to content
NessFlow
Menu
    Documentation contents

    Modules

    Modules outside the health score (rankings, Search Console, backlinks, security, logs). They carry trends, never a score.

    Read rank tracking

    GET /v1/projects/{project}/positions

    Tracked keywords and their latest position for the project domain, with the period summary. A keyword with measured: false was never checked; a keyword with measured: true and position: null was checked and is out of the top 100. Requires a plan that includes the module.

    Required scopes
    positions:read
    Rate-limit cost
    5 unit(s)

    Parameters

    • project path · string (uuid) · required

    • period query · string · optional

    Responses

    • 200 OK.
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/positions" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN"

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('GET', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/positions', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/positions', {
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
      },
    });
    
    const data = await response.json();

    Python

    import os
    
    import requests
    
    response = requests.get(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/positions",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "status": "unconfigured",
            "tracker": {
                "location": "string",
                "country": "string",
                "language": "string",
                "device": "string",
                "active": true,
                "last_tracked_on": "2026-10-01"
            },
            "period": {
                "preset": "string",
                "from": "2026-10-01",
                "to": "2026-10-01"
            },
            "summary": {
                "average_position": 0.5,
                "ranking_keywords": 42,
                "measured_keywords": 42,
                "tracked_keywords": 42,
                "top3": 42,
                "top10": 42,
                "visibility_percent": 0.5,
                "improved": 42,
                "declined": 42,
                "entered": 42,
                "exited": 42
            },
            "keywords": [
                {
                    "keyword": "string",
                    "active": true,
                    "measured": true,
                    "position": 42,
                    "url": "https://exemple.fr/",
                    "delta_1d": 42,
                    "delta_7d": 42,
                    "delta_30d": 42,
                    "search_volume": 42,
                    "keyword_difficulty": 42,
                    "search_intent": "string",
                    "serp_features": [
                        "string"
                    ]
                }
            ],
            "quota": {
                "used": 42,
                "limit": 100,
                "remaining": 100
            }
        }
    }

    Track keywords

    POST /v1/projects/{project}/tracked-keywords

    Puts keywords under daily rank tracking (at most 100 per request). A keyword is identified by its canonical form (lowercase, single spaces), which the response returns. A keyword already known to the project as a candidate is adopted. This opens a recurring daily spend: it counts against the plan pool positions.tracked_keywords (plan_limit.positions.tracked_keywords) and the per-project ceiling (keywords.project_limit), so an Idempotency-Key is required.

    Required scopes
    positions:write
    Rate-limit cost
    1 unit(s)
    Idempotency-Key
    Idempotency-Key required
    Rate-limit cost
    Consumes a plan quota

    Parameters

    • project path · string (uuid) · required

    Request body

    • keywords string[] · required

    Responses

    • 200 OK.
    • 400 Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 409 The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready).
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl -X POST "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"keywords":["string"]}'

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('POST', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
            'Idempotency-Key' => bin2hex(random_bytes(16)),
        ],
        'json' => [
            'keywords' => [
                'string',
            ],
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': crypto.randomUUID(),
      },
      body: JSON.stringify({
          "keywords": [
              "string"
          ]
      }),
    });
    
    const data = await response.json();

    Python

    import os
    import uuid
    
    import requests
    
    response = requests.post(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "keywords": [
                "string",
            ],
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "tracked": [
                "string"
            ],
            "already_tracked": [
                "string"
            ]
        }
    }

    Stop tracking keywords

    POST /v1/projects/{project}/tracked-keywords/untrack

    Removes keywords from tracking without deleting them: their paid history stays, and their slots are freed. Never refused by billing. Unknown or untracked keywords are ignored; untracked lists those that changed.

    Required scopes
    positions:write
    Rate-limit cost
    1 unit(s)
    Idempotency-Key
    Idempotency-Key accepted

    Parameters

    • project path · string (uuid) · required

    Request body

    • keywords string[] · required

    Responses

    • 200 OK.
    • 400 Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 409 The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready).
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl -X POST "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/untrack" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"keywords":["string"]}'

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('POST', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/untrack', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
            'Idempotency-Key' => bin2hex(random_bytes(16)),
        ],
        'json' => [
            'keywords' => [
                'string',
            ],
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/untrack', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': crypto.randomUUID(),
      },
      body: JSON.stringify({
          "keywords": [
              "string"
          ]
      }),
    });
    
    const data = await response.json();

    Python

    import os
    import uuid
    
    import requests
    
    response = requests.post(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/untrack",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "keywords": [
                "string",
            ],
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "untracked": [
                "string"
            ]
        }
    }

    Pause tracked keywords

    POST /v1/projects/{project}/tracked-keywords/pause

    Suspends the daily check of tracked keywords, which frees their slots in the plan pool. keywords.not_tracked if one of them is not tracked.

    Required scopes
    positions:write
    Rate-limit cost
    1 unit(s)
    Idempotency-Key
    Idempotency-Key accepted

    Parameters

    • project path · string (uuid) · required

    Request body

    • keywords string[] · required

    Responses

    • 200 OK.
    • 400 Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 409 The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready).
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl -X POST "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/pause" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"keywords":["string"]}'

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('POST', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/pause', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
            'Idempotency-Key' => bin2hex(random_bytes(16)),
        ],
        'json' => [
            'keywords' => [
                'string',
            ],
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/pause', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': crypto.randomUUID(),
      },
      body: JSON.stringify({
          "keywords": [
              "string"
          ]
      }),
    });
    
    const data = await response.json();

    Python

    import os
    import uuid
    
    import requests
    
    response = requests.post(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/pause",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "keywords": [
                "string",
            ],
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "active": true,
            "changed": [
                "string"
            ]
        }
    }

    Resume tracked keywords

    POST /v1/projects/{project}/tracked-keywords/resume

    Resumes the daily check of paused keywords. Resuming takes a slot back in the plan pool (plan_limit.positions.tracked_keywords), so an Idempotency-Key is required.

    Required scopes
    positions:write
    Rate-limit cost
    1 unit(s)
    Idempotency-Key
    Idempotency-Key required
    Rate-limit cost
    Consumes a plan quota

    Parameters

    • project path · string (uuid) · required

    Request body

    • keywords string[] · required

    Responses

    • 200 OK.
    • 400 Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 409 The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready).
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl -X POST "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/resume" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"keywords":["string"]}'

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('POST', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/resume', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
            'Idempotency-Key' => bin2hex(random_bytes(16)),
        ],
        'json' => [
            'keywords' => [
                'string',
            ],
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/resume', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': crypto.randomUUID(),
      },
      body: JSON.stringify({
          "keywords": [
              "string"
          ]
      }),
    });
    
    const data = await response.json();

    Python

    import os
    import uuid
    
    import requests
    
    response = requests.post(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/resume",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "keywords": [
                "string",
            ],
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "active": true,
            "changed": [
                "string"
            ]
        }
    }

    Check a keyword now

    POST /v1/projects/{project}/tracked-keywords/check

    Queues an immediate live check of one tracked keyword (202); the position appears in the rank tracking read once measured. One immediate check per keyword per day (keywords.already_checked_today), within the plan daily quota (plan_limit.positions.live_checks_per_day) and monthly spend cap.

    Required scopes
    positions:write
    Rate-limit cost
    1 unit(s)
    Idempotency-Key
    Idempotency-Key required
    Rate-limit cost
    Consumes a plan quota

    Parameters

    • project path · string (uuid) · required

    Request body

    • keyword string · required

    Responses

    • 202 OK.
    • 400 Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 409 The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready).
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl -X POST "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/check" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"keyword":"string"}'

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('POST', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/check', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
            'Idempotency-Key' => bin2hex(random_bytes(16)),
        ],
        'json' => [
            'keyword' => 'string',
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/check', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': crypto.randomUUID(),
      },
      body: JSON.stringify({
          "keyword": "string"
      }),
    });
    
    const data = await response.json();

    Python

    import os
    import uuid
    
    import requests
    
    response = requests.post(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/tracked-keywords/check",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "keyword": "string",
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "keyword": "string",
            "status": "queued",
            "date": "2026-10-01"
        }
    }

    Read Search Console data

    GET /v1/projects/{project}/search-console

    Performance totals and daily series (from the linked property), and the indexation inspection totals. unconfigured means no property is linked, pending that it is linked but not synced yet.

    Required scopes
    search_console:read
    Rate-limit cost
    5 unit(s)

    Parameters

    • project path · string (uuid) · required

    • period query · string · optional

    Responses

    • 200 OK.
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/search-console" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN"

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('GET', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/search-console', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/search-console', {
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
      },
    });
    
    const data = await response.json();

    Python

    import os
    
    import requests
    
    response = requests.get(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/search-console",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "status": "unconfigured",
            "property": "string",
            "performance": {
                "period": {
                    "preset": "string",
                    "from": "2026-10-01",
                    "to": "2026-10-01"
                },
                "totals": {
                    "clicks": 42,
                    "impressions": 42,
                    "ctr_percent": 0.5,
                    "average_position": 0.5
                },
                "daily": [
                    {
                        "date": "2026-10-01",
                        "clicks": 42,
                        "impressions": 42,
                        "average_position": 0.5
                    }
                ]
            },
            "indexation": {
                "inspected": 42,
                "indexed": 42,
                "excluded": 42,
                "canonical_conflicts": 42,
                "last_inspected_at": "2026-10-01T09:30:00Z"
            }
        }
    }

    Read security signals

    GET /v1/projects/{project}/security

    Passive security signals of the project site, with their status. An incomplete scan (scan.complete: false) does not mean nothing was found; score: null means unknown, never zero. Texts follow Accept-Language.

    Required scopes
    security:read
    Rate-limit cost
    5 unit(s)

    Parameters

    • project path · string (uuid) · required

    Responses

    • 200 OK.
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/security" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN"

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('GET', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/security', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/security', {
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
      },
    });
    
    const data = await response.json();

    Python

    import os
    
    import requests
    
    response = requests.get(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/security",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "status": "string",
            "target": "string",
            "scan": {
                "status": "string",
                "running": true,
                "complete": true,
                "results_truncated": true,
                "started_at": "2026-10-01T09:30:00Z",
                "finished_at": "2026-10-01T09:30:00Z"
            },
            "score": 42,
            "counts": {
                "problems": 42,
                "informational": 42,
                "fixed": 42,
                "masked": 42,
                "ignored": 42,
                "falsePositive": 42
            },
            "findings": [
                {
                    "key": "string",
                    "severity": "critical",
                    "status": "string",
                    "location": "string",
                    "title": "string",
                    "explanation": "string",
                    "action": "string",
                    "first_seen_at": "2026-10-01T09:30:00Z",
                    "last_seen_at": "2026-10-01T09:30:00Z",
                    "fixed_at": "2026-10-01T09:30:00Z"
                }
            ]
        }
    }

    Read server log analysis

    GET /v1/projects/{project}/logs

    Hits by audience (humans, search bots, AI bots, others) over the period, with the days actually covered by logs.

    Required scopes
    logs:read
    Rate-limit cost
    5 unit(s)

    Parameters

    • project path · string (uuid) · required

    • period query · string · optional

    Responses

    • 200 OK.
    • 401 Missing, invalid or expired token, or a member who left the team.
    • 403 The plan does not include the API (`api.not_in_plan`) or this verb (`api.write_not_in_plan`), or the token lacks a scope (`token.missing_scope`).
    • 404 No such resource for the token's team. Resources of another team answer 404 as well, never 403.
    • 422 Invalid query or body values (`validation_failed`), with `errors` by field.
    • 429 The plan rate limit is exhausted for one window.

    cURL

    curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/logs" \
      -H "Authorization: Bearer $NESSFLOW_TOKEN"

    PHP

    $client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
    
    $response = $client->request('GET', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/logs', [
        'headers' => [
            'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
        ],
    ]);
    
    $data = json_decode((string) $response->getBody(), true);

    JavaScript

    const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/logs', {
      headers: {
        Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
      },
    });
    
    const data = await response.json();

    Python

    import os
    
    import requests
    
    response = requests.get(
        "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/logs",
        headers={
            "Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
        },
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()

    Response example

    {
        "data": {
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "status": "pending",
            "period": {
                "preset": "string",
                "from": "2026-10-01",
                "to": "2026-10-01",
                "days": 42,
                "days_with_logs": 42
            },
            "totals": {
                "hits": 42,
                "bot_hits": 42,
                "human_hits": 42,
                "bytes": 42
            },
            "daily": [
                {
                    "date": "2026-10-01",
                    "humans": 42,
                    "search": 42,
                    "ai": 42,
                    "others": 42
                }
            ],
            "gaps": [
                {
                    "from": "2026-10-01",
                    "to": "2026-10-01",
                    "days": 42
                }
            ]
        }
    }

    API reference Error codes API documentation

    This page in Markdown