OpenSRS / Tucows is the registrar behind thousands of white-label domain shops. It’s the “serious” route if we want IBrandBiz to feel like a legit SaaS, not a hacked-on redirect.

Why OpenSRS is the right call

Battle-tested: They’ve been powering resellers for decades.

API: Modern XML/JSON-RPC interface, full domain lifecycle (search, register, renew, transfer, manage contacts, WHOIS privacy).

White-label: End users never see Tucows; it’s all IBrandBiz branding.

Billing: You set the retail price, they bill you wholesale.

Scalable: Built for exactly what we’re doing — reselling domains inside another product.

Integration Flow for IBrandBiz

Search

/api/domains/search → calls OpenSRS API: lookup_domain.

Returns: domain, availability, retail price (yours), type (standard/premium).

Checkout (Stripe)

User selects a domain.

/api/domains/order → creates DomainOrder (status: pending), Stripe Checkout session.

Stripe webhook

On checkout.session.completed, queue job → OpenSRS API: sw_register with registrant contact + nameservers.

Update order → active or failed.

Manage domain

GET /api/domains/:id → fetch status, expiry, DNS, WHOIS privacy toggle.

Actions: renew, transfer out, change nameservers.

What we need from OpenSRS

Reseller account (funded balance).

API credentials (username + private key).

Test environment (they provide a sandbox).

Compliance: ICANN email confirmations, WHOIS contact requirements.

Proposed Adapter Interface
// server/domains/providers/opensrs.ts
import { Registrar, SearchHit, RegisterInput } from "./types";
import fetch from "node-fetch";

const BASE = process.env.OPENSRS_BASE || "https://horizon.opensrs.net:55443";
const USER = process.env.OPENSRS_USER!;
const KEY = process.env.OPENSRS_KEY!;

async function callOpenSRS(action: string, object: string, attributes: Record<string,any>) {
  const body = {
    protocol: "XCP",
    action,
    object,
    attributes
  };
  const r = await fetch(BASE, {
    method: "POST",
    headers: {
      "Content-Type": "text/json",
      "X-Username": USER,
      "X-Signature": KEY
    },
    body: JSON.stringify(body)
  });
  return r.json();
}

export const opensrs: Registrar = {
  async search(query) {
    const res = await callOpenSRS("LOOKUP", "DOMAIN", { domain: query, search_type: "domain" });
    return [{
      domain: query,
      available: res.is_available,
      priceCents: res.price ? Math.round(parseFloat(res.price) * 100) : undefined
    }];
  },

  async register(input: RegisterInput) {
    const { domain, years, contact, privacy, nameservers } = input;
    const res = await callOpenSRS("SW_REGISTER", "DOMAIN", {
      domain,
      period: years,
      dns_template: nameservers?.length ? nameservers.join(",") : undefined,
      contact_set: {
        owner: contact,
        admin: contact,
        billing: contact,
        tech: contact
      },
      private: privacy ? 1 : 0
    });
    return {
      success: res.is_success,
      registrationId: res.registration_id,
      message: res.response_text
    };
  }
};

Next Steps

Phase A: Implement mock provider (so Replit can wire Stripe + flow).

Phase B: Swap to OpenSRS adapter with test creds.

Phase C: Fund reseller account, flip to live.

Phase D: Add management pages (renewals, DNS, transfers).