procurement.txt

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

ParameterRequiredDescription
domainYesThe domain to check (e.g. example.com). Protocol and path are stripped automatically.
formatNoResponse 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

FieldTypeDescription
domainstringThe sanitized domain that was checked
urlstringThe URL the file was fetched from (primary or .well-known path)
validbooleantrue if the file passes all required validation rules
fieldsobjectParsed field values. Repeatable fields (contact, escalation, commerce-protocol) are arrays; all others are strings.
warningsarrayNon-blocking issues (see Warning codes)
errorsarrayValidation failures (see Error codes)
agentReadinessstringHIGH+, HIGH, MEDIUM, LOW, or NONE (see Agent readiness)
fetchedAtstringISO 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.

ValueMeaning
HIGH+HIGH + at least two of: Service-Region, Payment-Terms, Auth, Min-Order, Interaction-Model
HIGHFile is valid and includes (Ordering + Pricing) or a Commerce-Protocol field
MEDIUMFile is valid and includes Ordering or Pricing (but not both)
LOWFile is valid with only Version and Contact
NONENo 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.

CodeDescription
WRONG_CONTENT_TYPEThe file was not served with Content-Type: text/plain
EXPIRES_PASTThe Expires date is in the past
EXPIRES_SOONThe 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:

CodeHTTP statusDescription
INVALID_INPUT400The domain parameter is missing, malformed, or a private IP address
NOT_FOUND404No procurement.txt found at /procurement.txt or /.well-known/procurement.txt
FETCH_FAILED502The file was found but returned a non-200 HTTP status
TIMEOUT502The domain did not respond within 5 seconds
REDIRECT_LOOP502The server returned too many redirects

Errors inside a 200 response (parse and validation errors) are listed in the errors array:

CodeDescription
MISSING_VERSIONThe Version field is absent
MISSING_CONTACTThe Contact field is absent
INVALID_VERSIONThe Version value is not a positive integer
INVALID_CONTACTA 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.