Reveal a name, then hold it
Turn a masked listing into a registrable name, reserve it inside the directory, and handle every refusal the two calls can return.
Two write calls exist on this API. POST /api/v1/domains/{id}/reveal turns a masked domain into a real name. POST /api/v1/domains/{id}/hold reserves the listing inside Revised while you make up your mind. They run in that order — a hold is refused until the same account has revealed the same listing.
Reveal
curl -s -X POST https://getrevised.com/api/v1/domains/00aLaXEG/reveal \
-H "Authorization: Bearer $REVISED_KEY"It returns the listing in the same shape GET /api/v1/domains/{id} does, plus revealed_at. The name below is a fabricated illustration — regular names are never published, here or anywhere else.
{
"id": "00aLaXEG",
"status": "active",
"domain": "greenvalleyfarms.com",
"tier": "regular",
"name_disclosed": true,
"hold_state": "none",
"revealed_at": "2026-09-22T03:15:02.117Z",
"availability_checked_at": "2026-09-21T18:40:11.002Z"
}When it is free
Both of these still write a ledger entry, so the reveal is recorded either way — which matters, because that record is what a hold checks:
- The listing is on the
opentier. Its name is published on the Revised site anyway. - Your plan has no reveal ceiling.
It is idempotent
A repeat call returns the original revealed_at, costs nothing, and is the safe way to re-read a name you have already bought. You do not need to cache names defensively to avoid double-charging.
def reveal(session, listing_id):
response = session.post(
f"https://getrevised.com/api/v1/domains/{listing_id}/reveal", timeout=30
)
if response.status_code >= 400:
error = response.json()["error"]
raise RuntimeError(f"{response.status_code} {error.get('reveal_code')}: {error['message']}")
return response.json()Reveal refusals
Branch on error.reveal_code, not on the HTTP status — several codes share a status.
reveal_code | Status | What to do |
|---|---|---|
QUOTA_EXHAUSTED | 402 | The month’s allowance is gone. The error carries resets_at. Stop revealing until then, or upgrade. |
FEATURED_REQUIRES_PRO | 402 | A free plan cannot reveal a featured listing. Skip the row or upgrade. |
HELD_BY_OTHER | 403 | Another account holds it. The error carries expires_at — never who holds it. Retry after that, or move on. |
NOT_FOUND | 404 | The listing has left the directory. Drop it from your working set. |
REVEAL_FAILED | — | Transient. Retry once with backoff, then treat as a skip. |
SIGN_IN_REQUIRED | 401 | The key did not resolve to an account. |
A QUOTA_EXHAUSTED response is worth handling properly rather than retrying:
import requests
try:
row = reveal(session, listing_id)
except RuntimeError as exc:
if "QUOTA_EXHAUSTED" in str(exc):
me = session.get("https://getrevised.com/api/v1/me", timeout=30).json()
print("out of reveals until", me["reveals"]["resets_at"])
raiseHold
A hold takes the listing off the shelf for every other account for a plan-dependent window, and masks the name for them while it runs.
curl -s -X POST https://getrevised.com/api/v1/domains/00aLaXEG/hold \
-H "Authorization: Bearer $REVISED_KEY"{
"hold": {
"id": "hold_7f3a91c2",
"listing_id": "00aLaXEG",
"held_at": "2026-09-22T03:16:40.000Z",
"expires_at": "2026-09-24T03:16:40.000Z",
"can_extend": true,
"extend_hours": 48
},
"holds": { "plan": "pro", "active": 1, "limit": 5, "hold_hours": 48 }
}Taking a hold you already have is not a second hold — the existing one comes back unchanged.
The holds block reports this account’s quota: how many holds are running, the plan’s ceiling, and how long a new hold runs for. Those numbers are plan-dependent — read them from the response rather than assuming the ones above.
Holds are account-scoped, not key-scoped. Every key on the account sees, extends and can end the same holds. Separate keys for separate systems separate the rate-limit bookkeeping, not the holds.
Hold refusals
Branch on error.hold_code. Three of these are completely different next actions and they are easy to conflate:
hold_code | What happened | What to do |
|---|---|---|
REVEAL_REQUIRED | This account has not revealed this listing | Call reveal first, then retry the hold. |
HELD_BY_OTHER | Somebody else holds it | The error carries expires_at. The listing is free the moment their window closes. |
HOLD_COOLDOWN | Your own hold on this listing ended within the last 30 days | The error carries available_at. Another account’s ended hold never blocks you — only yours does. |
HOLD_CAP_REACHED | You are at the plan’s ceiling | The error carries limit. End a hold you no longer need. |
HOLDS_REQUIRE_PRO | The plan does not include holds | Upgrade, or work without them. |
ALREADY_EXTENDED | The one permitted extension has been taken | Nothing. Let it run out or release it. |
HOLD_NOT_FOUND, HOLD_OVER | The hold id is unknown, or has already ended | Re-read GET /api/v1/holds. |
NOT_FOUND | The listing has left the directory | Drop it. |
Extend, once
curl -s -X POST https://getrevised.com/api/v1/holds/hold_7f3a91c2/extend \
-H "Authorization: Bearer $REVISED_KEY"The window extends from where it was going to end, not from now, so extending early loses you nothing. A second attempt is refused with ALREADY_EXTENDED.
End a hold
DELETE /api/v1/holds/{id} takes an outcome, defaulting to released:
curl -s -X DELETE https://getrevised.com/api/v1/holds/hold_7f3a91c2 \
-H "Authorization: Bearer $REVISED_KEY" \
-H "Content-Type: application/json" \
-d '{ "outcome": "registered" }'{
"ended_at": "2026-09-22T09:02:11.000Z",
"outcome": "registered",
"registration": "taken",
"holds": { "plan": "pro", "active": 0, "limit": 5, "hold_hours": 48 }
}releasedgives the listing straight back to everyone else.registeredrecords that you registered the name yourself. That triggers an availability re-check and retires the listing if the name now resolves. The response’sregistrationfield reports what the re-check found:takenmeans the name now resolves;unknownmeans no answer, which is not the same as available.expiredis not accepted. That outcome belongs to the clock.
Either way the listing is available to other accounts immediately, and you cannot hold that same listing again for 30 days.
Review your holds
curl -s https://getrevised.com/api/v1/holds \
-H "Authorization: Bearer $REVISED_KEY" | jq{
"active": [
{
"id": "hold_7f3a91c2",
"listing_id": "00aLaXEG",
"domain": "greenvalleyfarms.com",
"held_at": "2026-09-22T03:16:40.000Z",
"expires_at": "2026-09-24T03:16:40.000Z",
"can_extend": true,
"extend_hours": 48
}
],
"ended": [
{
"id": "hold_4b18de07",
"listing_id": "X00w46xl",
"ended_at": "2026-09-14T22:05:00.000Z",
"outcome": "expired",
"expires_at": "2026-09-14T22:05:00.000Z",
"held_at": "2026-09-12T22:05:00.000Z",
"can_extend": false
}
],
"holds": { "plan": "pro", "active": 1, "limit": 5, "hold_hours": 48 }
}Active holds carry domain, because a hold requires a reveal of the same listing by the same account. Ended holds carry their outcome — expired, released or registered.
The full flow
Filter and rank
Page
GET /api/v1/domains. Free, and it never charges for the rows it matched. See Find domains.Reveal the shortlist, not the page
One reveal per listing you are seriously considering. Repeat calls are free, so you never need to cache the name to protect your quota.
Hold what you want to research
Refused with
REVEAL_REQUIREDuntil step 2 has run for that listing on this account.Confirm availability at a registrar
availability_checked_atis a stamp, not a live check, and a hold does not reserve the name outside Revised.End the hold with the truth
registeredif you took the name,releasedif you did not. The 30-day cooldown on your own re-hold starts either way.