Golzak Registrar API (1.0.0)

Download OpenAPI specification:

Register and manage domains through Golzak, from your own systems or AI agents.

Reseller API to register and manage domains through Golzak. A partner company (the reseller) registers, renews, transfers and manages names for its own clients, paid from the prepaid credit of its Golzak account. Version 1 covers .ma domains only: .ma, .co.ma, .net.ma and .org.ma. Later versions may add extensions; GET /prices lists the extensions you can order.

  • Prices are the reseller's own: they come from the reseller's client group at Golzak and are read live on every call. GET /check and GET /prices return them. No price is written in this document.
  • Payment is prepaid credit. Each registration, renewal or transfer is paid from the credit balance (GET /balance). Not enough credit means error insufficient_credit and nothing is ordered.
  • Registration is asynchronous. POST /domains returns an operation. Its status moves pending → active, or refused when the registry (ANRT) refuses the name. Results arrive by signed webhook and by GET /operations/{id}.
  • Holder rules (who owns the domain, which legal ID) are enforced by the API, never left to the reseller. See the Holder schema.

Human guides, the AI integration guide and llms.txt are published next to this reference.

Account

Prepaid credit and the daily spending cap of your API key.

Read your credit and daily cap

Your prepaid credit (read live from Golzak's billing system) and, for the key making the call, its daily spending cap and what it has spent since 00:00 UTC.

Authorizations:
apiKey

Responses

Response samples

Content type
application/json
{
  • "credit": {
    },
  • "daily_spend_cap": {
    },
  • "spent_today": {
    },
  • "cap_resets_at": "2026-10-09T00:00:00Z"
}

Availability and prices

Is a name free, and what does it cost you. Prices are read live from your client group.

Check availability and your 1-year price

Answers whether name can be registered and returns your price for one year. The availability answer comes from a WHOIS lookup and is a strong hint, not a reservation: the registry gives the final answer when the registration is submitted.

Only .ma, .co.ma, .net.ma and .org.ma are accepted. .ac.ma, .gov.ma and .press.ma answer tld_manual_only.

Authorizations:
apiKey
query Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: name=atlas-tours.ma name=atlas-export.co.ma

Full domain name, lower case, e.g. example.ma or example.co.ma.

Responses

Response samples

Content type
application/json
Example
{
  • "name": "atlas-tours.ma",
  • "extension": ".ma",
  • "available": true,
  • "price": {
    }
}

List your prices for every accepted extension

Your register, renew and transfer prices for .ma, .co.ma, .net.ma and .org.ma, per number of years. The figures come from your client group at Golzak and are read live on every call: never cache them for longer than a quote you show to a client. The year counts listed are the only ones you can order.

Authorizations:
apiKey

Responses

Response samples

Content type
application/json
{
  • "currency": "<your account currency>",
  • "source": "client_group",
  • "read_at": "2026-10-08T09:00:00Z",
  • "extensions": [
    ]
}

Domains

Register, list, read, renew, change nameservers, lock, auto-renew, get the transfer code.

List your domains

Every domain of your account, newest first, paginated with an opaque cursor.

Authorizations:
apiKey
query Parameters
limit
integer <int32> [ 1 .. 100 ]
Default: 50

Page size.

cursor
string <= 512 characters ^[^\u0000-\u001F\u007F]*$

The next_cursor of the previous page.

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "next_cursor": null
}

Register a domain (asynchronous)

Orders the registration of name for years, for the holder given, paid from your credit. Every check runs before anything is ordered: name and extension, holder rules, availability, your price, your credit balance and your daily spending cap. If one fails you get the error and nothing is ordered or charged.

On success the answer is 202 with an operation in status pending. Follow it with webhooks or GET /operations/{id}. It ends in:

  • active: the domain is registered;
  • refused: the registry (ANRT) refused the name; the charge is returned to your credit (see refund);
  • failed: a technical failure; the charge is returned to your credit.

While ANRT examines a name (pending_reason: registry_review), documents_required is true (and documents_deadline when known): send the documents asked for in Golzak's e-mail before that date, or the request lapses.

Send ?dry_run=true to run every check without ordering: the answer is 200 with the charge that would be made.

Authorizations:
apiKey
query Parameters
dry_run
boolean
Default: false

true runs every check and returns the would-be charge; nothing is ordered.

header Parameters
Idempotency-Key
required
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$
Example: 0b8c7f0e-6a39-4b8f-9a0e-2f5d7c1e9a41

Required on every POST. A unique value per intended action (a UUID v4 is ideal). Retrying with the same key and the same body returns the first answer with Idempotent-Replayed: true and orders nothing new. The same key with a different body answers idempotency_key_reused. Keys are kept for 24 hours.

Request Body schema: application/json
required
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...

A lower-case ASCII host name (letters, digits, hyphens, dots). The API then checks the extension and answers 422 tld_manual_only or 422 tld_not_supported when it is not accepted, and 400 invalid_domain_name when it is not exactly one label plus an accepted extension (e.g. a.b.ma, or a bare co.ma, net.ma, org.ma, gov.ma, ac.ma, press.ma, refused as names by Golzak policy).

years
required
integer <int32> [ 1 .. 5 ]

Must be one of the year counts in your register price table (GET /prices). A name can never be valid for more than 5 years from today (ANRT decision 02/2024 art. 33.1): a renewal that would pass that limit answers validation_failed with exceeds_max_validity.

required
object (Holder)

The domain holder (registrant): your client, never your own company and never a registrar's staff. The API refuses a holder whose e-mail or organization is your own account's (holder_is_reseller).

legal_id is always required. What it must contain depends on type and moroccan:

type moroccan legal_id
individual true CIN (Moroccan national identity card number)
individual false passport number
company true company tax ID (ICE / RC)
company false company registration number or tax ID

moroccan selects which document the holder must give; it is not derived from the address (a Moroccan can live abroad). The API does not check the number's format: ANRT checks the documents.

nameservers
required
Array of strings (Nameservers) [ 2 .. 5 ] items unique [ items [ 3 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]... ]

2 to 5 distinct nameserver host names (Golzak API rule).

Responses

Request samples

Content type
application/json
Example
{
  • "name": "atlas-tours.ma",
  • "years": 1,
  • "holder": {
    },
  • "nameservers": [
    ]
}

Response samples

Content type
application/json
{
  • "dry_run": true,
  • "would_charge": {
    },
  • "credit_after": {
    }
}

Read one domain (status and expiry)

Status, dates, nameservers, auto-renew and transfer-lock state of one of your domains. A name that is not in your account answers domain_not_found, whether or not it exists elsewhere.

Authorizations:
apiKey
path Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: atlas-tours.ma atlas-export.co.ma

Full domain name of one of your domains.

Responses

Response samples

Content type
application/json
{
  • "name": "atlas-tours.ma",
  • "status": "active",
  • "registered_at": "2026-10-08",
  • "expires_at": "2027-10-08",
  • "auto_renew": false,
  • "transfer_locked": true,
  • "pending_operation_id": null,
  • "nameservers": [
    ]
}

Renew a domain (asynchronous)

Renews name for years, paid from your credit at your renew price. Credit and daily cap are checked before anything is ordered. Returns an operation that ends active (renewed, new expires_at on the domain) or failed (charge returned to your credit).

Authorizations:
apiKey
path Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: atlas-tours.ma atlas-export.co.ma

Full domain name of one of your domains.

query Parameters
dry_run
boolean
Default: false

true runs every check and returns the would-be charge; nothing is ordered.

header Parameters
Idempotency-Key
required
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$
Example: 0b8c7f0e-6a39-4b8f-9a0e-2f5d7c1e9a41

Required on every POST. A unique value per intended action (a UUID v4 is ideal). Retrying with the same key and the same body returns the first answer with Idempotent-Replayed: true and orders nothing new. The same key with a different body answers idempotency_key_reused. Keys are kept for 24 hours.

Request Body schema: application/json
required
years
required
integer <int32> [ 1 .. 5 ]

Must be one of the year counts in your renew price table. A name can never be valid for more than 5 years from today (ANRT decision 02/2024 art. 33.1): a renewal that would pass that limit answers validation_failed with exceeds_max_validity.

Responses

Request samples

Content type
application/json
{
  • "years": 1
}

Response samples

Content type
application/json
{
  • "dry_run": true,
  • "would_charge": {
    },
  • "credit_after": {
    }
}

Replace the nameservers

Replaces the full nameserver list. Synchronous: the answer comes after the registry accepted the change. A name still under ANRT examination cannot be changed (domain_status_prohibits). Idempotency-Key is accepted and recommended here.

Authorizations:
apiKey
path Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: atlas-tours.ma atlas-export.co.ma

Full domain name of one of your domains.

header Parameters
Idempotency-Key
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$

Optional on PUT; same rules as on POST. Recommended.

Request Body schema: application/json
required
nameservers
required
Array of strings (Nameservers) [ 2 .. 5 ] items unique [ items [ 3 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]... ]

2 to 5 distinct nameserver host names (Golzak API rule).

Responses

Request samples

Content type
application/json
{
  • "nameservers": [
    ]
}

Response samples

Content type
application/json
{
  • "name": "atlas-tours.ma",
  • "status": "pending_registration",
  • "registered_at": "2019-08-24",
  • "expires_at": "2019-08-24",
  • "auto_renew": true,
  • "pending_operation_id": "string",
  • "transfer_locked": true,
  • "nameservers": [
    ]
}

Get a new transfer (EPP) code

Returns the transfer code (EPP auth code) the holder needs to move the name to another registrar. Each call sets a new code at the registry; the previous code stops working. Give the code only to the domain holder.

The code alone is not enough: Golzak locks every name against transfer. Remove the lock first with PUT /domains/{name}/transfer-lock ({"locked": false}), or the new registrar's transfer request is refused.

Authorizations:
apiKey
path Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: atlas-tours.ma atlas-export.co.ma

Full domain name of one of your domains.

Responses

Response samples

Content type
application/json
{
  • "name": "atlas-tours.ma",
  • "epp_code": "<new code>"
}

Lock or unlock transfers

Turns the registry transfer lock (clientTransferProhibited) on or off. Golzak locks every name after registration and after a transfer in. Unlock it only when the holder is moving the name to another registrar, together with GET /domains/{name}/epp-code; lock it again if the move is abandoned. Synchronous. A name under ANRT examination or expired cannot be changed (domain_status_prohibits).

Authorizations:
apiKey
path Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: atlas-tours.ma atlas-export.co.ma

Full domain name of one of your domains.

header Parameters
Idempotency-Key
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$

Optional on PUT; same rules as on POST. Recommended.

Request Body schema: application/json
required
locked
required
boolean

true locks the name against transfer; false allows a transfer out.

Responses

Request samples

Content type
application/json
{
  • "locked": false
}

Response samples

Content type
application/json
{
  • "name": "atlas-tours.ma",
  • "status": "pending_registration",
  • "registered_at": "2019-08-24",
  • "expires_at": "2019-08-24",
  • "auto_renew": true,
  • "pending_operation_id": "string",
  • "transfer_locked": true,
  • "nameservers": [
    ]
}

Turn automatic renewal on or off

Domains registered or transferred through the API start with auto_renew: false: nothing is ever charged without a call from you. With auto_renew: true, Golzak renews the name for one year shortly before expires_at, at your renew price, paid from your credit. That renewal counts against your account's daily cap for automatic renewals (not a key's cap), appears as an operation with initiator: auto_renew, and is reported by webhook. If credit or cap do not allow it, the operation ends failed and you are told by webhook; renew by hand before expires_at.

Authorizations:
apiKey
path Parameters
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...
Examples: atlas-tours.ma atlas-export.co.ma

Full domain name of one of your domains.

header Parameters
Idempotency-Key
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$

Optional on PUT; same rules as on POST. Recommended.

Request Body schema: application/json
required
enabled
required
boolean

Responses

Request samples

Content type
application/json
{
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "name": "atlas-tours.ma",
  • "status": "pending_registration",
  • "registered_at": "2019-08-24",
  • "expires_at": "2019-08-24",
  • "auto_renew": true,
  • "pending_operation_id": "string",
  • "transfer_locked": true,
  • "nameservers": [
    ]
}

Operations

Follow asynchronous work (registration, renewal, transfer).

Operation event (sent by Golzak to your URL) Webhook

Golzak POSTs this to every webhook endpoint of your account (set on developers.golzak.com, each with its own secret) when an operation changes state. Verify the signature before trusting it:

Golzak-Signature: v1=<hex> where <hex> is HMAC-SHA256(webhook_secret, "<Golzak-Webhook-Timestamp>.<raw body>"). Refuse a timestamp more than 300 seconds from your clock. Compare in constant time.

Answer any 2xx within 10 seconds. Other answers and timeouts are retried with backoff for 24 hours. Deliveries can repeat or arrive out of order: deduplicate on Golzak-Webhook-Id, and trust the operation's updated_at (or re-read GET /operations/{id}).

header Parameters
Golzak-Webhook-Id
required
string <= 255 characters ^[^\u0000-\u001F\u007F]*$

Unique per event; the same on every retry of that event.

Golzak-Webhook-Timestamp
required
string <= 255 characters ^[0-9]{10}$

Unix time (seconds) when this delivery was signed.

Golzak-Signature
required
string <= 255 characters ^v1=[0-9a-f]{64}$

v1= followed by the lower-case hex HMAC-SHA256.

Request Body schema: application/json
required
id
required
string <= 255 characters ^[^\u0000-\u001F\u007F]*$

Same value as the Golzak-Webhook-Id header.

type
required
string <= 255 characters ^[^\u0000-\u001F\u007F]*$
  • operation.pending: the operation entered registry_review (documents required);
  • operation.active, operation.refused, operation.failed: final state.

v1 may add event types: acknowledge (2xx) and ignore a type you do not know.

created_at
required
string <date-time> <= 255 characters
required
object

Responses

Request samples

Content type
application/json
{
  • "id": "evt_01JA7XB2C3D4E5F6G7H8J9K0LM",
  • "type": "operation.active",
  • "created_at": "2026-10-09T08:00:00Z",
  • "data": {
    }
}

Read an operation

The current state of an operation returned by a POST, or created by an automatic renewal. Poll it when you missed a webhook; once a minute at most, once an hour during registry_review.

Authorizations:
apiKey
path Parameters
id
required
string <= 255 characters ^op_[0-9A-Z]{26}$

Operation ID returned by a POST.

Responses

Response samples

Content type
application/json
Example
{
  • "id": "op_01JA7X3M9Q2W8E5R6T7Y8U9I0P",
  • "type": "register",
  • "initiator": "api",
  • "status": "pending",
  • "pending_reason": "registry_review",
  • "domain": "atlas-tours.ma",
  • "years": 1,
  • "charge": {
    },
  • "refund": null,
  • "documents_required": true,
  • "documents_deadline": null,
  • "error": null,
  • "created_at": "2026-10-08T09:00:00Z",
  • "updated_at": "2026-10-08T09:01:10Z",
  • "completed_at": null
}

Transfers

Move a .ma name from another registrar to Golzak.

Transfer a domain in (asynchronous)

Transfers name from another registrar to Golzak with the EPP code the holder got from the current registrar. Your transfer price is read live from your client group, like every other price (GET /prices). Credit and daily cap are checked first. Returns an operation that ends active (the name is in your account) or failed (charge returned to your credit).

Timing (ANRT decision 02/2024 art. 35): the current registrar has two business days to accept or oppose; without an answer the transfer completes automatically. If ANRT has to decide an opposition it takes up to three more business days. Before ordering, make sure the name is unlocked at the current registrar. If the transfer has not completed 10 business days after the request, the operation ends failed with transfer_not_completed and the charge is returned.

Authorizations:
apiKey
query Parameters
dry_run
boolean
Default: false

true runs every check and returns the would-be charge; nothing is ordered.

header Parameters
Idempotency-Key
required
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$
Example: 0b8c7f0e-6a39-4b8f-9a0e-2f5d7c1e9a41

Required on every POST. A unique value per intended action (a UUID v4 is ideal). Retrying with the same key and the same body returns the first answer with Idempotent-Replayed: true and orders nothing new. The same key with a different body answers idempotency_key_reused. Keys are kept for 24 hours.

Request Body schema: application/json
required
name
required
string (DomainNameInput) [ 4 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0...

A lower-case ASCII host name (letters, digits, hyphens, dots). The API then checks the extension and answers 422 tld_manual_only or 422 tld_not_supported when it is not accepted, and 400 invalid_domain_name when it is not exactly one label plus an accepted extension (e.g. a.b.ma, or a bare co.ma, net.ma, org.ma, gov.ma, ac.ma, press.ma, refused as names by Golzak policy).

epp_code
required
string [ 1 .. 255 ] characters ^[^\u0000-\u001F\u007F]*$

Transfer code (EPP auth code) from the current registrar.

nameservers
Array of strings (Nameservers) [ 2 .. 5 ] items unique [ items [ 3 .. 253 ] characters ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]... ]

2 to 5 distinct nameserver host names (Golzak API rule).

Responses

Request samples

Content type
application/json
{
  • "name": "atlas-tours.ma",
  • "epp_code": "<code from the current registrar>"
}

Response samples

Content type
application/json
{
  • "dry_run": true,
  • "would_charge": {
    },
  • "credit_after": {
    }
}