Netlify is a hosting service for the programmable web. It understands your documents and provides an API to handle atomic deploys of websites, manage form submissions, inject JavaScript snippets, and
Full LLM thinking from the 4-phase benchmark pipeline.
{
"service_type": "rest_api",
"base_url": "https://api.netlify.com/api/v1",
"auth_method": "oauth2",
"auth_config": {
"header": "Authorization",
"prefix": "Bearer"
},
"endpoints": [
{
"path": "/sites",
"method": "GET",
"purpose": "List all sites for the authenticated user",
"params": {},
"response_format": "json",
"is_primary": true
},
{
"path": "/sites",
"method": "POST",
"purpose": "Create a new site",
"params": {},
"response_format": "json",
"is_primary": false
},
{
"path": "/sites/{site_id}",
"method": "GET",
"purpose": "Get details of a specific site",
"params": {
"site_id": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": true
},
{
"path": "/sites/{site_id}",
"method": "PUT",
"purpose": "Update a site",
"params": {
"site_id": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/sites/{site_id}",
"method": "DELETE",
"purpose": "Delete a site",
"params": {
"site_id": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
}
],
"pricing_model": {
"type": "tiered",
"details": {},
"free_tier": {
"requests": null,
"period": null
},
"paid_tiers": []
},
"rate_limits": {
"rpm": null,
"tpm": null,
"daily": null,
"concurrent": null
},
"capabilities": [
"site_management",
"deployment",
"build_management",
"form_handling",
"dns_management",
"ssl_certificates",
"environment_variables",
"functions",
"edge_functions",
"database",
"storage",
"ai_gateway"
],
"agent_readiness": {
"supports_x402": false,
"supports_streaming": false,
"has_sandbox": false,
"sdks": ["go", "javascript"],
"agent_auth_methods": ["oauth2_client_credentials"]
}
}```json
{
"tests": [
{
"name": "list_sites_happy_path",
"endpoint": "/sites",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns JSON array of site objects for the authenticated user",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "data", "type": "array", "min_length": 0}
},
{
"name": "list_sites_pagination",
"endpoint": "/sites?page=1&per_page=5",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns array truncated to per_page=5; verifies pagination params honored",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "data", "type": "array", "max_length": 5}
},
{
"name": "list_sites_filter_owner",
"endpoint": "/sites?filter=owner",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns only sites owned by the authenticated user",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "data", "type": "array"}
},
{
"name": "get_site_happy_path",
"endpoint": "/sites/{site_id}",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns a single site object with id equal to requested site_id",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "id", "type": "string", "equals_path_param": "site_id"}
},
{
"name": "get_current_user",
"endpoint": "/user",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Confirms auth is valid and returns user profile (id, email)",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "id", "type": "string"}
},
{
"name": "get_site_not_found",
"endpoint": "/sites/0000000000000000000000000000000000000000",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 404,
"intent": "validation",
"expected_behavior": "Nonexistent site_id returns structured 404 error body, not 200 or 500",
"metrics": ["status_code", "accuracy"],
"validation": {"field": "message", "type": "string"}
},
{
"name": "get_site_invalid_id_format",
"endpoint": "/sites/!!!not-a-valid-id!!!",
"method": "GET",
"headers": {"Authorization": "Bearer {token}"},
"payload": {},
"expected_status": 404,
"intent": "validation",
"expected_behavior": "Malformed site_id is rejected with a 4xx error body rather than a 500",
"metrics": ["status_code", "accuracy"]
},
{
"name": "create_site_missing_required_body",
"endpoint": "/sites",
"method": "POST",
"headers": {"Authorization": "Bearer {token}", "Content-Type": "application/json"},
"payload": {},
"expected_status": 422,
"intent": "validation",
"expected_behavior": "Empty body should be rejected with a structured validation error (4xx), not silently accepted",
"metrics": ["status_code", "accuracy"],
"validation": {"field": "message", "type": "string"}
},
{
"name": "create_site_happy_path",
"endpoint": "/sites",
"method": "POST",
"headers": {"Authorization": "Bearer {token}", "Content-Type": "application/json"},
"payload": {"name": "prowl-benchmark-tmp-site"},
"expected_status": 201,
"intent": "happy_path",
"expected_behavior": "Creates a new site and returns site object with id and url; cleanup via DELETE afterward",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "id", "type": "string"}
},
{
"name": "create_site_invalid_configure_dns_type",
"endpoint": "/sites?configure_dns=notabool",
"method": "POST",
"headers": {"Authorization": "Bearer {token}", "Content-Type": "application/json"},
"payload": {"name": "prowl-benchmark-badparam"},
"expected_status": 400,
"intent": "validation",
"expected_behavior": "Non-boolean value for configure_dns query param should be rejected with 4xx",
"metrics": ["status_code"]
},
{
"name": "list_sites_missing_auth",
"endpoint": "/sites",
"method": "GET",
"headers": {},
"payload": {},
"expected_status": 401,
"intent": "auth",
"expected_behavior": "Request wit1/17 tests passed
| Test | Endpoint | Status | Latency |
|---|---|---|---|
| list_sites_happy_path | GET /sites | 401 | 150ms |
| list_sites_pagination | GET /sites?page=1&per_page=5 | 401 | 48ms |
| list_sites_filter_owner | GET /sites?filter=owner | 401 | 50ms |
| get_site_happy_path | GET /sites/{site_id} | 401 | 51ms |
| get_current_user | GET /user | 401 | 59ms |
| get_site_not_found | GET /sites/0000000000000000000000000000000000000000 | 401 | 49ms |
| get_site_invalid_id_format | GET /sites/!!!not-a-valid-id!!! | 401 | 49ms |
| create_site_missing_required_body | POST /sites | 401 | 52ms |
| create_site_happy_path | POST /sites | 401 | 48ms |
| create_site_invalid_configure_dns_type | POST /sites?configure_dns=notabool | 401 | 46ms |
{"model": "deepseek", "data": {"overall": 55, "dimensions": {"token_efficiency": 7.0, "first_try_success": 5.0, "response_parseability": 8.0, "error_clarity": 6.0, "doc_quality": 5.0, "auth_simplicity": 4.0, "latency": 10.0, "consistency": 9.0}, "pricing_normalized": {"cost_per_1k_requests": null, "cost_per_1m_input_tokens": null, "cost_per_1m_output_tokens": null, "free_tier_requests": null, "estimated_monthly_cost_light": null, "estimated_monthly_cost_heavy": null}, "issues": [{"severity": "critical", "detail": "All authenticated happy-path and validation tests returned 401 'Access Denied' \u2014 the benchmark lacked valid credentials, so no meaningful happy-path, validation-of-real-data, or pagination/filter behavior could be verified. Only public endpoints and unauthenticated auth-rejection tests produced useful signal.", "endpoint": "/sites"}, {"severity": "high", "detail": "Validation tests (invalid site id format, missing required body, invalid query param type, missing resource) all returned 401 instead of expected 4xx validation responses, because the agent never authenticated. Real 400/422 behavior for these endpoints is unverified.", "endpoint": "/sites/{site_id}"}, {"severity": "medium", "detail": "Error body is inconsistent across endpoints: /sites returns {'code','message'} while /purge returns {'code','msg','error_id'}. Field name differs ('message' vs 'msg'), and error_id only appears on some endpoints.", "endpoint": "/purge"}, {"severity": "low", "detail": "401 error body is minimal ({'code':401,'message':'Access Denied'}) \u2014 it does not indicate whether the token was missing, malformed, or lacked scope, making agent self-correction harder.", "endpoint": "/sites"}], "recommendations": ["Re-run the benchmark with a valid API token so happy-path, pagination, filter, create/get/update/delete, and true validation paths can be exercised; the current run is dominated by auth failures.", "Standardize error envelopes across all endpoints (e.g. always use {code, message, error_id}) so agents can parse errors uniformly.", "Enrich 401 responses to distinguish 'missing token' vs 'invalid token' vs 'insufficient scope' \u2014 this helps an agent recover autonomously.", "Publish a complete OpenAPI spec with example requests/responses for /sites, /sites/{site_id}, /purge, and env-var endpoints to reduce agent guesswork.", "Document the auth scheme explicitly (token header name/format) and any rate-limit headers, since auth was the main failure mode.", "Confirm whether /ai-gateway/providers is intentionally public and document it, as it was the only endpoint returning 200."]}}Show your live agent-readiness score on your own site. Free, no auth — it updates as your score changes.
<a href="https://prowl.world/service/netlifys-api-documentation">
<img src="https://prowl.world/badge/netlifys-api-documentation.svg" height="56" alt="Agent-readiness on Prowl">
</a>
See operational metrics, LLM evaluations, agent readiness, and more.
Open in Dashboard