WAFRA ResellerLog in

Before you write any code

Base URL https://www.wafra.net/api/reseller/v1

Auth Authorization: Bearer <key>

Money QAR, sent as a JSON number. 45 means 45.00.

The build order

#StepCallsSpends money?
01Create a keyportal onlyno
02Read the accountGET /account /balance /ledgerno
03Keep the balanceportal onlyno
04Receive eventsPOST /webhooksno
05Name checkGET /domains/checkno
06Customers and contactsPOST /customers POST /contactsno
07Quote, then registerPOST /pricing/quote POST /domainsyes
08Renew, transfer, DNS/renew /transfer /dns/enableyes
09Server catalogueGET /servers/locations /plansno
10Quote, then createPOST /servers/quotes POST /serversyes
11Operate the machine/power /backups /mail /dnsno
12Resize and renewal/rescale /renew /cancelyes
13Publish the hostnameGET PUT /servers/hostnameno

Start

Prove the key, keep the balance in the portal, and listen for the result.

01Create a key

portal only

What it is. The credential for every call. It is created in the portal under API keys, not by an API call.

Key prefixSpendsUse for
wf_test_test balancebuilding and testing
wf_live_live balanceproduction

What it does. Give the key the scopes it needs: domains and servers. The secret is shown once.

How to implement

  1. Set the top bar to Current Mode: Test. The portal then shows the test balance, test keys, test names, test servers, and the test ledger.
  2. Add funds adds any amount to the test domain balance or the test server balance and takes no card.
  3. Build against wf_test_. The Sandbox page calls every published path with the test key and shows the panel those calls fill.
  4. When WAFRA approves the company, switch the same code to wf_live_.

02Read the account

GET /accountGET /account/balanceGET /account/ledger

What it is. These reads confirm the key and show the money.

CallReturns
GET /accountThe company and its status
GET /account/balanceTwo wallets. available_qar and held_qar are the domain balance. server_available_qar and server_held_qar are the server balance
GET /account/ledger?wallet=domainTop-ups, holds, captures, and releases on the domain wallet
GET /account/ledger?wallet=serverThe same list for the server wallet

Amounts are JSON numbers in QAR. 45 means 45.00 QAR.

How to implement

  1. Send Authorization: Bearer <key> to https://www.wafra.net/api/reseller/v1.
  2. Keep the key off the browser.
  3. If the status is not active, stop and wait for approval before a live purchase.

03Keep the balance

portal only

What it is. There is no API to add money. The company keeps each balance itself.

WalletPays forRead
DomainNamesavailable_qar
ServerMachinesserver_available_qar

A wf_test_ key reads and spends the test balances. A wf_live_ key reads and spends the live balances.

How to implement

  1. Load the live balance in the reseller portal, on Add funds, before you sell.
  2. Set Current Mode to Test to load any test amount instead.
  3. WAFRA can also credit the live balance from the desk. Your integration only reads the balance and spends what is already there.

04Receive events

POST /webhooks

What it is. Your HTTPS URL. WAFRA posts the result of a registration, a renewal, a transfer, and a low balance.

Request

http
POST /webhooks
Authorization: Bearer wf_live_...
Content-Type: application/json

{ "url": "https://yourapp.example/wafra-webhook" }

The signing secret is returned once. Save it.

Headers on every delivery

HeaderValue
X-Wafra-Eventthe event name
X-Wafra-Signaturehex HMAC-SHA256 of the raw body, using your secret

Verify before you trust

js
const expected = crypto
  .createHmac("sha256", secret)
  .update(rawBody)
  .digest("hex");

if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
  return res.status(401).end();
}
res.status(200).end();

Answer 2xx quickly, then do your own work.

Events

EventMeaning
domain.registeredRegistration succeeded, hold captured
domain.registration_failedRegistration failed, hold released
domain.renewedRenewed. Carries domain_id, not the domain name
domain.gracePaid term ended. Renewable for 30 days
domain.removedDeleted. This is not a registration result
domain.transfer.completedTransfer in finished
domain.transfer.failedTransfer failed
domain.eligibility.expiring.qa document expiring. Fields: domain_id, domain, customer_id, expires_on, days_left, stage (30 or 7)
dns.graceWAFRA DNS charge failed. 5 days to pay
dns.removedDNS zone and records deleted
server.graceMachine is off for 7 days
server.removedMachine deleted
balance.lowDomain balance at or under the company threshold, or an automatic domain renewal could not hold the price
topup.capturedTop-up received

Amounts in the body are QAR. dns.grace and dns.removed are the DNS anniversary, not the domain expiry.

Domains

Check, quote, then register. Renew and transfer use the same quote. An unpaid name can be renewed for 30 days, then it is deleted. An expired .qa document suspends the name for 15 days.

05Check the name

GET /domains/check?domain=

What it is. The check asks if the name is free.

CallReturnsCharges?
Zones and the QAR price for register, renew, and transferno
GET /domains/check?domain=Whether the name can be registered, and the one-year priceno

A zone that is not on this company comes back as unsupported.

06Customers and contacts

POST /customersPOST /contacts

What it is. The customer is the person you are selling to. The contacts are the four records the registry stores on the name.

CallStores a passwordReturnsSpends
POST /customersyescustomer idno
POST /auth/registeryescustomer id, access token, refresh tokenno
POST /auth/loginnoaccess token, refresh tokenno
POST /auth/refreshnoaccess token, refresh tokenno

Both create calls take email, a password of at least 8 characters, and name. The access token lasts 15 minutes.

A customer token can list and read that customer's servers, poll readiness, power them, run backups, and manage Coolify domains, DNS, and mailboxes. Ordering, resize, the billing cycle, renewal, and deletion stay on the company key.

Contact fields

All of these are required. state is optional.

FieldRule
first_name, last_name, organization, address, cityEnglish characters only
emailrequired
phoneIncludes the country code. +97470202010 and +974.70202010 are both accepted. The API stores +974.70202010
postal_codeAt least 4 digits when it is numbers only, or 2 characters when it contains a letter
countryTwo-letter code
customer_idThe buyer id from POST /customers. That contact belongs to that buyer

first_name and last_name are joined into one name for .qa. One contact is created on both .qa and the other registry, and the same contact id is used for either name. One contact id can fill more than one role.

WAFRA assigns the contact id. The reseller does not. PATCH /contacts/{id} can change an admin, tech, or billing record. A contact that is the registrant on a name cannot be edited or deleted. Point the domain at a different verified contact with PUT /domains/{id}/contacts.

How to implement

  1. If buyers already sign in on your side, call POST /customers from your server, keep the password you generated, and store only the returned id. Pass that id as customer_id.
  2. If you want WAFRA to sign the buyer in, use POST /auth/register and store the refresh token on your server.
  3. Save the four contact ids and reuse them.
  4. A contact missing address, city, postal_code, organization, or any other required field is refused, on create and again when it is used as the registrant.
  5. POST /contacts/{id}/verify asks the registry to email that contact. .qa does not send its own email. POST /contacts/{id}/activate sends the code and marks the contact verified only when the registry accepts it. A test key returns the code in the verify response and sends no email.

07Quote, then register

POST /pricing/quotePOST /domains

What it is. The quote freezes the wholesale price for 5 minutes. The register call spends it.

The flow

text
POST /pricing/quote ─► quote_id (valid 5 min)
        │
        ▼
POST /domains  (quote_id + Idempotency-Key + 4 verified contacts)
        │
        ├─ 201 ─► name registered, hold captured
        │            └─► .qa only: upload document next
        ├─ 422 before hold ─► no money moved
        ├─ 422 registry_failed ─► hold released, money is back
        └─ 503 settlement held ─► DO NOT RETRY. Wait for the event.

Step 1: quote

FieldRequiredNotes
actionyesregister
domainyes
yearsyes1 to 10
wafra_dnsnotrue adds WAFRA DNS at 24 QAR a year

The response id and quote_id are the same value, with amount_qar and expires_at.

Step 2: register

FieldRequiredNotes
quote_idyesFrom step 1. Older than 5 minutes means quote again
domain, yearsyesMust match the quote
contacts.registrant contacts.admin contacts.tech contacts.billingyesAll four must already be verified
wafra_dnsnoMust equal the quote, or omit it. A mismatch is refused before any hold
eligibility_entity eligibility_type eligibility_value.qa familySee below. Send them before the hold
extrasome TLDsSee Reference. A checkbox extra is true. A select extra must be one of the listed values. An extension that is not offered is refused
Header Idempotency-KeyyesNew key per new attempt. The key is stored for the company and is not expired by the API

For .qa, .com.qa, and .net.qa, each hostname is turned into a nameserver id before the name is registered, and a missing host is created. The Qatar registry does not accept the hostname on the domain. An empty id list leaves the name inactive. WAFRA DNS publishes ns5.wafracloud.net and ns6.wafracloud.net.

WAFRA assigns the domain id. For .qa, .com.qa, and .net.qa that id is the numeric id stored at the registry, and renew uses that same id. A dom_ id is used only when the registry has no number. The reseller does not choose domain, contact, nameserver, or server ids. The reseller chooses customer_id. The name is also stored on the reseller's WAFRA user, so WAFRA can open it the same way as a retail name. Retail card renewal and retail invoices do not charge it. Renewal spends the reseller balance when POST /domains/{id}/renew is called.

Results

ResponseMeaningMoneyWhat you do
201RegisteredcapturedUpload the document if .qa
422 contact_unverifiedContact not verifiednone movedVerify, then retry with a new key
422 eligibility_requiredMissing eligibilitynone movedFix the body
422 registry_failedRegistry refused, after the holdreleasedMoney is back
503 settlement: heldOutcome pendingheldDo not retry. Wait for the event

`.qa`, `.com.qa`, and `.net.qa` eligibility

Zoneeligibility_entityeligibility_type
.qapersonQatar ID or Residency Permit
.qacompanyTrade License/CR
.com.qa, .net.qacompany onlyTrade License/CR

eligibility_value is the number printed on the document: the CR number, the licence number, or the ID number.

Name matching

  • An individual contact must be the English name on the card, in the same words and the same order.
  • A company contact must be the legal entity name. A legal-form suffix may differ.
  • For a Qatar ID or a Residency Permit, the .qa label must be that English name with spaces and hyphens removed. .com.qa and .net.qa do not use that label rule.
  • Trademark is not accepted. Do not send a document link.

Document lifecycle

WhenWhat happens
File missingGET /domains/{id}/documents returns on_file false and blocked true. Renew is refused with eligibility_required and no money is held
30 days and 7 days before expirydomain.eligibility.expiring, stage is 30 or 7
Expiry dateNameservers become nssuspend1.wafracloud.net and nssuspend2.wafracloud.net for 15 days
Day 16The name is set for deletion

08Renew, transfer, and DNS

POST /domains/{id}/renewPOST /domains/transferPOST /domains/{id}/documentsPOST /domains/{id}/dns/enable

What it is. Each of these is the same pattern as registration: quote, then the billable call.

JobQuote actionThen callMoney
RenewrenewPOST /domains/{id}/renewDomain balance. The renew quote does not include WAFRA DNS
Transfer intransfer_inPOST /domains/transfer with quote_id, domain, auth_code, and the same eligibility and contacts a registration needs.qa, .com.qa, and .net.qa quote at 0 QAR. Any other transfer stays held until it finishes
WAFRA DNSdnsPOST /domains/{id}/dns/enable24 QAR a year from the day it is turned on, not from the domain expiry

The old path POST /domains/{id}/transfer is the same call as POST /domains/transfer. Upload the file after the name exists. Do not send a link.

CallWhat it does
POST /domains/{id}/transfer/completeFinish a waiting .qa transfer with the new registrant eligibility
POST /domains/{id}/internal-transferMove a .qa name between two of your own customers. No transfer code
POST /domains/{id}/transfer-outSets transfer_status to outbound and returns the auth code. Calling it again returns the same code. For .qa the registry emails that code to the registrant
GET /domains/{id}/auth-codeReads that code and does not change the status
GET /domains/transfersEvery row with a transfer status, including a finished transfer-in, a transfer-out, and an internal move
PUT /domains/{id}/contactsAssigns different verified contacts. It does not edit the contact record. Changing the registrant on .qa, .com.qa, or .net.qa needs the new holder's eligibility
POST /domains/{id}/dnsAdds a record with type, host, value, and ttl, only while DNS is on and not in the 5-day window
PATCH or DELETE /domains/{id}/dns/{recordId}Edits or removes a record while WAFRA DNS is on
POST /nameservers then PUT /domains/{id}/nameserversNameservers are free. For .qa that PUT, and registration, turn each hostname into a nameserver id and create a missing host. An empty id list leaves the name inactive
PATCH /domains/{id}Can set name_servers, locked, or auto_renew
POST /domains/{id}/documentsMultipart form data: file, eligibility_entity, eligibility_type, eligibility_value. One file is enough
GET /domains/{id}/documentsReports on_file
POST /domains/{id}/eligibilityDoes not store a file. For .qa, .com.qa, and .net.qa it is refused

DNS anniversary

POST /domains/{id}/dns/enable sets dns_paid_until one year ahead for each year on the quote. POST /domains/{id}/dns/disable turns billing off and leaves the zone in place until that paid date. On the paid date the balance is charged again if DNS is still on. If the balance is short, or DNS was turned off, there are 5 days to pay. Paying calls dns/enable again and turns the zone back on. On the 6th day the zone and its records are removed.

How to implement

  1. A new domain is stored with auto-renew on. PATCH auto_renew false when the domain balance should not renew it. The same switch is on the domain page. A server starts on, and POST /servers/{id}/auto-renew turns it off.
  2. None of these charges a card. A short balance, or auto-renew left off, puts the name in a 30-day grace after the expiry date, and the server off for 7 days. Power on is refused until Renew.
  3. The renewal run is once a day at 03:00 UTC. It looks 14 days ahead and takes one year from the domain balance. If the balance cannot hold that price, balance.low fires that day and again on each later day the hold still fails. That webhook is not deduped. WAFRA DNS is not part of that charge.
  4. A short balance before the expiry only warns. The current paid term stays up. If it is still unpaid when the 30 days end, the name is deleted at the registry. Nameserver, lock, and DNS changes are refused until POST /domains/{id}/renew succeeds.
  5. For .qa, .com.qa, and .net.qa, renew is refused until a current eligibility document is stored, and an expired document blocks every change, including renew. The renewal sends the stored type and the number on that document. The registrant must match the name on the document. If the current file is not stored, the nameservers become nssuspend1.wafracloud.net and nssuspend2.wafracloud.net for 15 days. On the 16th day the name is deleted at the registry.

Servers

Quote, create, then operate. Renewal comes out of the server balance. An unpaid server is off for 7 days, then it is deleted.

09Read the server catalogue

GET /servers/locationsGET /servers/plans

What it is. Choose a location first. The plan list is the machines this company can sell there, at the price set for this company.

FactRule
PriceOne price in QAR, monthly and yearly. A company price is what the server balance pays. A plan with no company price uses the current selling price
Listed machinesOnly machines that can be provisioned immediately. Dedicated servers are hidden, and the dedicated calls are not on this API. The cx63 plan is hidden. A plan the company has hidden is omitted
Show or hidePOST /servers/plans/{plan_id} with shown true puts a plan back, and shown false hides it. Send the plan id you already know
LocationGET /servers/locations returns the ids. GET /servers/plans requires location
hel1Helsinki catalogue only. A region plan is not in that list
Any other locationThat region catalogue only. A Helsinki plan is not in that list
Disk, CPU, memoryCome from the plan. Each plan includes disk_gb
ImagesGET /servers/images returns image ubuntu-22.04 and panels hestiacp and coolify. The call does not charge. The servers scope is required

How to implement

  1. Read the locations first, then GET /servers/plans with that location, then the images.
  2. Use those ids exactly. Cache the plan list for the page, and read it again before a quote.
  3. The price in the list is the price the server balance will pay.

10Quote, then create

POST /servers/quotesPOST /servers

What it is. The quote freezes this company price for five minutes. The create call holds it on the server balance and starts the machine.

FieldRequiredNotes
plan_idyesFrom the catalogue for that location
billing_cycleyesmonthly or yearly
locationyesAn id from GET /servers/locations. Helsinki plans use hel1
imageyesMust be ubuntu-22.04
panelyeshestiacp or coolify. Coolify is rejected on a machine that is too small
hostname_parentnoOmit to use the parent saved in Settings, or the buyer parent when customer_id is sent. An empty string forces wafracloud.net. A full hostname is refused
customer_idnoUses that buyer parent when hostname_parent is omitted
hostnamenoDo not send it. WAFRA assigns vps and six new letters, then the parent. The six letters change on every quote
disk_gb, cpu, ram, memory, storagenoDo not send them. Disk, CPU, and memory come from the plan

The nameservers are ns1 and ns2 on that new host. Step 13 is the setup. The quote field publication says who writes the zone. publication external means the name is not published. The quote response includes the hostname WAFRA assigned.

POST /servers takes quote_id and an optional customer_id. Idempotency-Key is required. The server balance holds the cycle price plus any setup. The hold stays until the tunnel is up. The server is marked ready only then, and the login is emailed to the company and, when customer_id was sent, to that customer. If the tunnel is still down one hour after the order, status becomes error and the hold is released. A test key returns a fake server already ready and never starts a real machine.

How to implement

  1. Send the location, image, and panel you read from the catalogue calls. Do not invent a location or an image.
  2. Save the server id from the 201. settlement is held until the machine is ready.
  3. Poll GET /servers/{id}/readiness until ready is true. Keep polling. The wait is at most 1 hour. Payment does not mean the machine is ready. ready, tunnel, wait_until, and seconds_remaining are on that response.
  4. GET /servers/{id} returns hostname, url, address, location, plan_id, root_username, root_password, panel_username, panel_email, panel_password, storage_gb, ram_gb, cpu_cores, backup_cap_gb, ready, and wait_until. root_username is root. On Coolify, panel_username and panel_email are the email address, and panel_password is the password. On Hestia, panel_username is the panel user. The list omits the passwords.
  5. There is no webhook for a server becoming ready.

11Operate the machine

GET /servers/{id}/readinessGET /servers/{id}/detailsPOST /servers/{id}/powerPOST /servers/{id}/backupsGET /servers/{id}/domainsGET /servers/{id}/dnsPOST /servers/{id}/mail

What it is. Power and backups are the day-to-day controls. They do not charge the balance. The panel address and the root login are already on the server read. There is no terminal call.

ControlSendCharges?
Poweraction on, off, or rebootno
BackupsCopies are stored on Backblaze. Losing the machine does not delete copies already uploadedno
Mailop list, connection, create, password, or deleteno

Opening the server lists the copies and does not start a backup. The first time the copy store is missing, that read prepares it and starts the first copy. A later read does not start another copy. One copy is taken each day. Five copies are kept.

PanelRestore
Hestia, hestiacpop restore with snapshot_id, or op restore-account with user and snapshot_id. Account reads are account-snapshots, account-snapshot-inventory, account-snapshot-mailboxes, and account-restore-status
Coolify, coolifyWhole server is op restore. Platform ops start with coolify-platform-. Domain ops start with coolify-domain- and send domain. App ops start with coolify-app- and send uuid
Shared readsget-status, snapshots, get-usage, run-now, verify, and restore-status

An operation from the other panel is refused. A customer token can read the server, poll readiness, power it, run backups, and manage Coolify domains, DNS, and mailboxes. Ordering, resize, the billing cycle, renewal, and deletion stay on the company key.

Coolify domains, DNS, and mail

On a Coolify server, add the domain before a mailbox. POST /servers/{id}/domains sends domain and creates the DNS zone, the mail domain, the site, and the certificate. The zone already holds the address records, mail, webmail, and an MX record for mail.domain. The response nameservers are ns1 and ns2 on the server hostname.

CallBody
GET /servers/{id}/dns?domain=Lists the zone
POST /servers/{id}/dnsdomain and record, with record.name, record.type, record.value, and optional record.priority and record.ttl
PUT /servers/{id}/dnsThe same record plus old_name and old_type
DELETE /servers/{id}/dns?domain=&name=&type=Removes that record
DELETE /servers/{id}/domains?domain=Removes that domain
GET or POST /servers/{id}/mailMailboxes only. create and password also send email and a password of at least 6 characters

Types are A, AAAA, CNAME, MX, TXT, SRV, and CAA. NS records and the ns1 and ns2 records are not listed. A write that names them is refused, because changing them can take the server offline. A TXT value is returned in full. A semicolon inside the value is kept. Send subdomain_of when the name sits under a domain that is already there. Those records are written into the parent zone.

GET /servers/{id}/details returns the hostname, the address, ns1 and ns2 on that hostname, the nameserver address, and the uptime once the server is active. Readiness stays for a machine that is not active yet.

IMAP is mail.domain port 993 and SMTP is mail.domain port 465. Hestia domains, DNS, and mail stay in the Hestia panel, and these calls are refused there. There is no mail security, filter, forwarder, or migration call. There is no call for a root password reset, a rebuild, reverse DNS, metrics, a browser console, a firewall, rescue, an ISO, or a static address. WAFRA sets the reverse record when the machine is created.

How to implement

  1. Call power, backups, and mail only after readiness says ready is true.
  2. While a server is in the 7-day grace, power on and reboot are refused until it is renewed.
  3. Show the panel url and the root login in your own panel. The customer does not need a WAFRA login.
  4. The reseller portal server page uses these same calls. The Coolify login is the email and the password. It does not include those mailboxes. A mailbox saved in the portal is the mailbox GET or POST /servers/{id}/mail returns.

12Resize and renewal

POST /servers/{id}/rescale/quotePOST /servers/{id}/rescalePOST /servers/{id}/renew

What it is. A larger plan charges the remaining days of the current cycle. Renewal charges the server balance on the renewal date.

Field on the quoteMeaning
charge_qarThe price difference for the days left in the cycle. A yearly cycle uses twelve times the monthly difference, then the share of the year that is left
is_downgradeA downgrade returns charge_qar 0 and does not credit the wallet
days_remainingDays left in the cycle
next_qarThe cycle price stored after the change

A Helsinki machine stays on the Helsinki catalogue. The new plan must use the same processor family and the same disk type. Shared and dedicated CPU plans in that family are allowed. Send keep_disk. Leave it out or send true to keep the current disk, which is what the WAFRA card does. Send false only when the new plan disk is larger and that disk should grow. That growth is permanent and later plans must be at least that size. Leave disk_gb out. A smaller disk is refused.

A region machine stays in the same location and the same machine family. Read GET /servers/plans for that location and send one of those plan ids. Send disk_gb. Omit it to keep the current disk. A value below the current disk is refused. The disk can only grow. Leave keep_disk out. Sending the other machine field is refused. The same plan with the same disk is refused.

The machine stops, the change is applied, and it starts again. POST /servers/{id}/rescale takes the same body. Send Idempotency-Key when charge_qar is above 0.

CallEffect
POST /servers/{id}/billing-cyclebilling_cycle monthly or yearly, a different value from the one stored. It does not read Idempotency-Key. The same server and the same new cycle are one charge. A cheaper cycle changes the stored price and does not refund
POST /servers/{id}/auto-renewA new server is stored with auto-renew on. This sets it on only when enabled is the boolean true
POST /servers/{id}/renewCharges the next period from the server balance. It is the only call that starts a machine that was turned off for a missed renewal
POST /servers/{id}/cancelDeletes the machine now, sets status cancelled, and stops renewal. WAFRA then removes the zone rows and the registry glue it created. An outside parent is left unchanged. The reverse record goes away with the machine. The period already captured is not refunded

There is no card invoice for a reseller server. There is no manage-server call.

13Publish the server hostname

GET /servers/hostnamePUT /servers/hostnamePATCH /customers/{id}

What it is. Every server gets a name: vps plus six new letters plus . plus the parent. Its nameservers are ns1 and ns2 on that same name.

Choose a parent

OptionYou sendWho writes the zoneUse when
WAFRA zonehostname_parent ""WAFRA, on wafracloud.netAlmost always. This does not use the domain wallet
Company domainomit hostname_parentWAFRA if the domain is on this account with WAFRA DNS paid. Otherwise youThe parent saved in Settings should be the name on every new server
Customer domainthe customer's domainSame rule as a company domainThis order should use that customer's own domain

Read `publication` on the quote

publicationautomaticMeaning
wafratrueWAFRA writes everything on wafracloud.net
accounttrueParent is on this account with WAFRA DNS. WAFRA writes the zone
externalfalseWAFRA writes nothing in the zone. Your code must

Who does what

WAFRAYou
Assign hostname and nameserver namesyes
Assign the IP addressyes
Write the zone, wafracloud.net or an account parent with DNS paidyes
Write the zone, outside parentyes
Create glue at an outside registrar (glue yours)yes. No API call exists
glue registryyes, even when publication is external
Set reverse DNS to the hostnameyes, for every parent
Check that the name resolvesyes
Keep the parent's WAFRA DNS paidyes, domain wallet

POST /nameservers is only for a domain this account holds at Qatar or CentralNic. automatic false means the zone is not written.

The five records, for an `external` parent

Read them from GET /servers/{id}/details once address is present. Rows are relative to the zone when publication is account, and relative to the parent when publication is external. Example with parent example.com, label vpsabcdef, IP 203.0.113.10:

dns
vpsabcdef            A    203.0.113.10
ns1.vpsabcdef        A    203.0.113.10
ns2.vpsabcdef        A    203.0.113.10
vpsabcdef            NS   ns1.vpsabcdef.example.com.
vpsabcdef            NS   ns2.vpsabcdef.example.com.

WAFRA uses TTL 3600. The response does not include a TTL. The sandbox address is 203.0.113.10, so you can test the record shape. The sandbox writes nothing to any registrar.

What can take the names down

Good to know

  • Settings does not rename a server that already exists. A new quote mints a new name. Changing a domain buyer does not rewrite servers that already exist.
  • PUT /servers/hostname returns the same fields as GET.
  • PATCH /customers/{id} with hostname_parent saves a buyer parent. An empty string clears it. Send that customer_id on the quote.
  • A parent that belongs to a different buyer is refused on the quote and on PATCH. The error names that buyer and says to send that customer_id, or to use a company domain.
  • Create inherits the quote's buyer. A different customer_id on create is refused before the hold.
  • Cancel removes only the five rows and the ns1 and ns2 hosts WAFRA created. It does not delete the parent zone. An outside parent is left for the reseller. A row you edited to another address stays.

How to implement

  1. Use wafracloud.net unless the DNS side is automatic. Calling the server API is not that automation.
  2. Read publication, automatic, glue, and dns_grace on the quote. publication wafra and publication account are written by WAFRA. publication external means the checkout writes hostname_records and, when glue is yours, the host records at the registrar.
  3. Offer three choices. Omit hostname_parent for the company domain saved in Settings. Send hostname_parent as an empty string for the WAFRA zone, wafracloud.net. Send the customer's domain for a customer domain. Do not send hostname.
  4. When GET /servers/{id}/details has an address, the five hostname_records are the rows to copy. Do this in the same code that creates the server when publication is external.

Reference

Contacts

A contact uses the same fields a retailer contact uses. All of these are required: first_name, last_name, email, phone, organization, address, city, postal_code, country.

first_name, last_name, organization, address, and city use English characters only. phone includes the country code. +97470202010 and +974.70202010 are both accepted. The API stores the phone as +974.70202010. A .qa contact is sent to the registry in that form, with first_name and last_name joined into one name. country is the two-letter code, such as QA. postal_code accepts letters or numbers. A code with a letter needs at least 2 characters. A numbers-only code needs at least 4 digits.

state is optional. The stored name is first_name and last_name together.

One contact is created on both .qa and the other registry. Verification is required because that same contact is used for both. POST /contacts/{id}/verify emails the address on the contact. The other registry sends that email. .qa does not send its own. POST /contacts/{id}/activate confirms the code from that email. Registration, transfer in, and an internal transfer refuse until registrant, admin, tech, and billing are verified. The error code is contact_unverified and no money is held.

Documents the reseller keeps

A .qa, .com.qa, or .net.qa name does not take a document link. After the name exists, POST /domains/{id}/documents uploads the file. That call reads it and stores it under the domain name. One file is enough. A Qatar ID or Residency Permit can include the front and the back in that same photo or PDF.

.qa, .com.qa, and .net.qa

These three need eligibility_entity and eligibility_type before the balance is held. eligibility_entity is person for an individual, or company for a company. .com.qa and .net.qa are company only. An individual uses Qatar ID or Residency Permit. A company uses Trade License/CR. Trademark is not accepted. The file is uploaded after the name exists. The reader accepts only a Commercial Registration, a Commercial License, a Qatar ID, or a Residency Permit, and only when that file matches the type and has not expired. A link is not stored. .com.sa is a different mechanism: it sends an https url, not this file upload. The name is registered and paid before the file exists. If the upload is refused, upload again. No suspension starts until a file with an expiry date is stored. Renew is refused until a current file is stored. error.code is eligibility_required and no money is held. GET /domains/{id}/documents returns on_file false and blocked true while the file is missing. The reseller is notified 30 days before the document expires, and again 7 days before. The webhook is domain.eligibility.expiring and stage is 30 or 7. On the expiry date the nameservers become nssuspend1.wafracloud.net and nssuspend2.wafracloud.net. There are 15 days to upload a current file. On the 16th day the name is set for deletion. A new name, and a name that has just transferred in, stays locked for 60 days. PATCH locked false, POST /domains/{id}/transfer-out, and GET /domains/{id}/auth-code return error.code domain_locked until that date, in the API and in the portal. Transfer out is refused for those 60 days. For .qa, .com.qa, and .net.qa the registrar lock is not set, so this API refuses the transfer itself. For every other name the registrar transfer lock is also set at registration. A name that reaches the end of its paid term without a renewal stays for 30 days. Only renewal is accepted. The nameservers are not changed for that reason. After 30 days the name is deleted at the registry.

.qa accepts Trade License/CR, Qatar ID, and Residency Permit. Trademark is not accepted. .com.qa and .net.qa accept Trade License/CR. Qatar ID, Residency Permit, and Trademark are refused on those two.

An individual, for Qatar ID or Residency Permit: upload one file. The front and the back of the card can be in that same file. The number is read from the file. Send eligibility_entity person.

A company, for Trade License/CR: upload one file. Do not send a link. The file is read for the licence or CR number. Send eligibility_entity company.

.com.sa

Send documents with kind sa_trademark or sa_incorporation and an https url. A trademark certificate must be for this exact name. An incorporation certificate is the local-presence alternative. Store the file. WAFRA can ask for it.

Extensions that are not offered

A check returns supported false. Register and transfer are refused. .adult, .adult.ht, .porn, .xxx, .sex, .sexy, .webcam, .casino, .bet, .poker, .lotto, .bingo, .gay, .lesbian, .il, .co.il, .org.il, .net.il, .ac.il, .gov.il, .muni.il, .cannabis, .vodka, .wine, .beer.

Extensions that cannot be transferred in

.cf, .gq, .hu. Registration can still be quoted when the extension is on this company catalogue.

Extensions that need extra fields

Send extra on register. Send it on transfer-in as well when the note below says so. The keys are the same keys a retailer form collects.

.law

Only licensed/accredited legal professionals may register .law domains. Required on register and on transfer-in. Your accreditation details will be sent to the registry for verification. Registration may be delayed or rejected if verification fails.

  • extra.accreditationBody (text, required). Accreditation Body. Name of the body that accredited you
  • extra.accreditationId (text, required). Accreditation / License ID. Your unique accreditation or bar number
  • extra.accreditationYear (text, required). Year of Accreditation.
  • extra.jurisdictionCountry (text, required). Jurisdiction Country. 2-letter country code
  • extra.jurisdictionProvince (text, optional). Jurisdiction Province/State.

.abogado

Only licensed/accredited legal professionals may register .abogado domains. Required on register and on transfer-in. Your accreditation details will be verified by the registry.

  • extra.accreditationBody (text, required). Accreditation Body.
  • extra.accreditationId (text, required). Accreditation / License ID.
  • extra.accreditationYear (text, required). Year of Accreditation.
  • extra.jurisdictionCountry (text, required). Jurisdiction Country.

.aero

Only aviation industry members may register .aero domains. You need an ENS Auth ID from information.aero. Required on register and on transfer-in. Your ENS credentials will be verified with the .aero registry. Apply for an ID at https://information.aero if you don't have one.

  • extra.ensAuthId (text, required). AERO ENS Auth ID. Apply at https://information.aero
  • extra.ensAuthKey (text, required). AERO ENS Auth Key.

.travel

Registrant must be part of the travel industry. Required on register and on transfer-in. The registry will verify your travel industry affiliation.

  • extra.travelUin (text, optional). Travel UIN (Unique ID Number). If you have a Travel UIN, enter it
  • extra.travelIndustry (checkbox, required). Travel Industry Confirmation. I confirm the registrant is part of the travel industry

.coop

Only cooperative entities may register .coop domains. Required on register and on transfer-in. The .coop registry will verify that your organization meets cooperative eligibility requirements after submission.

  • extra.coopEligibility (checkbox, required). Cooperative Eligibility Confirmation. I confirm this organization meets .coop eligibility requirements

.nyc

At least one contact must have a valid physical address in New York City. Required on register and on transfer-in. The registry will verify that the specified contact has a valid NYC address.

  • extra.nycContact (select, required). NYC Contact Role. One of: OWNER, ADMIN, TECH, BILLING. Which contact has the NYC address?

.swiss

Requires a Swiss Enterprise Identification Number (UID). Required on register and on transfer-in. The Swiss registry (BAKOM) will verify your UID after submission. This process may take several days.

  • extra.swissUid (text, required). Swiss Enterprise UID. Unternehmens-Identifikationsnummer
  • extra.intendedUse (text, required). Intended Use of Domain.

.zuerich

Must be a Zurich public authority or a legal entity registered in the Canton of Zurich Commercial Register. Required on register and on transfer-in. Your UID will be verified against the Canton of Zurich Commercial Register (zefix.ch).

  • extra.zuerichUid (text, required). UID Number (or "PUBLIC"). Check your UID at https://www.zefix.ch
  • extra.zuerichAgreement (checkbox, required). Canton of Zurich Agreement. I accept the local laws of the Canton of Zurich (TLDV ordinance)

.us

Registrant must have a connection to the United States. Required on register and on transfer-in. The .us registry enforces nexus requirements. Non-compliant registrations may be suspended.

  • extra.usNexusPurpose (select, required). Nexus Purpose. One of: P1, P2, P3, P4, P5. Purpose of domain registration
  • extra.usNexusCategory (select, required). Nexus Category. One of: C11, C12, C21, C31, C32. Your connection to the United States
  • extra.usNexusValidator (text, optional). Country Code (for C31/C32). Required if nexus category is C31 or C32

.au

Registrant must demonstrate Australian eligibility (ABN, ACN, or Trademark). Required on register and on transfer-in. The .au registry will verify your eligibility details.

  • extra.auIdType (select, required). ID Type. One of: ABN, ACN, TM, OTHER.
  • extra.auIdNumber (text, required). ID Number.
  • extra.auRelationType (select, required). Registrant Type. One of: Company, RegisteredBusiness, SoleTrader, Partnership, TrademarkOwner, CitizenResident, IncorporatedAssociation, NonProfitOrganisation, Charity.

.com.au

Registrant must demonstrate Australian eligibility (ABN, ACN, or Trademark). Required on register and on transfer-in. The .au registry will verify your eligibility details.

  • extra.auIdType (select, required). ID Type. One of: ABN, ACN, TM, OTHER.
  • extra.auIdNumber (text, required). ID Number.
  • extra.auRelationType (select, required). Registrant Type. One of: Company, RegisteredBusiness, SoleTrader, Partnership, TrademarkOwner, CitizenResident.

.ca

Registrant must meet Canadian Presence Requirements (CPR). Required on register and on transfer-in. CIRA will verify your Canadian presence status.

  • extra.caLegalType (select, required). Legal Type. One of: CCO, RES, ABO, ASS, CCT, EDU, GOV, HOP, INB, LAM, LGR, MAJ, OMK, PLT, PRT, TDM, TRD, TRS. Your connection to Canada

.eu

Registrant must be within the European Union, EEA, or have EU citizenship. Required on register and on transfer-in. EURid will verify your EU connection. Non-EU registrants can use trustee service.

  • extra.euRegistrantCitizenship (text, optional). EU Country of Citizenship/Residence. EU/EEA country code, or leave blank if using trustee
  • extra.euAcceptTrustee (checkbox, optional). Use Trustee Service (if not EU-based). If you are not based in the EU, a local trustee can be used

.it

Requires Italian entity information or trustee service for non-EU registrants. Required on register and on transfer-in. The .it registry (NIC.it) will verify your identity. Non-EU registrants must use a trustee service.

  • extra.itEntityType (select, required). Entity Type. One of: 1, 2, 3, 4, 5, 6, 7.
  • extra.itPin (text, required). Italian Tax Code (Codice Fiscale) / VAT. Your Italian fiscal code or VAT number
  • extra.itAcceptTrustee (checkbox, optional). Use Trustee Service (if non-EU). Non-EU registrants require a local trustee

.de

Requires a German administrative contact address or trustee service. Required on register and on transfer-in. DENIC requires a German admin-C address. Non-German registrants can use the trustee service.

  • extra.deAcceptTrustee (checkbox, optional). Use German Trustee Service. If you don't have a German address, a local trustee will be used

.fr

EU citizens/residents or entities can register. Non-EU registrants can use trustee service. Required on register and on transfer-in. AFNIC may verify your identity. Non-EU registrants must use a trustee.

  • extra.frAcceptTrustee (checkbox, optional). Use French Trustee Service. If you are not based in the EU, enable trustee service

.es

Requires Spanish identification details. Required on register and on transfer-in. The .es registry will verify your ID information.

  • extra.esOwnerIdType (select, required). Owner ID Type. One of: 0, 1, 2, 3.
  • extra.esOwnerId (text, required). Owner ID Number.

.uk

Requires corporate type and registration number for organizations. Required on register and on transfer-in. Nominet may verify your corporate details.

  • extra.ukCorporateType (select, optional). Corporate Type. One of: LTD, PLC, LLP, IP, RCHAR, SCH, GOV, STAT. Required for organizations
  • extra.ukCorporateNumber (text, optional). Company Registration Number. Companies House registration number

.co.uk

Requires corporate type and registration number for organizations. Required on register and on transfer-in. Nominet may verify your corporate details.

  • extra.ukCorporateType (select, optional). Corporate Type. One of: LTD, PLC, LLP, RCHAR.
  • extra.ukCorporateNumber (text, optional). Company Registration Number.

.ltda

Requires business authority and license information for Brazilian limited companies. Required on register and on transfer-in. The registry will verify your company license details.

  • extra.ltdaAuthorityName (text, required). Issuing Authority Name.
  • extra.ltdaLicenseNumber (text, required). License Number.

.srl

Requires business authority and license information for SRL companies. Required on register and on transfer-in. The registry will verify your company license details.

  • extra.srlAuthorityName (text, required). Issuing Authority Name.
  • extra.srlLicenseNumber (text, required). License Number.

.berlin

Requires local presence in Berlin, Germany, or trustee service. Required on register. The registry will verify the Berlin presence. Trustee service creates a local contact on your behalf.

  • extra.berlinTrustee (checkbox, optional). Use Berlin Trustee Service. Enable if you don't have a Berlin address

.bayern

Requires local presence in Bavaria, Germany, or trustee service. Required on register. The registry will verify the Bavarian presence.

  • extra.bayernTrustee (checkbox, optional). Use Bavaria Trustee Service.

.hamburg

Requires local presence in Hamburg, Germany, or trustee service. Required on register. The registry will verify the Hamburg presence.

  • extra.hamburgTrustee (checkbox, optional). Use Hamburg Trustee Service.

.ruhr

Requires local presence in the Ruhr region, Germany, or trustee service. Required on register. The registry will verify the Ruhr region presence.

  • extra.ruhrTrustee (checkbox, optional). Use Ruhr Trustee Service.