Documentation · v1

API getsebi.xyz

Everything the panel can do can be done from here too: availability checks, registration, renewal, DNS management, bulk operations and webhook notifications. Built for resellers and automated integrations.

Base URLhttps://api.getsebi.xyz/api/v1

First steps

Create a key in the API panel, then check it:

curl https://api.getsebi.xyz/api/v1/ping \
  -H "Authorization: Bearer gsk_live_..."

A good response shows the account and the key’s permissions:

{
  "ok": true,
  "account": "[email protected]",
  "scopes": ["domains:read", "domains:write"]
}

From zero to your first registered name is three requests: check availability, make sure you have balance, register.

Authentication

Every request carries the key in the Authorization header. The key is shown once, at creation — we keep only a hash, so we cannot recover it for you. If you lose it, revoke it and make another; revocation takes effect immediately.

Authorization: Bearer gsk_live_a1b2c3...

Test keys and live keys. A gsk_test_ key goes through exactly the same validation as a gsk_live_ one, but writes nothing and never touches your balance: routes that create or cost money return what would have happened, with "test": true. You prove out your integration without buying real names. Keys are issued in test mode by default — for a live one you ask explicitly with mode: "live".

Each key carries only the permissions you give it. Grant the minimum: an integration that only reads the portfolio has no business holding domains:write.

domains:readRead the portfolio and availability
domains:writeRegister, renew and delete names
dns:readRead DNS records
dns:writeCreate and delete DNS records
account:readRead the balance, the account and the webhooks

Errors and limits

Every response has the same shape, with success as the first thing to check. On success, all the content sits under data:

{
  "success": true,
  "data": { "name": "my-client.getsebi.xyz", "status": "active" },
  "request_id": "req_a1b2c3d4e5"
}

On failure, error is the human message and code is what you test in code — messages get reworded, codes do not:

{
  "success": false,
  "error": "Insufficient balance: 900 cents needed",
  "code": "insufficient_balance",
  "request_id": "req_a1b2c3d4e5"
}

request_id is on both. Quote it when you ask for help.

Every response carries the rate-limit headers. By default 100 requests per minute and 5000 per hour per key:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1788281336

When you exceed either one, you get 429 with Retry-After in seconds. Honour it — do not retry immediately.

Idempotency

Every operation that costs money requires a unique Idempotency-Key header. If your request times out and you retry it with the same key, you get the original response instead of being charged twice.

curl -X POST https://api.getsebi.xyz/api/v1/domains \
  -H "Authorization: Bearer gsk_live_..." \
  -H "Idempotency-Key: comanda-4471" \
  -H "Content-Type: application/json" \
  -d '{"name":"clientul-meu","years":1,"target":"93.184.216.34"}'

A replay returns the Idempotent-Replay: true header. If you use the same key with a different body, you get 409 — that is a guard against a bug in your code, not an obstacle.

Domain names

GET/v1/availability?name=exempludomains:read
Says whether a name is free. Possible reasons: taken, reserved, invalid_name.

Internationalized names. You may send a name in any script — café, привет, مرحبا. It is transcribed to its ASCII form before anything else happens, so café and xn--caf-dma are the same name everywhere: availability, registration, renewal and the URL path /v1/domains/<label>. Responses always carry the ASCII form in name — that is the key you store and send back — plus unicode_name for display. One name must use a single script: пpивет, which mixes a Latin p into Cyrillic letters, is rejected.

POST/v1/domains/checkdomains:read
Checks up to 100 names in one request. The top-level price is a reference for a standard-tier name; each result carries its own tier and price — a short or dictionary-common name costs more, with your reseller discount still applied on top.
curl -X POST https://api.getsebi.xyz/api/v1/domains/check \
  -H "Authorization: Bearer gsk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"names":["firma1","car"],"plan":"2years"}'

{
  "success": true,
  "data": {
    "plan": "2years", "price_cents": 1050,
    "list_price_cents": 1500, "discount_percent": 30,
    "results": [
      { "name": "firma1", "available": true, "tier": "standard",
        "price": 1050, "list_price_cents": 1500 },
      { "name": "car", "available": true, "tier": "silver",
        "price": 21000, "list_price_cents": 30000 }
    ]
  }
}
GET/v1/domainsdomains:read
Your portfolio. Two kinds of pagination, because they do different jobs: ?page=1&limit=50 gives you the total and the page count; ?cursor= stays stable if names are inserted while you walk the list (an OFFSET would skip rows). limit is capped at 200.
{
  "success": true,
  "data": {
    "domains": [{ "name": "clientul-meu.getsebi.xyz", "status": "active",
                  "expires_at": "2027-09-01T10:00:00Z", "auto_renew": false }],
    "page": 1, "limit": 50, "total": 137, "pages": 3, "has_more": true
  }
}
GET/v1/domains/:labeldomains:read
A single name from your account.
POST/v1/domains/registerdomains:write
Registers a name and debits your balance, with your discount applied. Fields: name, plan (1year, 2years, 4years; years: 1|2|4 also works), an optional target (IP or hostname — it creates the A or CNAME record automatically) and an optional contact. POST /v1/domains does the same thing. Requires Idempotency-Key.

contact (name, email, phone, company, address, city, country, postal_code) is informational, for your own records: the registrant of record stays your account, and none of it is published in WHOIS.

The response carries tier and price_cents for what was actually charged — a short or dictionary-common name debits more than the plan's base price. Check /v1/domains/check beforehand if the price needs to be shown to your own customer before you charge them.

POST/v1/domains/:label/renewdomains:write
Extends the term, always at the plan's base price — a name bought at a premium tier renews like any other name; the tier only affects the price at registration. Requires Idempotency-Key.
DELETE/v1/domains/:labeldomains:write
Releases the name immediately. No refund — the response says so explicitly with "refunded": false.

DNS records

Accepted types: A, AAAA, CNAME, MX, TXT, NS. Up to 25 records per name, TTL between 60 and 86400. The same rules as in the panel: a CNAME cannot coexist with other records of the same name, and NS delegation on the root excludes everything else.

GET/v1/domains/:label/dnsdns:read
Every record, plus whether the zone is delegated and to which nameservers.
POST/v1/domains/:label/dnsdns:write
Adds a record.
curl -X POST https://api.getsebi.xyz/api/v1/domains/clientul-meu/dns \
  -H "Authorization: Bearer gsk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"type":"A","name":"@","content":"93.184.216.34","ttl":3600}'
DELETE/v1/dns/:iddns:write
Deletes a record, from our database and from public DNS.

Bulk operations

Up to 500 names per request. The job runs in the background and you poll it by id — 500 registrations do not fit in an HTTP response that will not time out.

curl -X POST https://api.getsebi.xyz/api/v1/bulk/domains \
  -H "Authorization: Bearer gsk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"items":[
        {"name":"client-a","years":1},
        {"name":"client-b","years":2,"target":"93.184.216.34"}
      ]}'

You get 202 with the job id. Then:

GET /v1/bulk/jobs/:id

{
  "status": "completed", "total": 2, "succeeded": 1, "failed": 1,
  "results": [
    { "name": "client-a", "status": "ok", "expires_at": "2027-09-01T..." },
    { "name": "client-b", "status": "error",
      "error": { "code": "taken", "message": "The name client-b is not available" } }
  ]
}

Each item succeeds or fails independently — one taken name does not stop the rest of the batch. /v1/bulk/renew works the same way.

Webhooks

Instead of polling us, we send you the events. The endpoint must be HTTPS. Evenimentele disponibile: domain.registered, domain.renewed, domain.deleted, domain.expiring, domain.expired, domain.suspended, domain.unsuspended, dns.updated, bulk.completed.

Verify the signature. Every delivery carries antetul X-Getsebi-Signature: t=<timestamp>,v1=<hmac>, where the HMAC-SHA256 is computed over timestamp + "." + the raw body, with the endpoint secret. Without verification, anyone can send you fake events.

const crypto = require("crypto");

function verifica(rawBody, header, secret) {
  const [t, v1] = header.split(",").map(p => p.split("=")[1]);
  // Respinge livrarile vechi: protectie impotriva reluarii.
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const asteptat = crypto.createHmac("sha256", secret)
    .update(t + "." + rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(asteptat));
}

Answer with any 2xx code. If you do not, we retry 6 times with growing gaps: 30 seconds, 2 minutes, 10 minutes, an hour, 6 hours, 24 hours. Deliveries and the codes received are visible at GET /v1/webhooks/:id/deliveries.

Balance and pricing

The API runs on a prepaid balance: registrations and renewals debit it. When it is not enough, you get 402 with the code insufficient_balance and nothing else happens.

GET/v1/accountaccount:read
Your current balance and the name count in each state.
GET/v1/pricing
Current pricing. No authentication required.

Balance top-ups are still manual for now, through our team. Write to us and we issue a proforma. Automatic card top-up arrives together with invoicing.

We version the API in its URL. A change that breaks existing integrations means a new version, not a silent change to v1.

WHOIS · Report abuse · My keys