Domains and association files
Hosted subdomains, custom domains, and the hourly check that tells you a link is broken before your users do.
A link needs a domain, and the operating systems will only open your app from that domain if a file at a well-known path says they may. Vouch hosts the domain, generates the file and keeps checking it.
Adding a domain
A hosted subdomain works immediately, with no DNS to configure:
curl -X POST https://api.vouch.dev/v1/apps/app_123/domains \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{"host":"roam.vouch.dev"}'A custom domain needs you to prove you own it. The response carries a CNAME target and a verification token; publish either, then verify:
curl -X POST https://api.vouch.dev/v1/domains/dom_123/verify \
-H "Authorization: Bearer sk_live_…"| Proof | Record |
|---|---|
| CNAME | Point the host at the cname_target in the response. |
| TXT | Publish the verification_token at _vouch.yourdomain.com. |
If verification fails, the error says what DNS actually returned rather than just refusing.
The association files
Vouch generates and serves both files for every verified domain, from your registered identifiers:
| File | Platform | Built from |
|---|---|---|
/.well-known/apple-app-site-association | iOS | Your Apple Team ID and bundle identifier |
/.well-known/assetlinks.json | Android | Your package name and every SHA-256 signing fingerprint |
Register the Play App Signing fingerprint, not just your upload key. Google re-signs production builds with its own key, so a file listing only your upload fingerprint verifies in testing and fails for real users. The dashboard warns until it is added.
Path rules
By default every path on the domain opens the app. Path rules narrow that, and they go into the generated iOS file as well as being applied by the resolver.
curl -X PUT https://api.vouch.dev/v1/apps/app_123/path-rules \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{"rules":[
{"platform":"both","pattern":"/posts/*","kind":"allow"},
{"platform":"both","pattern":"/admin/*","kind":"exclude"}
]}'Rules are ordered and the first match decides. Check them against real URLs before you save:
curl -X POST https://api.vouch.dev/v1/apps/app_123/path-rules/preview \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{"platform":"ios","urls":["https://roam.vouch.dev/posts/9","https://roam.vouch.dev/admin/x"]}'The hourly check
Every verified domain is fetched at least hourly, the way Apple's CDN and Android's verifier fetch it: no redirects followed, content type checked, body compared against what we generated. Vouch also asks Apple's CDN what copy it is holding, because that is the copy that actually decides whether your links work on iOS.
A failure opens an alert and clears it when the next check passes.
curl https://api.vouch.dev/v1/domains/dom_123/checks \
-H "Authorization: Bearer sk_live_…"What each problem means
| Code | Meaning | Usual fix |
|---|---|---|
redirect | The file redirects. Apple does not follow redirects. | Serve it directly at the well-known path. |
wrong_content_type | Not served as JSON. | Send application/json. |
invalid_json | The body is not valid JSON. | Usually a proxy or error page is being served instead. |
content_mismatch | The file differs from what Vouch generated. | Something else is serving it; remove the override. |
tls_error | The certificate did not validate for this hostname. | Issue a certificate covering the exact host. |
timeout | The host did not answer in time. | Check the origin. |
not_found | The path returns 404. | The domain is not routed to Vouch. |
unexpected_status | Some other HTTP status. | Read the status in the check. |
too_large | The file is over the size limit. | Trim the path rules. |
dns_error | The hostname does not resolve. | Check the DNS record. |
unreachable | The host refused the connection. | Check routing and firewalls. |
read_error | The connection dropped mid-body. | Usually an origin problem. |
apple_cdn_not_found | Apple's CDN has no copy yet. | Expected on a new domain; see below. |
apple_cdn_stale | Apple's copy differs from yours. | See below. |
apple_cdn_unreachable | Apple's CDN could not be reached. | Transient; the next check will retry. |
apple_cdn_error | Apple's CDN returned an error. | Transient. |
Each problem in the response carries a fix field with the specific remedy for your domain.
Apple's CDN
iOS does not usually fetch your file directly. It fetches Apple's cached copy, and Apple offers no API to force a refresh. That means a corrected file can take time to reach devices.
curl https://api.vouch.dev/v1/domains/dom_123/apple-cdn-guide \
-H "Authorization: Bearer sk_live_…"The guide returns the current steps for your domain, including the developer-mode entitlement that makes a device fetch your file directly while you are testing.