HelipodDocs

Plan and add-ons

Read the project's email plan, renew or change it, and buy extra mailboxes and inbox storage.

Every project's email service runs on a plan (Free, Starter, Pro, Business). An API key can read the plan, renew it, change it, and set the inbox add-ons. Purchases are paid from your Helipod wallet, like in the dashboard.

Two rules for purchases with a key

  • Every paid call accepts ?dryRun=true: nothing is charged, the response shows the price and your wallet after it.
  • The real call needs an Idempotency-Key header (8 to 128 characters: letters, digits, _ . : -). A retry with the same value returns the first answer instead of charging again. Without it the call answers 400 IDEMPOTENCY_KEY_REQUIRED.

Without an active plan (the Free plan counts), a key can still read the status and the plan, and buy or renew one; every other route answers 402 NO_PLAN until then. A Helipod API key or an AI tool signed in with the Email API can do this even for a project that has no email yet: buying a plan then also sets email up (see Buy a plan). Cancelling a plan, the auto-renew and pay-as-you-go switches and email API keys stay in the dashboard: those routes answer 403 KEY_NOT_ALLOWED to a key.

Plans

GET/plans
The plan catalogue with prices and limits. Needs no key.
curl https://mail.helipod.io/api/email/plans

Each plan has a code (FREE, STARTER, PRO, BUSINESS), a monthly price in IDR, the discounts for longer cycles (discount3month, discount6month, yearlyDiscount, in percent; 0 means the cycle is not offered) and its limits.

Current plan

GET/plan
The project's active plan and subscription.
curl https://mail.helipod.io/api/email/plan \
  -H "Authorization: Bearer your_email_api_key"
{
  "success": true,
  "data": {
    "plan": { "code": "STARTER", "name": "Starter", "price": "29400.00", "limits": { "dailySendLimit": 0, "monthlySendLimit": 2500, "maxDomains": 2 } },
    "subscription": {
      "status": "active",
      "startedAt": "2026-10-01T03:00:00.000Z",
      "expiredAt": "2026-11-01T03:00:00.000Z",
      "code": "STARTER",
      "billingMonths": 1,
      "extraMailboxes": 0,
      "extraStorageGb": 0
    }
  }
}

plan and subscription are null when the project has no active plan. The limits object is shortened here.

Renew

POST/plan/renewcharges your walletdryRunIdempotency-Key
Extend the active plan by another cycle.

Prop

Type

curl -X POST "https://mail.helipod.io/api/email/plan/renew?dryRun=true" \
  -H "Authorization: Bearer your_email_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "months": 3 }'
{
  "success": true,
  "data": {
    "dryRun": true,
    "action": "renew",
    "mode": "extend",
    "planCode": "STARTER",
    "months": 3,
    "charge": "83790.00",
    "expiredAt": "2027-02-01T03:00:00.000Z",
    "currency": "IDR",
    "walletBalance": "500000.00",
    "walletBalanceAfter": "416210.00",
    "enoughBalance": true
  }
}

The new cycle starts when the current one ends; expiredAt is the new end date. Then send the same request without dryRun and with an Idempotency-Key:

curl -X POST https://mail.helipod.io/api/email/plan/renew \
  -H "Authorization: Bearer your_email_api_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: email-renew-2026-10-a1b2" \
  -d '{ "months": 3 }'

The response is { "activated": true, "charged": "83790.00", "extended": true, "subscription": { ... } } with the new expiredAt in subscription. Renewing into another plan answers 409 PLAN_ACTIVE: use change instead.

Change plan

POST/plan/changecharges your walletdryRunIdempotency-Key
Move to a larger or smaller plan.

Prop

Type

  • A larger plan applies at once. You pay the difference for the rest of the current cycle; the end date stays the same. The dry run answers mode: "immediate" with the charge.
  • A smaller plan is scheduled for the next cycle and costs nothing now. The dry run answers mode: "scheduled" with effectiveAt.
  • The plan must fit what the project already uses, for example its number of domains.

A paid change answers 200, a scheduled one 201.

Buy a plan

POST/plancharges your walletdryRunIdempotency-Key
Buy a plan for the project.

Prop

Type

While a plan is active, buying the same plan changes nothing (mode: "already_active" in a dry run) and buying another one answers 409 PLAN_ACTIVE or 409 DOWNGRADE_NOT_ALLOWED: use change. A paid purchase answers 200, a free activation 201.

With a Helipod API key (or an AI tool signed in) for a project that has no email yet, the purchase also sets email up for it, and the response adds setup: { configSetId, alreadyActive, jobId }. Setup finishes in the background; then add a sending domain. If setup fails, the plan stays bought and setup holds { code, error }: retry with POST /setup.

Inbox add-ons

POST/plan/addonscharges your walletdryRunIdempotency-Key
Set the number of extra mailboxes and extra inbox storage.

Prop

Type

curl -X POST "https://mail.helipod.io/api/email/plan/addons?dryRun=true" \
  -H "Authorization: Bearer your_email_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "extraMailboxes": 2, "extraStorageGb": 5 }'
{
  "success": true,
  "data": {
    "extraMailboxes": 2,
    "extraStorageGb": 5,
    "charge": "18000.00",
    "remainingDays": 15,
    "monthlyAfter": "36000.00",
    "expiredAt": "2026-11-01T03:00:00.000Z",
    "dryRun": true,
    "currency": "IDR",
    "walletBalance": "500000.00",
    "walletBalanceAfter": "482000.00",
    "enoughBalance": true
  }
}
  • An increase is charged now, pro rata to the end of the current cycle (charge), and then renews with the plan (monthlyAfter per month).
  • A decrease costs nothing and is refused while you use more than is left (409 ADDON_IN_USE): delete a mailbox or some mail first.
  • Add-ons need a plan that includes receiving (402 PLAN_REQUIRED on the Free plan).

Errors

CodeStatusMeaning
IDEMPOTENCY_KEY_REQUIRED400A purchase with a key was sent without an Idempotency-Key header.
REQUEST_IN_PROGRESS409A request with the same Idempotency-Key is still running.
PLAN_REQUIRED400 / 402planCode is missing (400), or add-ons on a plan without receiving (402).
PLAN_NOT_FOUND404No plan with this code.
NO_PLAN404No plan to renew or change.
PLAN_ACTIVE409Another plan is active: use change.
DOWNGRADE_NOT_ALLOWED409A smaller plan can't be bought while a larger one is active: use change to schedule it.
ADDON_IN_USE409The add-ons can't go below what is in use.
INSUFFICIENT_BALANCE402The wallet can't cover the charge. Nothing is charged.
KEY_NOT_ALLOWED403The route stays in the dashboard.

On this page