Documentation contents
Projects
Projects (sites followed over time) and their health scorecard.
List projects
GET
/v1/projects
Every project of the token's team, newest first.
- Required scopes
- projects:read
- Rate-limit cost
- 1 unit(s)
Parameters
-
cursorquery · string · optionalOpaque cursor from `meta.next_cursor`. It is bound to the request that issued it; reusing it with other filters returns `400 pagination.invalid_cursor`.
-
limitquery · integer · optionalItems per page, 1 to 100 (default 25).
Responses
-
200OK. -
400Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`). -
422Invalid query or body values (`validation_failed`), with `errors` by field. -
401Missing, invalid or expired token, or a member who left the team. -
403The 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`). -
404No such resource for the token's team. Resources of another team answer 404 as well, never 403. -
429The plan rate limit is exhausted for one window.
cURL
curl "https://api.nessflow.com/v1/projects" \
-H "Authorization: Bearer $NESSFLOW_TOKEN"
PHP
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
$response = $client->request('GET', 'projects', [
'headers' => [
'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
],
]);
$data = json_decode((string) $response->getBody(), true);
JavaScript
const response = await fetch('https://api.nessflow.com/v1/projects', {
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",
headers={
"Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
},
timeout=30,
)
response.raise_for_status()
data = response.json()
Response example
{
"data": [
{
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"name": "Exemple",
"slug": "string",
"url": "https://exemple.fr/",
"domain": "string",
"locked": true,
"created_at": "2026-10-01T09:30:00Z",
"latest_completed_crawl": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"finished_at": "string"
}
}
],
"meta": {
"limit": 100,
"has_more": true,
"next_cursor": "string"
}
}
Create a project
POST
/v1/projects
Creates a project and its default campaign, under the same rules as the product: the URL must be a public site, and the plan project limit applies.
- Required scopes
- projects:write
- Rate-limit cost
- 1 unit(s)
- Idempotency-Key
- Idempotency-Key accepted
Request body
-
urlstring · requiredPublic site URL.
-
namestring | null · optionalDefaults to the host name.
Responses
-
201OK. -
400Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`). -
401Missing, invalid or expired token, or a member who left the team. -
403The 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`). -
404No such resource for the token's team. Resources of another team answer 404 as well, never 403. -
409The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready). -
422Invalid query or body values (`validation_failed`), with `errors` by field. -
429The plan rate limit is exhausted for one window.
cURL
curl -X POST "https://api.nessflow.com/v1/projects" \
-H "Authorization: Bearer $NESSFLOW_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"url":"https://exemple.fr/","name":"Exemple"}'
PHP
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
$response = $client->request('POST', 'projects', [
'headers' => [
'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
'Idempotency-Key' => bin2hex(random_bytes(16)),
],
'json' => [
'url' => 'https://exemple.fr/',
'name' => 'Exemple',
],
]);
$data = json_decode((string) $response->getBody(), true);
JavaScript
const response = await fetch('https://api.nessflow.com/v1/projects', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"url": "https://exemple.fr/",
"name": "Exemple"
}),
});
const data = await response.json();
Python
import os
import uuid
import requests
response = requests.post(
"https://api.nessflow.com/v1/projects",
headers={
"Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"url": "https://exemple.fr/",
"name": "Exemple",
},
timeout=30,
)
response.raise_for_status()
data = response.json()
Response example
{
"data": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"name": "Exemple",
"slug": "string",
"url": "https://exemple.fr/",
"domain": "string",
"locked": true,
"created_at": "2026-10-01T09:30:00Z",
"latest_completed_crawl": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"finished_at": "string"
}
}
}
Get a project
GET
/v1/projects/{project}
A project and its latest completed crawl.
- Required scopes
- projects:read
- Rate-limit cost
- 1 unit(s)
Parameters
-
projectpath · string (uuid) · required
Responses
-
200OK. -
401Missing, invalid or expired token, or a member who left the team. -
403The 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`). -
404No such resource for the token's team. Resources of another team answer 404 as well, never 403. -
429The plan rate limit is exhausted for one window.
cURL
curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57" \
-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', [
'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', {
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",
headers={
"Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
},
timeout=30,
)
response.raise_for_status()
data = response.json()
Response example
{
"data": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"name": "Exemple",
"slug": "string",
"url": "https://exemple.fr/",
"domain": "string",
"locked": true,
"created_at": "2026-10-01T09:30:00Z",
"latest_completed_crawl": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"finished_at": "string"
}
}
}
Update a project
PATCH
/v1/projects/{project}
Changes the name or the URL. Changing the URL clears what described the
previous site (profile, priority URLs). A read-only project answers
403 project.locked.
- Required scopes
- projects:write
- Rate-limit cost
- 1 unit(s)
Parameters
-
projectpath · string (uuid) · required
Request body
-
namestring · optional -
urlstring · optional
Responses
-
200OK. -
401Missing, invalid or expired token, or a member who left the team. -
403The 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`). -
404No such resource for the token's team. Resources of another team answer 404 as well, never 403. -
422Invalid query or body values (`validation_failed`), with `errors` by field. -
429The plan rate limit is exhausted for one window.
cURL
curl -X PATCH "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57" \
-H "Authorization: Bearer $NESSFLOW_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Exemple","url":"https://exemple.fr/"}'
PHP
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
$response = $client->request('PATCH', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57', [
'headers' => [
'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
],
'json' => [
'name' => 'Exemple',
'url' => 'https://exemple.fr/',
],
]);
$data = json_decode((string) $response->getBody(), true);
JavaScript
const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Exemple",
"url": "https://exemple.fr/"
}),
});
const data = await response.json();
Python
import os
import requests
response = requests.patch(
"https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
headers={
"Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
},
json={
"name": "Exemple",
"url": "https://exemple.fr/",
},
timeout=30,
)
response.raise_for_status()
data = response.json()
Response example
{
"data": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"name": "Exemple",
"slug": "string",
"url": "https://exemple.fr/",
"domain": "string",
"locked": true,
"created_at": "2026-10-01T09:30:00Z",
"latest_completed_crawl": {
"id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
"finished_at": "string"
}
}
}
Delete a project
DELETE
/v1/projects/{project}
Deletes the project and everything it holds, for good. Allowed on a read-only project.
- Required scopes
- projects:write
- Rate-limit cost
- 1 unit(s)
Parameters
-
projectpath · string (uuid) · required
Responses
-
204Deleted. -
401Missing, invalid or expired token, or a member who left the team. -
403The 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`). -
404No such resource for the token's team. Resources of another team answer 404 as well, never 403. -
429The plan rate limit is exhausted for one window.
cURL
curl -X DELETE "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57" \
-H "Authorization: Bearer $NESSFLOW_TOKEN"
PHP
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.nessflow.com/v1/']);
$response = $client->request('DELETE', 'projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57', [
'headers' => [
'Authorization' => 'Bearer '.getenv('NESSFLOW_TOKEN'),
],
]);
JavaScript
const response = await fetch('https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.NESSFLOW_TOKEN}`,
},
});
Python
import os
import requests
response = requests.delete(
"https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
headers={
"Authorization": f"Bearer {os.environ['NESSFLOW_TOKEN']}",
},
timeout=30,
)
response.raise_for_status()
Response example
No response body.
Get the health scorecard
GET
/v1/projects/{project}/scorecard
The five pillars of the health score (technical, content and GEO,
accessibility, Search Console acquisition, log exploration), as on the
project screen. There is no global average by design: pillars of different
natures do not add up. A pillar that cannot be measured has score: null,
never 0.
- Required scopes
- projects:read
- Rate-limit cost
- 5 unit(s)
Parameters
-
projectpath · string (uuid) · required
Responses
-
200OK. -
401Missing, invalid or expired token, or a member who left the team. -
403The 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`). -
404No such resource for the token's team. Resources of another team answer 404 as well, never 403. -
429The plan rate limit is exhausted for one window.
cURL
curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/scorecard" \
-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/scorecard', [
'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/scorecard', {
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/scorecard",
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",
"pillars": [
{
"key": "technique",
"score": 42,
"status": "good",
"available": true,
"version": 42,
"as_of": "string",
"blocked_reason": "string",
"axes": [
{}
]
}
]
}
}