Integrations
Fail the build, not the customer
A malformed sitemap is a deploy problem that behaves like an SEO problem three weeks later. These are the ways to move that discovery back to the pull request.
GitHub code scanning
The API speaks SARIF 2.1.0, which is the format GitHub code scanning ingests directly. That single fact is what makes this worth wiring up: the output is not a log line, it is an annotation on the exact line of the exact file, on the pull request that introduced it.
name: Validate XML
on:
pull_request:
paths:
- "public/sitemap.xml"
- "**/*.xml"
permissions:
contents: read
security-events: write # required to upload SARIF
jobs:
xml:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate sitemap
run: |
curl -sS --fail-with-body \
-X POST "https://xmldir.com/api/v1/validate?format=sarif" \
-H "Authorization: Bearer ${{ secrets.XMLDIR_API_KEY }}" \
-H "Content-Type: application/xml" \
--data-binary @public/sitemap.xml \
> xmldir.sarif
# Runs even when validation failed, so the annotations still appear.
- name: Upload results
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: xmldir.sarif
category: xmldir
Two things that catch people out
security-events: write is required to upload SARIF, and the default token does not have it. And the upload step needs if: always() — without it, a failed validation skips the upload and you get a red build with no annotations explaining why.
A clean run is not an empty file
Valid documents return a well-formed SARIF log with an empty results array. Code scanning needs that to clear previously reported findings — an empty file would leave stale annotations on the pull request forever.
What gets reported
4 rules, each with a stable id so a finding can be suppressed or tracked over time.
xml/well-formed
WellFormed
Document must be well-formed XML
xml/schema-valid
SchemaValid
Document must satisfy the supplied XSD
xml/namespace-undeclared
NamespaceUndeclared
Namespace prefixes must be declared before use
xml/namespace-unused
NamespaceUnused
Declared namespaces should be used
Full request and response shapes are in the API reference
Webhooks for monitored sources
CI catches the XML you generate. Monitoring catches the XML you do not control — a partner feed, a supplier's endpoint. Register a URL, enable monitoring, and a POST arrives when its structure changes, with the paths that moved.
The payload carries the change, not the document. Routing a partner's XML through a chat integration is how payloads end up somewhere they should not be.
{
"source": "https://example.com/sitemap.xml",
"detectedKind": "sitemap",
"checkedAt": "2026-08-18T09:14:22Z",
"changed": true,
"changeCount": 3,
"added": ["/urlset/url/video:video"],
"removed": [],
"changedPaths": ["/urlset/url/lastmod"]
}Anything that speaks HTTP
Any CI
GitLab, Jenkins, CircleCI, Buildkite — it is one curl and a non-zero exit code. SARIF is the bonus, not the requirement.
Alerting
Point a monitoring webhook at whatever already pages you. The payload is small and stable enough to route on.
Pre-commit
The same endpoint works from a git hook, which catches a malformed document before it is ever pushed.
Get started
Get an API key and put this in your pipeline.
Keys are free, issued per account, and stored only as a hash — so a key is shown once and cannot be recovered by anyone, including us.