Validation API
The procurement.txt validation API lets you programmatically check whether a domain publishes a valid procurement.txt file. It fetches the file, parses it, runs validation rules, and returns a structured result including field values, warnings, errors, and an agent-readiness score.
The API is free to use, requires no authentication, and supports CORS — you can call it directly from a browser.
Endpoint
GET https://procurementtxt.org/api/validate
Query parameters
| Parameter | Required | Description |
|---|---|---|
domain | Yes | The domain to check (e.g. example.com). Protocol and path are stripped automatically. |
format | No | Response format: json (default) or text |
Response — JSON
A successful response returns HTTP 200 with Content-Type: application/json.
{
"domain": "example.com",
"url": "https://example.com/procurement.txt",
"valid": true,
"fields": {
"version": "1",
"contact": ["mailto:sales@example.com", "https://example.com/contact"],
"pricing": "public",
"ordering": "api https://api.example.com/openapi.json",
"quote": "yes",
"invoice": "api https://api.example.com/openapi.json"
},
"warnings": [],
"errors": [],
"agentReadiness": "HIGH",
"fetchedAt": "2026-03-26T12:00:00.000Z"
}Response fields
| Field | Type | Description |
|---|---|---|
domain | string | The sanitized domain that was checked |
url | string | The URL the file was fetched from (primary or .well-known path) |
valid | boolean | true if the file passes all required validation rules |
fields | object | Parsed field values. Repeatable fields (contact, escalation, commerce-protocol) are arrays; all others are strings. |
warnings | array | Non-blocking issues (see Warning codes) |
errors | array | Validation failures (see Error codes) |
agentReadiness | string | HIGH+, HIGH, MEDIUM, LOW, or NONE (see Agent readiness) |
fetchedAt | string | ISO 8601 timestamp of when the file was fetched |
Response — plain text
Add ?format=text to get a human-readable plain-text response, useful for CLI scripts.
curl "https://procurementtxt.org/api/validate?domain=example.com&format=text"Domain: example.com
URL: https://example.com/procurement.txt
Valid: true
Agent Readiness: HIGH
Fields:
Version: 1
Contact: mailto:sales@example.com
Pricing: public
Warnings: none
Errors: none
Fetched: 2026-03-26T12:00:00.000Z
Agent readiness
The agentReadiness field summarises how well a procurement.txt file serves automated agents.
| Value | Meaning |
|---|---|
HIGH+ | HIGH + at least two of: Service-Region, Payment-Terms, Auth, Min-Order, Interaction-Model |
HIGH | File is valid and includes (Ordering + Pricing) or a Commerce-Protocol field |
MEDIUM | File is valid and includes Ordering or Pricing (but not both) |
LOW | File is valid with only Version and Contact |
NONE | No procurement.txt found, file could not be fetched, or file is invalid |
Warning codes
Warnings are non-blocking — the file is still usable, but something could be improved.
| Code | Description |
|---|---|
WRONG_CONTENT_TYPE | The file was not served with Content-Type: text/plain |
EXPIRES_PAST | The Expires date is in the past |
EXPIRES_SOON | The Expires date is within 30 days |
Error codes
Errors indicate a validation failure. A file with errors has valid: false.
HTTP-level errors (non-200 responses from this API) use a separate set of codes:
| Code | HTTP status | Description |
|---|---|---|
INVALID_INPUT | 400 | The domain parameter is missing, malformed, or a private IP address |
NOT_FOUND | 404 | No procurement.txt found at /procurement.txt or /.well-known/procurement.txt |
FETCH_FAILED | 502 | The file was found but returned a non-200 HTTP status |
TIMEOUT | 502 | The domain did not respond within 5 seconds |
REDIRECT_LOOP | 502 | The server returned too many redirects |
Errors inside a 200 response (parse and validation errors) are listed in the errors array:
| Code | Description |
|---|---|
MISSING_VERSION | The Version field is absent |
MISSING_CONTACT | The Contact field is absent |
INVALID_VERSION | The Version value is not a positive integer |
INVALID_CONTACT | A Contact value is not a valid mailto:, https:, or tel: URI |
CORS
The API includes Access-Control-Allow-Origin: * on all responses. You can call it from a browser without a proxy.
const res = await fetch('https://procurementtxt.org/api/validate?domain=example.com')
const data = await res.json()
console.log(data.agentReadiness) // "HIGH"Examples
curl — JSON
curl "https://procurementtxt.org/api/validate?domain=example.com"curl — plain text
curl "https://procurementtxt.org/api/validate?domain=example.com&format=text"JavaScript fetch
const res = await fetch('https://procurementtxt.org/api/validate?domain=example.com')
if (!res.ok) {
const err = await res.json()
console.error(err.error, err.message)
} else {
const data = await res.json()
console.log(data.valid, data.agentReadiness)
}Python
import httpx
r = httpx.get("https://procurementtxt.org/api/validate", params={"domain": "example.com"})
r.raise_for_status()
data = r.json()
print(data["valid"], data["agentReadiness"])Rate limits
There are currently no enforced rate limits. Please be considerate — validate one domain at a time rather than bulk-scanning. The API fetches live files from third-party domains on each request.