API Docs / Hosting Partner API

Hosting Partner API

The Hosting Partner API lets resellers provision mailboxes and domains for their own clients programmatically — the same actions available in the Partner dashboard, just callable from your own systems. Requires an approved, active or trial Hosting Partner account.

Apply for a hosting partner account, then create API keys from Partner Dashboard → Developer. Every request needs one client domain added and verified before you can provision a mailbox on it — see Domains below.

Authentication

Include your API key in the X-API-Key header on every request:

X-API-Key: ker_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Scopes

Each key is created with one or more scopes. A request 403s if the key is missing a scope it needs — read-only integrations should only request :read scopes.

ScopeGrants
partner:mailboxes:readList mailboxes
partner:mailboxes:writeCreate, delete, and renew mailboxes
partner:domains:readList domains and check verification status
partner:domains:writeAdd, verify, and delete domains
partner:addons:readRead add-on pricing and purchase status
partner:addons:writePurchase domain-slot and storage add-ons
partner:stats:readRead aggregate stats and account summary
partner:settings:writeChange account-wide settings (e.g. the default client lapse policy)

IP restrictions

Optionally lock a key down to specific source IPs (or CIDR ranges) when you create it. Both an allowlist and a blocklist can be set at once — the blocklist is checked first, so an IP that matches both is denied.

  • allowed_ips — if set, only these IPs/CIDRs may use the key (everyone else gets 403). Leave unset to allow any IP.
  • blocked_ips — these IPs/CIDRs are always rejected, even if also present in the allowlist.
POST https://api.kerabie.email/api-keys
{
  "name": "Reseller panel integration",
  "scopes": ["partner:mailboxes:write", "partner:domains:read"],
  "allowed_ips": ["203.0.113.0/24"],
  "blocked_ips": ["198.51.100.0/24"]
}

Mailboxes

POSThttps://api.kerabie.email/v1/hosting/mailboxes
Provision a mailbox for a client. The domain must already be added and verified (see Domains below) — this fails with 400 otherwise.
ParameterTypeRequiredDescription
domain_idintegerrequiredID of one of your verified domains
local_partstringrequiredPart before the @ — full address is local_part@domain
passwordstringrequiredInitial mailbox password (min 8 chars)
display_namestringoptionalFriendly name shown in email clients
plan_idstringrequired"pro" (5GB) or "premium" (20GB) — drives the wholesale rate and storage tier
funding_modestringoptional"slot" (default, draws from your prepaid pool/trial) or "pay_as_you_go" — see the Pay-as-you-go section below
return_urlstringoptionalRequired when funding_mode="pay_as_you_go" — where the client's Bachs checkout redirects after payment

Request

{
  "domain_id": 3,
  "local_part": "john",
  "password": "SecurePass123!",
  "display_name": "John Smith",
  "plan_id": "premium"
}

Response 201

{
  "id": 42,
  "email_address": "john@yourclientdomain.com",
  "domain": "yourclientdomain.com",
  "plan_type": "premium",
  "status": "active",
  "is_trial": false,
  "monthly_rate_usd": 6.0,
  "monthly_rate_ngn": 4500.0,
  "expires_at": "2026-08-23T18:17:16Z",
  "mailu_provisioned": true,
  "created_at": "2026-07-23T18:17:12Z"
}
GEThttps://api.kerabie.email/v1/hosting/mailboxes
List mailboxes provisioned under your account.
ParameterTypeRequiredDescription
statusstringoptionalFilter by status: trial | active | expired | suspended
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}
Permanently delete a mailbox and all its email. A prepaid slot already consumed by this mailbox is forfeited, not refunded.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/renew
Consume one unused slot from your pool to extend a mailbox whose term has ended (or is ending soon), and re-enable it if it was disabled.

Domains

A client's domain has to be added and pass DNS verification before you can provision mailboxes on it — this proves you (or your client) actually control that domain's DNS, and confirms mail sent to it will actually reach Kerabie's mail servers. New accounts get 2 free domain slots; buy more via the add-ons endpoint.

POSThttps://api.kerabie.email/v1/hosting/domains
Claim a client domain. Returns the DNS records to configure — the domain isn't usable until it's verified.
ParameterTypeRequiredDescription
domain_namestringrequiredDomain name (e.g. yourclientdomain.com)
client_idintegeroptionalAttach to an existing client (see Clients below) — omit to auto-create a new one named after the domain

Response 201

{
  "id": 3,
  "domain_name": "yourclientdomain.com",
  "status": "pending",
  "is_verified": false,
  "mailu_added": false,
  "dns_records": [
    { "type": "MX",  "host": "@", "value": "10 mail.kerabie.email",
      "description": "Routes incoming mail for this domain to Kerabie's mail servers.",
      "ok": null, "found_value": null, "reason": null },
    { "type": "TXT", "host": "@", "value": "kerabie-verify=5kMm7kfncTQfgIx7lSOuLBU9",
      "description": "Proves you control this domain's DNS.",
      "ok": null, "found_value": null, "reason": null },
    { "type": "TXT", "host": "@", "value": "v=spf1 mx include:relay.kerabie.email ~all",
      "description": "Authorizes Kerabie's mail servers to send email for this domain.",
      "ok": null, "found_value": null, "reason": null },
    { "type": "TXT", "host": "_dmarc", "value": "v=DMARC1; p=none; rua=mailto:dmarc@kerabie.email",
      "description": "Protects this domain from spoofing and improves deliverability.",
      "ok": null, "found_value": null, "reason": null },
    { "type": "TXT", "host": "dkim._domainkey", "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkq...",
      "description": "Enables cryptographic signing (DKIM) of outgoing messages to improve delivery.",
      "ok": null, "found_value": null, "reason": null }
  ]
}

The DKIM TXT record is generated natively by Mailu the first time the domain is added, and cached. ok/found_value/reason are always null here — nothing has been checked yet. They're populated by the verify call below.

GEThttps://api.kerabie.email/v1/hosting/domains
List all domains claimed under your account, with DNS records (and their last check result) for any that still need attention.
GEThttps://api.kerabie.email/v1/hosting/domains/{id}
Check a single domain's status — the intended target for polling while waiting on DNS propagation.
POSThttps://api.kerabie.email/v1/hosting/domains/{id}/verify
Re-check DNS now — every call, not just while still pending, since verifying only requires MX + the ownership TXT token but SPF/DMARC/DKIM are checked and reported too and can still be wrong on an already-verified domain. On success, the domain is registered in Mailu and ready for mailboxes. A partner_domain.verified or partner_domain.verification_failed webhook fires on the first state change.

Response 200 — some records still wrong

A real example: 4 of 5 records were configured correctly, but the domain's registrar (Namecheap) had its own Email Forwarding feature still overriding the MX record.reason names the specific problem instead of a generic "not verified" — this is the whole reason these three fields exist.

{
  "id": 3,
  "domain_name": "yourclientdomain.com",
  "status": "failed",
  "is_verified": false,
  "dns_records": [
    { "type": "MX", "host": "@", "value": "10 mail.kerabie.email",
      "ok": false, "found_value": "10 eforward2.registrar-servers.com",
      "reason": "Found eforward2.registrar-servers.com instead of mail.kerabie.email — looks like Namecheap Email Forwarding is still enabled for this domain. Disable it (or make sure Custom MX is the selected mail-handling mode) so this record actually takes effect." },
    { "type": "TXT", "host": "@", "value": "kerabie-verify=...",
      "ok": true, "found_value": "kerabie-verify=...", "reason": null },
    { "type": "TXT", "host": "@", "value": "v=spf1 mx include:relay.kerabie.email ~all",
      "ok": true, "found_value": "v=spf1 mx include:relay.kerabie.email ~all", "reason": null },
    { "type": "TXT", "host": "_dmarc", "value": "v=DMARC1; p=none; ...",
      "ok": true, "found_value": "v=DMARC1; p=none; ...", "reason": null },
    { "type": "TXT", "host": "dkim._domainkey", "value": "v=DKIM1; k=rsa; p=...",
      "ok": true, "found_value": "v=DKIM1; k=rsa; p=...", "reason": null }
  ]
}

Response 200 — verified

{
  "id": 3,
  "domain_name": "yourclientdomain.com",
  "status": "verified",
  "is_verified": true,
  "mailu_added": true,
  "verified_at": "2026-07-23T18:15:05Z",
  "dns_records": null
}

dns_records goes back to null once every record checks out — it's non-null whenever there's something worth showing: still pending, or verified but with an SPF/DMARC/DKIM record still wrong (verification itself only requires MX + the ownership token).

DELETEhttps://api.kerabie.email/v1/hosting/domains/{id}
Remove a domain. Fails with 409 if any mailboxes still use it — delete those first.

Clients

A client is your real-world customer — the entity a domain (and, through it, every mailbox provisioned on that domain) belongs to. One client can own several domains. Every domain is attached to exactly one client; adding a domain without a client_id auto-creates a new single-domain client named after it, so you never have to think about this if you don't need the grouping. Each client also carries its own optional lapse_action_override, which takes priority over your account-wide default (see Settings below) for what happens when one of that client's mailboxes lapses.

GEThttps://api.kerabie.email/v1/hosting/clients
List your clients, each with its domain/mailbox counts and resolved lapse override.
POSThttps://api.kerabie.email/v1/hosting/clients
Create a client.
ParameterTypeRequiredDescription
namestringrequiredDisplay name, e.g. "Acme Corp"

Response 201

{
  "id": 7,
  "name": "Acme Corp",
  "lapse_action_override": null,
  "domain_count": 0,
  "mailbox_count": 0,
  "created_at": "2026-09-22T10:00:00Z"
}
PATCHhttps://api.kerabie.email/v1/hosting/clients/{id}
Rename a client and/or set its lapse policy override.
ParameterTypeRequiredDescription
namestringoptionalNew display name
lapse_action_overridestringoptional"suspend" | "downgrade_free" | null — null clears the override, falling back to your account default
DELETEhttps://api.kerabie.email/v1/hosting/clients/{id}
Remove a client. Fails with 409 if any domains still belong to it — reassign or delete those first.

Settings

Account-wide hosting settings. Today this is just the default lapse policy — what happens to a client's mailbox when its trial/prepaid term ends, or a pay-as-you-go payment fails: suspend locks it out entirely (the only behavior before this setting existed), while downgrade_free keeps it reachable on the Free plan instead. A client's own lapse_action_override (see Clients above) takes priority over this default.

PATCHhttps://api.kerabie.email/v1/hosting/settings
Set your account-wide default lapse policy.
ParameterTypeRequiredDescription
default_client_lapse_actionstringrequired"suspend" or "downgrade_free"

Request

{ "default_client_lapse_action": "downgrade_free" }

White-labeling

An active or trial hosting account can replace Kerabie's own name, logo, and colors with your own — shown on the sign-in page, the logged-in sidebar, and the browser tab icon. It only ever appears on your own custom webmail domain (below); logging in via the shared webmail.kerabie.email always shows plain Kerabie branding, even for your own clients.

Both of these are managed from the dashboard (Settings → Branding and Hosting → Webmail Domain) rather than the API-key surface documented elsewhere on this page — they read from your logged-in session, not an X-API-Key.

Custom webmail domain

Pick a hostname you control — e.g. webmail.yourbrand.com — and point it at Kerabie with a single CNAME record:

CNAME  webmail.yourbrand.com  →  webmail.kerabie.email

Only one domain per account at a time — remove the existing one before adding a replacement. Once DNS resolves correctly the domain flips to verified automatically (checked on a short poll, or immediately via a manual re-check) and a TLS certificate is issued the first time it's actually visited over HTTPS — nothing further to configure.

Branding

Four fields, all optional and independently settable:

  • Brand name — replaces "Kerabie WebMail" throughout.
  • Logo — a public image URL (upload one from the dashboard and it fills this in for you).
  • Primary / secondary color — a hex color (#7c3aed) or a CSS gradient (linear-gradient(90deg, #7c3aed, #db2777)). Primary drives buttons and accents; secondary is optional and used where a second tone is needed.

Saving branding requires the custom domain condition above (an active/trial hosting account) — attempting to save on a pending or expired account returns 403.

Pay-as-you-go mailboxes

An alternative to buying mailbox slots upfront: the client pays Kerabie directly, on a recurring monthly basis, at a retail price you set — you never pay anything upfront, and instead earn the markup over Kerabie's wholesale rate as a revenue share, credited to your payout balance (GET/POST /partners/me/payouts — same balance and withdrawal flow referral commissions use).

Currently USD and NGN only (matching the rest of the platform's billing), and monthly billing only — the multi-cycle terms (yearly/biennial/triennial) that the prepaid slot pool supports don't apply here.

1. Set your retail price

GEThttps://api.kerabie.email/v1/hosting/retail-pricing
Your current retail price per plan tier/currency, plus the wholesale floor (Kerabie's own cost) for each — retail_price is null until you've set one.
PUThttps://api.kerabie.email/v1/hosting/retail-pricing
Set (or change) your retail price for one plan tier/currency. Rejected with 400 if below the wholesale floor. Creates or updates a real recurring billing product behind the scenes — takes a moment the first time.
ParameterTypeRequiredDescription
plan_typestringrequired"pro" or "premium"
currencystringrequired"usd" or "ngn"
retail_pricenumberrequiredMust be ≥ the wholesale rate for this tier/currency

Request

{ "plan_type": "pro", "currency": "usd", "retail_price": 5.00 }

2. Provision with funding_mode="pay_as_you_go"

Same POST /v1/hosting/mailboxes call as any mailbox (see Mailboxes above), with funding_mode: "pay_as_you_go" and a return_url. A retail price must already be set for that plan tier/currency (step 1) or this 400s. The mailbox account is created immediately — the client can see it's ready — but stays disabled and status: "pending_payment" until payment clears. The response includes a checkout_url: send this to your client to complete.

Response 201

{
  "id": 8,
  "email_address": "client@yourclientdomain.com",
  "status": "pending_payment",
  "is_pay_as_you_go": true,
  "checkout_url": "https://checkout.bachs.io/c/6a5wgGmDy7coMgg"
}

3. Get notified when payment clears

Kerabie handles all recurring billing and dunning — you never see a checkout flow or a raw payment status. Instead, listen for these webhook events (see Webhooks below for signature verification):

EventFires when
partner_mailbox.payment_confirmedThe client's payment clears — the mailbox is (re-)enabled. Fires on the FIRST payment and on every monthly renewal, not just once.
partner_mailbox.payment_failedA renewal charge fails — the mailbox is disabled until it's paid (Kerabie runs the retry/dunning schedule).
partner_mailbox.expiredThe client cancels — the mailbox is disabled and marked expired.
partner_mailbox.payment_abandonedThe client never completed the FIRST payment and the 7-day grace period (below) ran out — the mailbox and its account are gone, not just disabled.

Use partner_mailbox.payment_confirmed to verify a client actually paid — don't rely on the browser reaching your return_url alone, since a client can close the tab before the redirect, or the checkout page can be revisited without a real payment.

4. Polling, as an alternative to webhooks

If you'd rather poll than expose a webhook receiver, GET /v1/hosting/mailboxes/{id} returns the same status a webhook would tell you about, and — while status is still "pending_payment" — re-returns the same checkout_url from step 2, in case the client lost the link before you had a chance to save it.

GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}
Current status of a single mailbox. checkout_url is only populated while status is pending_payment; null once paid.

5. Unpaid mailboxes expire automatically

A client who never completes the first payment isn't left provisioned forever: if status is still "pending_payment" 7 days after creation, Kerabie deletes the mailbox and the account behind it automatically and fires partner_mailbox.payment_abandoned. Nothing real ever activated on that account, so there's no customer data to preserve.

This is also why DELETE /v1/hosting/mailboxes/{id} behaves differently depending on whether the mailbox ever got paid: deleting a mailbox that's still "pending_payment" deletes the underlying account too, same as the automatic 7-day cleanup — there's nothing to keep. Deleting any other mailbox (already active, whether pay-as-you-go or slot-funded) only deactivates the account and removes the mailbox/slot; the account's data (subscription, mail, forwarding rules) is left intact in case it needs to be looked up later.

6. Manage a client's subscription

Once a pay-as-you-go mailbox is active, you can check its billing status, cancel it, move the client to a different plan tier, or sell them an add-on — all without them ever needing to log in anywhere themselves. These only work for is_pay_as_you_go: true mailboxes; calling any of them on a slot-funded mailbox returns 400 — manage those with renew/DELETE instead.

GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/subscription
Live billing status for one mailbox's underlying subscription — plan, price, current period, next renewal date, auto_renew.

Response 200

{
  "mailbox_id": 8,
  "plan_type": "premium",
  "billing_cycle": "monthly",
  "status": "active",
  "currency": "usd",
  "total_price": 6.0,
  "current_period_start": "2026-09-05",
  "current_period_end": "2026-10-05",
  "next_billing_date": "2026-10-05",
  "auto_renew": true,
  "payment_provider": "bachs"
}
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/cancel-subscription
Stop future charges for this client — at the end of the current period by default, or immediately. Doesn't delete the mailbox itself; call DELETE /mailboxes/{id} separately if you want that too.
ParameterTypeRequiredDescription
immediatebooleanoptionalCancel right away instead of at period end (default false)
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/upgrade
Move the client to a different plan tier (pro <-> premium), billed at YOUR retail price for that tier — never Kerabie's standard price. Requires a retail price already set for the target plan/currency (step 1) or this 400s.
ParameterTypeRequiredDescription
new_plan_typestringrequired"pro" or "premium" — must differ from the mailbox's current plan
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/addons/purchase
Sell the client an extra mailbox or extra storage add-on, at Kerabie's standard add-on price (add-ons sit outside your retail pricing). Returns a checkout URL for the client to pay — same pattern as step 2's mailbox checkout.
ParameterTypeRequiredDescription
typestringrequired"extra_mailbox" or "extra_storage"
quantityintegeroptionalDefault 1
return_urlstringrequiredWhere the client's checkout redirects after payment

Response 200

{
  "payment_method_id": 91,
  "checkout_url": "https://checkout.bachs.io/c/9fK2mQwLp0aXcRt",
  "status": "pending_payment"
}

Mailbox management

The full toolset a client would get if they ever logged into Kerabie directly — forwarding rules, aliases, signature/sender name, contacts, and campaigns — all available on their behalf through your own systems, since there's no end-customer self-service portal. Every endpoint below takes the mailbox's id from Mailboxes above.

Forwarding

GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/forwarding
List forwarding rules on this mailbox.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/forwarding
Create a forwarding rule. Only one active rule per mailbox — delete the existing one first. The destination address gets a confirmation email; mail doesn't actually forward until they confirm it.
ParameterTypeRequiredDescription
emailstringrequiredThe mailbox to forward from (must be this mailbox's address)
forward_tostringrequiredDestination email address
keep_copybooleanoptionalKeep a copy in the original mailbox too (default true)
PATCHhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/forwarding/{rule_id}
Pause or resume a rule without deleting it.
ParameterTypeRequiredDescription
enabledbooleanrequiredMail only actually forwards while enabled AND confirmed
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/forwarding/{rule_id}
Remove a forwarding rule.

Aliases

GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/aliases
List aliases delivering to this mailbox. Paginated.
ParameterTypeRequiredDescription
pageintegeroptionalDefault 1
page_sizeintegeroptionalDefault 20, max 100
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/aliases
Create an alias address that delivers to this mailbox.
ParameterTypeRequiredDescription
mailboxstringrequiredThis mailbox's address (the delivery target)
alias_addressstringrequiredThe new alias address
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/aliases/{alias_id}
Remove an alias.

Signature & sender name

PATCHhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/identity
Update the mailbox's sender display name and/or HTML signature. Omit a field to leave it unchanged.
ParameterTypeRequiredDescription
display_namestringoptionalName shown to recipients
signature_htmlstringoptionalHTML signature appended to outgoing mail

Contacts

Requires the client's plan to include contacts (Pro and Premium both do) — 403s otherwise. Contacts belong to the client's account as a whole, not a specific mailbox.

GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts
List/search contacts.
ParameterTypeRequiredDescription
group_idintegeroptionalFilter to one group
qstringoptionalSearch email, name, or company
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts
Create a contact.
ParameterTypeRequiredDescription
emailstringrequired
namestringoptional
phonestringoptional
companystringoptional
notesstringoptional
group_idintegeroptional
PATCHhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts/{contact_id}
Update a contact. Same fields as create, all optional.
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts/{contact_id}
Delete a contact.
GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts/groups
List contact groups.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts/groups
Create a contact group.
ParameterTypeRequiredDescription
namestringrequired
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/contacts/groups/{group_id}
Delete a contact group.

Campaigns

Requires the client's plan to include campaigns (Pro and Premium both do) — 403s otherwise. A campaign starts as a single-step send; add more steps to turn it into a drip sequence.

GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns
List campaigns.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns
Create a campaign (starts in draft status, with one step already set from subject/body_html).
ParameterTypeRequiredDescription
from_emailstringrequiredMust be this mailbox's address
namestringrequiredInternal campaign name
subjectstringrequired
body_htmlstringrequired
group_idintegeroptionalSend to one contact group
segment_filterarrayoptionalOr send to a filtered segment — see the dashboard for the filter shape
GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}
Get one campaign.
PUThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}
Edit a draft campaign. 400s once it's left draft status.
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}
Delete a campaign. 400s while it's actively sending or paused.
GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/steps
List drip steps.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/steps
Add a drip step to a draft campaign.
ParameterTypeRequiredDescription
delay_hoursintegeroptionalHours after the previous step (default 0)
subjectstringrequired
subject_bstringoptionalA/B variant subject
ab_split_percentintegeroptional0-100, default 50
body_htmlstringrequired
DELETEhttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/steps/{step_id}
Remove a drip step. Step 0 can't be deleted — edit the campaign's subject/body instead.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/send
Start sending a draft campaign. 429s if the recipient count exceeds today's remaining send quota on this mailbox.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/pause
Pause a campaign that's currently sending.
POSThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/resume
Resume a paused campaign.
GEThttps://api.kerabie.email/v1/hosting/mailboxes/{id}/campaigns/{campaign_id}/stats
Send stats: total, sent, suppressed, opened, clicked, bounced.

Add-ons

Two purchasable add-ons, billed once via Flutterwave (card or, for NGN accounts, direct bank transfer): extra domain slots, and extra per-mailbox storage. Mailbox count is a separate thing — see the slot pool purchase flow in the Partner dashboard.

GEThttps://api.kerabie.email/v1/hosting/addons/pricing
Current unit prices in your account's currency, plus your current domain limit/usage and storage bonus.
{
  "currency_code": "NGN",
  "domain_slot_unit_price": 4000.0,
  "storage_gb_unit_price": 800.0,
  "domain_limit": 2,
  "domains_used": 1,
  "extra_storage_mb": 0
}
POSThttps://api.kerabie.email/v1/hosting/addons/purchase
Buy N domain slots or N GB of extra storage. Returns a checkout URL (card) or a bank account to transfer to (bank_transfer, NGN only). The add-on activates once payment confirms — poll the verify endpoint below, or subscribe to partner_addon.purchased.
ParameterTypeRequiredDescription
addon_typestringrequired"domain_slot" or "storage"
quantityintegerrequiredNumber of slots (domain_slot) or GB (storage)
payment_methodstringoptional"card" (default) or "bank_transfer"
return_urlstringrequiredWhere the card checkout redirects back to
POSThttps://api.kerabie.email/v1/hosting/addons/purchase/verify
Fallback check if a webhook hasn't landed yet — pass the purchase reference to re-check payment status directly.
ParameterTypeRequiredDescription
referencestringrequiredThe reference returned from the purchase call

Stats

GEThttps://api.kerabie.email/v1/hosting/stats
Aggregate counts for dashboards — also surfaces DNS setup records for any domain still waiting on verification.
{
  "mailboxes_total": 12,
  "mailboxes_by_status": { "active": 10, "expired": 2 },
  "mailboxes_by_plan": { "pro": 8, "premium": 4 },
  "slots_unused": 3,
  "slots_assigned": 10,
  "slots_expired": 2,
  "domains_total": 4,
  "domains_verified": 3,
  "domains_pending": 1,
  "domain_limit": 5,
  "extra_storage_mb": 2048,
  "pending_domain_setup": [
    { "domain_id": 7, "domain_name": "pending-client.com", "status": "pending", "dns_records": [ /* ... */ ] }
  ]
}
GEThttps://api.kerabie.email/v1/hosting/summary
Trial status, wholesale plan rates, and unused-slot count — the same data the dashboard overview page shows.

Webhooks

Hosting-partner events use the exact same delivery mechanism as the rest of the platform — HMAC-SHA256 signed, retried with exponential backoff. See the Webhooks docs for signature verification code and the retry schedule. Create endpoints from Partner Dashboard → Developer or POST /webhooks.

EventTriggered when
partner_mailbox.createdA mailbox is provisioned (dashboard or API)
partner_mailbox.deletedA mailbox is deleted
partner_mailbox.renewedA mailbox's term is renewed
partner_mailbox.expiring_soonA paid mailbox's term ends in ~7 days
partner_domain.addedA client domain is claimed
partner_domain.verifiedA domain passes DNS verification (first time only)
partner_domain.verification_failedA verification check fails
partner_pool.purchasedA mailbox-slot pool purchase completes
partner_addon.purchasedA domain-slot or storage add-on purchase completes
partner_trial.expiring_soonYour hosting trial ends in ~7 days
partner_mailbox.payment_confirmedA pay-as-you-go client's payment clears (first payment or any renewal)
partner_mailbox.payment_failedA pay-as-you-go client's renewal charge fails
partner_mailbox.expiredA pay-as-you-go client cancels
partner_mailbox.payment_abandonedA pay-as-you-go mailbox's first payment was never completed within 7 days — it and its account were deleted

Errors

CodeMeaning
400Bad request — e.g. invalid domain name, or provisioning on an unverified domain
401Missing, invalid, revoked, or expired API key
402Payment required — no mailbox slots, or domain limit reached
403IP blocked/not allowlisted for this key, missing scope, or hosting account not active/trial
404Resource not found (or not yours)
409Domain already claimed, mailbox already exists, or domain still has mailboxes on it