Skip to content

Domain.verify

Check your domain’s DNS and certificate, whether Google and Bing read its sitemap, and each key page’s index state with its fix.

Price
Free
Success rate
99.8% of 45,746 calls
Freshness
Read fresh each call
Emits
Domain.verified
Capability
Domains
POST https://api.sb/{your-domain}/domains/verify

Inputs

NameTypeDefaultMeaning
domainDomainRequiredYour Domain id. Also served at /domains/{domain}/verify, as the hub defines it.
pagesstring[]the Site’s key PagesPages to inspect, up to 2,000 a day per site, shared with every other tool on that property.

Outputs

FieldTypeWhat null means
domainDomainNever null: with its state after the checks.
dns{ ok: boolean; fix: string | null }Never null. fix is null when ok.
certificate{ ok: boolean; fix: string | null }Never null. fix is null when ok.
searchEngines{ venue: 'google-search' | 'bing'; verified: boolean; sitemap: { submitted: number; indexed: number; lastRead: string | null; errors: number } | null }[]Never null. sitemap: null means no sitemap was read yet.
pages{ url: string; state: IndexState; reason: string | null; lastCrawl: string | null; canonical: string | null; robots: 'allowed' | 'blocked' | null }[]Never null: one row per page inspected.
pages[].state'indexed' | 'discovered-not-indexed' | 'crawled-not-indexed' | 'duplicate' | 'not-seen' | 'excluded'Never null.
pages[].reasonstring | nullNull when indexed; otherwise the engine’s own wording.
pages[].lastCrawlstring | null, in ISO 8601Never crawled.
pages[].canonicalstring | nullThe engine has not chosen one yet.
lagDaysnumber, in daysNever null: how far behind the engine’s own report runs, about 2 days.
observedAtstring, in ISO 8601Never null.
method'reported' | 'sampled'Never null. Google reads reported; Bing has no reporting API, so its fields are read by a browser agent and read sampled.

Read the result

FieldValueWhat it meansWhat to do
pages[].statenot-seenThe engine has never found the page.Confirm it is in the sitemap, link it from 2 indexed pages, and earn one followed outside link. (the index-state playbook)
pages[].statediscovered-not-indexedFound, not crawled yet: low priority on a new domain.Link it from the home and pricing pages; request indexing for key pages only. (the index-state playbook)
pages[].statecrawled-not-indexedCrawled and judged not worth indexing yet.Merge thin pages and add a fact only you have. Do not request again until the page changed. (the index-state playbook)
pagesKey pages indexedUnder 80% by week 2, or under 100% by week 4, means discovery is the problem, not content.Fix discovery before you write another page. (our planning numbers)
pagesOver 30% crawled-not-indexed at week 6A quality problem across the site.Pause publishing and fix the thin pages first. (our planning number)

Effects

Action class

None: no approval rule names it, so it runs within its seat’s Permissions and Limits

Modes
  • try: Runs every check and returns the results; nothing is written onto the Domain.
  • send: Returns a pending Action at once; its Event carries the rows when the read finishes.
  • do: Waits for the read and returns the rows, billed per result.
Idempotency

The same Idempotency-Key with the same input replays the first answer at $0; with other input it returns 409.

Saved or shared

Writes each check onto the Domain; a failed check moves a live Domain to degraded, and a degraded canonical Domain opens an Incident.

Emits

Domain.verified with { domain, dns, certificate, searchEngines, pages }

Performed by

Reliability Engineer

Price

Free. Free: every check, read from your own Search Console.

Reliability

The first route succeeds 99.8% of 45,746 calls. If it fails, the call refuses with sources-busy and nothing is spent.

Freshness

Every call reads fresh. Readings about people are never shared across startups. The source runs 2 days behind.

Batch and pages

Up to 2,000 pages a day per site. It answers in one response.

Rate

The shared rate rules: 10 calls a second per key, and an array input counts as one call.

Refuses when

CheckErrorFixThen call
The call needs an account you have not connected, such as your Search Console property or your Meta ad accountaccount-not-connectedConnect the account with POST /{namespace}/integrations/connect, approve it at the connectUrl, then send the call again.Integration.connect
The account’s own daily or per-minute cap is used up, such as 2,000 page checks a day per Search Console propertyquota-reachedRetry after the reset time the response gives; nothing was sent or spent.Action.retry

Every data call can also meet the shared data-call refusals: filter-unsupported, input-missing, limit-exceeded, max-cost, rate-limited, sources-busy, venue-unsupported.

The account-not-connected payload
JSON
{
  "type": "https://startupbuilder.dev/errors/account-not-connected",
  "title": "Account not connected",
  "status": 409,
  "detail": "The call needs an account you have not connected, such as your Search Console property or your Meta ad account.",
  "fix": "Connect the account with Integration.connect, approve it at the connectUrl, then send the call again.",
  "next": {
    "verb": "Integration.connect",
    "input": {
      "system": "ads",
      "venue": "facebook",
      "scope": "startup",
      "grants": [
        "ads_management",
        "ads_read"
      ]
    }
  },
  "instance": "https://api.sb/leaseline.app/actions/action_1"
}

When it waits

Returns in one response; nothing waits.

Example

Text
Is leaseline.app verified on Google and Bing, and is the rent ledger
template page indexed yet? Spend nothing.

To retry, send the same Idempotency-Key: the retry returns the first answer for $0. A new key reads again.

Test values, and watching it

A sk_test_ key answers these the same way every time, at $0 (every test value).

Test valueAlways returnsWhat it is for
maxCost: 0.0001Refuses with max-costAny priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap.
rate-limited.testRefuses with rate-limitedAny call naming this hostname answers 429 with Retry-After, so your retry logic runs.
sources-busy.testRefuses with sources-busyAny call naming this hostname answers 503 as if every route were busy, and nothing is spent.

Watch it on a schedule: a Monitor runs this call and records an Event only when the reading changes.

TypeScript
await $.Monitor.create({
  verb: 'Domain.verify',
  input: { domain: 'domain_ut1ZlxY4Z1' },
  change: 'index-change',
  every: '1d',
})

Used by