← back to Domain Sniper
register: fix Namecheap false-positive when API ok but registration failed
667159d4a7a5e365c6c2d748cdc2df90e2f0a92b · 2026-05-12 18:46:31 -0700 · steve
Eyeball audit of the Namecheap response parser caught a real bug:
the success check only matched the open tag '<DomainCreateResult'
regardless of its Registered= attribute. Namecheap API uses a two-
layer status: outer Status="OK" means 'API call accepted', inner
DomainCreateResult Registered="true" means 'domain actually
registered'. A request can succeed at layer 1 and fail at layer 2
(e.g. domain unavailable, registrant invalid, insufficient funds)
without raising an <Error> — the prior code would report success
on such cases.
New logic requires BOTH:
apiOk = Status="OK"
regOk = DomainCreateResult ... Registered="true"
plus a clearer detail message that distinguishes 'api failed'
from 'api ok but registration declined'.
watch-outbound.js audit: clean (loopback-only, no hardcoded creds,
35-pattern INTEL allowlist comprehensive). NameSilo + GoDaddy
parsers also reviewed — NameSilo correct, GoDaddy intentionally
NOT_WIRED to avoid silent billing.
Files touched
Diff
commit 667159d4a7a5e365c6c2d748cdc2df90e2f0a92b
Author: steve <steve@designerwallcoverings.com>
Date: Tue May 12 18:46:31 2026 -0700
register: fix Namecheap false-positive when API ok but registration failed
Eyeball audit of the Namecheap response parser caught a real bug:
the success check only matched the open tag '<DomainCreateResult'
regardless of its Registered= attribute. Namecheap API uses a two-
layer status: outer Status="OK" means 'API call accepted', inner
DomainCreateResult Registered="true" means 'domain actually
registered'. A request can succeed at layer 1 and fail at layer 2
(e.g. domain unavailable, registrant invalid, insufficient funds)
without raising an <Error> — the prior code would report success
on such cases.
New logic requires BOTH:
apiOk = Status="OK"
regOk = DomainCreateResult ... Registered="true"
plus a clearer detail message that distinguishes 'api failed'
from 'api ok but registration declined'.
watch-outbound.js audit: clean (loopback-only, no hardcoded creds,
35-pattern INTEL allowlist comprehensive). NameSilo + GoDaddy
parsers also reviewed — NameSilo correct, GoDaddy intentionally
NOT_WIRED to avoid silent billing.
---
register.js | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/register.js b/register.js
index 75218eb..24de98e 100644
--- a/register.js
+++ b/register.js
@@ -84,9 +84,21 @@ async function registerNamecheap(domain) {
{ hostname: 'api.namecheap.com', path: '/xml.response?' + params.toString(), method: 'GET' },
null,
);
- const success = /Status="OK"/.test(r.body) && /<DomainCreateResult/.test(r.body);
+ // Two-layer success check: the API call must have Status="OK" AND the
+ // inner <DomainCreateResult Registered="true"...> must confirm the actual
+ // registration. Status="OK" alone only means "API request was valid" — it
+ // does NOT mean the domain was registered (the create result can still
+ // come back Registered="false" with the call still nominally OK).
+ const apiOk = /Status="OK"/.test(r.body);
+ const regOk = /<DomainCreateResult\b[^>]*\bRegistered="true"/i.test(r.body);
+ const success = apiOk && regOk;
const errMatch = r.body.match(/<Error[^>]*>([^<]+)<\/Error>/);
- return { success, code: success ? 'OK' : 'ERROR', detail: errMatch ? errMatch[1] : (success ? 'registered' : 'unknown'), http: r.status };
+ let detail;
+ if (success) detail = 'registered';
+ else if (!apiOk && errMatch) detail = errMatch[1];
+ else if (apiOk && !regOk) detail = 'api ok but DomainCreateResult.Registered != true';
+ else detail = 'unknown';
+ return { success, code: success ? 'OK' : 'ERROR', detail, http: r.status };
}
async function registerGodaddy(domain) {
← 9f69a10 check: annotate owned domains in DoH-check output (non-block
·
back to Domain Sniper
·
watch-outbound: extend INTEL allowlist with RIRs, CZDS, 2026 0d22891 →