Docs
Claim and verify a domain
Three calls: create a claim, publish one DNS TXT record, and verify it. Every example below is the real shape of the /api/v1 response for the step it sits next to.
Every route
| Action | Method | Route |
|---|---|---|
| createDomainClaim | POST | /api/v1/claims |
| getDomainClaim | GET | /api/v1/claims/:id |
| listDomainClaims | GET | /api/v1/claims |
| checkDnsRecord | POST | /api/v1/claims/:id/check |
| verifyAndClaimDomain | POST | /api/v1/claims/:id/verify |
| releaseDomainClaim | DELETE | /api/v1/claims/:id |
Every request needs a signed-in session, which is checked before anything else, including the request body. Every response, success or failure, has one shape: { success: true, data } or { success: false, error }. The discriminant is always success, never ok.
For the full request and response shape of every route, see the API reference. It is a browsable OpenAPI spec, generated from the same definitions these routes run on, so it cannot drift from what the API actually does.
1. Create a claim
Call POST /api/v1/claims with the domain you want to prove you own. One call creates the claim, with status pending_dns, and returns the exact DNS record to publish. There is no second call to fetch the instructions.
A claim is good for 7 days from creation. If it isn't verified by then, it expires and a fresh POST /api/v1/claims starts a new one with a new token.
2. Add the TXT record
The response from step 1 includes a record object with three fields:
- Name
- _vouch-challenge.example.com
- Type
- TXT
- Value
- vouch-domain-verify=M6KqqqYx3NNo0v4qkZz2Pmw8XrhvS4BQ5y6k5AKa6_E
Important: The most common mistake is a doubled suffix
Most DNS providers already append your domain to whatever you type into a record's Name/Host field. Paste the full name we gave you — _vouch-challenge.example.com — into that field, and the record you actually publish ends up at _vouch-challenge.example.com.example.com, not where we're looking. Enter only the label before your domain (_vouch-challenge, with the domain left for the provider to add) and you're fine.
When that happens you get DNS_RECORD_WRONG_HOSTNAME rather than a plain "not found": your token was there, just one level too deep. The error's evidence field carries both hostnames, the one queried and the one where the token turned up, so you can show the difference directly.
Check the record
POST /api/v1/claims/:id/check runs a live DNS lookup and tells you what it found, without touching the claim. Use it to confirm a record is in place, or to show someone why theirs isn't working yet. The claim stays pending_dns even when the record matches. Only /verify advances it.
3. Verify
POST /api/v1/claims/:id/verify runs the same lookup as /check and, on a match, advances the claim to verified and stamps verifiedAt.
It is a POST rather than a GET because it changes something. Browsers, proxies and link prefetchers all treat GET as safe to issue on their own, and none of them should be able to start a verification you didn't ask for.
Still propagating
DNS propagation isn't instant, and a record you just saved may take anywhere from seconds to an hour to become visible. Calling /verify before then returns DNS_NO_TXT_FOUND, which means nothing is wrong yet. Keep calling /verify on a widening interval until it succeeds or the claim expires, rather than treating the first miss as a failure.
Read success, not the status code
/check and /verify return HTTP 200 when the lookup ran fine but the record isn't published yet, has the wrong value, or is sitting at a doubled hostname. The request was handled correctly; the answer just happens to be no.
Six codes arrive this way: DNS_NO_TXT_FOUND, DNS_TOKEN_MISMATCH, DNS_RECORD_WRONG_HOSTNAME, DNS_NXDOMAIN, DNS_LOOKUP_TIMEOUT, and DNS_LOOKUP_FAILED. The doubled-suffix response above is one of them: 200 OK, with "success": false in the body.
Read success in the response body, not the status code. The status tells you whether the request was handled. Only success tells you whether the thing you asked for happened.
A 4xx means something different: the request itself cannot succeed, whatever DNS says. Creating a claim for a domain another account has already verified returns DOMAIN_ALREADY_CLAIMED with a genuine 409 Conflict, because no DNS record could make that request valid.
After verifying
GET /api/v1/claims/:id is a plain read. It performs no DNS lookup and changes nothing, so you can call it as often as you like. GET /api/v1/claims lists every claim your account can see, and DELETE /api/v1/claims/:id releases one you no longer want.
A verified claim stays verified. Vouch does not re-check the record afterwards, so removing it will not revoke the claim, and releasing the domain is the only way to give it up.
Every error code
Every error carries a code, a plain-language message and remediation, an isRetriable flag, and a fault. The last two answer different questions. isRetriable asks whether the same call could succeed later; fault asks who has to do something about it. DNS_TOKEN_MISMATCH is retriable, but only once the record is corrected. DNS_LOOKUP_TIMEOUT is retriable and needs nobody: it clears on its own.
▸ Show all 18 error codes
| Code | What it means | Retriable | Fault |
|---|---|---|---|
| VALIDATION_FAILED | The request body failed schema validation. | No | User |
| DOMAIN_INVALID_FORMAT | The domain string isn't a valid hostname. | No | User |
| DOMAIN_IS_PUBLIC_SUFFIX | The domain is a shared suffix (e.g. co.uk) nobody can claim alone. | No | User |
| DOMAIN_ALREADY_CLAIMED | Another account already verified this domain. | No | User |
| CLAIM_NOT_FOUND | The claim id doesn't resolve to a row this org can see. | No | User |
| CLAIM_NOT_PENDING | The claim's current status doesn't accept this transition. | No | User |
| CLAIM_ALREADY_VERIFYING | A verification attempt for this claim is already in flight. | Yes | External |
| CLAIM_EXPIRED | The claim's 7-day window closed before it was verified. | No | User |
| DNS_NO_TXT_FOUND | No TXT record was found at the expected name yet. | Yes | External |
| DNS_TOKEN_MISMATCH | A TXT record was found at the right name, but its value doesn't match. | Yes | User |
| DNS_RECORD_WRONG_HOSTNAME | The token was found, but at a doubled-suffix hostname instead of the one queried. | Yes | User |
| DNS_NXDOMAIN | The domain doesn't resolve at all. | No | User |
| DNS_LOOKUP_TIMEOUT | The DNS resolver didn't respond in time. | Yes | External |
| DNS_LOOKUP_FAILED | The DNS resolver returned an error. | Yes | External |
| RATE_LIMITED | Too many requests — see the Retry-After header. | Yes | External |
| UNAUTHENTICATED | No session was presented at all. | No | User |
| UNAUTHORIZED | A session was presented, but it isn't this claim's org. | No | User |
| INTERNAL_ERROR | An unhandled exception on our side, not a decision anyone made. | Yes | System |