Verifying ownership
A website must prove domain control before its node is trusted. Verification is a challenge-and-check flow: the server issues a token, you place it on the domain, and the server re-reads it to advance a state machine. The method you use sets the node's trust tier.
Why verification gates everything
Verification is what makes a Knowledge Node a primary source rather than a claim. An AI consumer weights a node by how its domain ownership was proven. Verification gates ingestion and publishing: content should only be pushed when the website is verified (or in grace), and a node should never be made public on an unverified domain. The trust tier derived from the method is published in trust.json and mirrored into manifest.json.trust_tier.
The verification methods
The method drives the trust tier (highest to lowest):
| Method | Trust tier | How you prove ownership |
|---|---|---|
dns_txt | highest | Add a TXT record containing the challenge token to the domain's DNS. |
plugin_signed | high | A signed plugin (for example the WordPress connector) attests ownership. |
well_known_file | medium-high | Serve the token at a well-known path on the site. |
meta_tag | medium-low | Add a <meta> tag with the token to the site's HTML. |
manual | lowest | A reviewed, manually-approved verification. |
A higher-tier method produces a node an AI consumer can trust more. dns_txt is the strongest because it proves control of the domain itself, not just of one page.
The endpoints
apps/api/src/modules/verification/router.ts. The challenge fetch is SSRF-guarded.
| Method | Path | Min role | Status |
|---|---|---|---|
| GET | /v1/websites/:id/verification | viewer | 200 (current state) |
| POST | /v1/websites/:id/verification/challenge | editor | 201 (issues a token) |
| POST | /v1/websites/:id/verification/check | editor | 200 (re-reads, advances state) |
Errors: validation.failed, website.not_found, auth.forbidden, verification.method_unsupported.
The flow
1. Request a challenge
curl -sS -X POST https://api.bainquet.online/v1/websites/$WEBSITE_ID/verification/challenge \
-H "Authorization: Bearer $ACCESS_JWT" \
-H 'Content-Type: application/json' \
-d '{ "method": "dns_txt" }'The response carries the token to place. The method determines where it goes.
2. Place the token
dns_txt: add a TXT record to the domain containing the challenge token.well_known_file: serve the token at the well-known path returned by the challenge.meta_tag: add the returned<meta>tag to the site's HTML<head>.plugin: configure the signed connector plugin, which attests ownership.
3. Check
curl -sS -X POST https://api.bainquet.online/v1/websites/$WEBSITE_ID/verification/check \
-H "Authorization: Bearer $ACCESS_JWT" \
-H 'Content-Type: application/json' \
-d '{}'The server re-reads ownership and advances the state machine. On success the state becomes verified.
Verification states
| State | Meaning |
|---|---|
pending | A challenge is issued but ownership is not yet confirmed. |
verified | Ownership is confirmed; the node is trusted and can publish. |
grace | Previously verified, but a re-check is overdue or failing; still allowed to operate temporarily. Ingestion in this state carries a meta.warning="verification_grace". |
failed | A check failed; ownership could not be confirmed. |
revoked | Verification was withdrawn. |
challenge check (ok) re-check overdue/failing
pending ---------> verified ------------------------> grace
^ | ^ |
| check (fail) | | re-check (ok) | re-check (fail)
+---- failed <-----+ +------------------------------+
revoked (withdrawn)Periodic re-verification
A periodic re-verification job (verification.check) and verification.lost / verification.restored events are specified, but the worker handler is a stub today and no scheduler enqueues it on a timer. Re-checks are triggered through the check endpoint. See Architecture.
How verification feeds ingestion and publish
- Ingestion should run only when the website is
verifiedorgrace. Ingrace, responses carry ameta.warning="verification_grace"hint. - Publish writes a trust posture into
trust.jsonfrom the verification method and state. (The current build does not yet hard-gate publish with a409 website.not_verifiedpre-check; that gate is deferred.) - The trust tier is mirrored into
manifest.json.trust_tierso a consumer reads it from the node entry point.
Related
- Core concepts: the trust-tier ranking.
- Connector tokens: the next step after verifying.
- Node files: where the trust posture is published.