AhaSend Sub Accounts API
Provision and manage isolated sub accounts under a parent account, their API keys, and their usage.
Provision and manage isolated sub accounts under a parent account, their API keys, and their usage.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/ahasend-sub-accounts-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
openapi: 3.2.0
info:
title: AhaSend API v2 Accounts Sub Accounts API
description: "The AhaSend API v2 allows you to send transactional emails, manage domains, webhooks, routes, API keys, and\
\ view statistics.\n\n## Authentication\nAll API requests must be authenticated using a Bearer token in the Authorization\
\ header:\n```\nAuthorization: Bearer aha-sk-64-CHARACTER-RANDOM-STRING\n```\n\n## Scopes\nAPI keys have specific scopes\
\ that control access to different resources and actions:\n\n### Message Scopes\n- `messages:send:all` - Send messages\
\ from any domain in the account\n- `messages:send:{domain}` - Send messages from a specific domain\n- `messages:cancel:all`\
\ - Cancel messages from any domain\n- `messages:cancel:{domain}` - Cancel messages from a specific domain\n- `messages:read:all`\
\ - Read messages from any domain\n- `messages:read:{domain}` - Read messages from a specific domain\n\n### Domain Scopes\n\
- `domains:read` - Read all domains\n- `domains:write` - Create and update domains\n- `domains:delete:all` - Delete any\
\ domain\n- `domains:delete:{domain}` - Delete a specific domain\n\n### Account Scopes\n- `accounts:read` - Read account\
\ information\n- `accounts:write` - Update account settings\n- `accounts:billing` - Access billing information\n- `accounts:members:read`\
\ - Read account members\n- `accounts:members:add` - Add account members\n- `accounts:members:update` - Update account\
\ members\n- `accounts:members:remove` - Remove account members\n\n### Webhook Scopes\n- `webhooks:read:all` - Read all\
\ webhooks\n- `webhooks:read:{domain}` - Read webhooks for a specific domain\n- `webhooks:write:all` - Create and update\
\ webhooks\n- `webhooks:write:{domain}` - Create and update webhooks for a specific domain\n- `webhooks:delete:all` -\
\ Delete any webhook\n- `webhooks:delete:{domain}` - Delete webhooks for a specific domain\n\n### Route Scopes\n- `routes:read:all`\
\ - Read all routes\n- `routes:read:{domain}` - Read routes for a specific domain\n- `routes:write:all` - Create and update\
\ routes\n- `routes:write:{domain}` - Create and update routes for a specific domain\n- `routes:delete:all` - Delete any\
\ route\n- `routes:delete:{domain}` - Delete routes for a specific domain\n\n### Suppression Scopes\n- `suppressions:read`\
\ - Read suppressions\n- `suppressions:write` - Create suppressions\n- `suppressions:delete` - Delete suppressions\n-\
\ `suppressions:wipe` - Delete all suppressions (dangerous)\n\n### SMTP Credentials Scopes\n- `smtp-credentials:read:all`\
\ - Read all SMTP credentials\n- `smtp-credentials:read:{domain}` - Read SMTP credentials for a specific domain\n- `smtp-credentials:write:all`\
\ - Create SMTP credentials\n- `smtp-credentials:write:{domain}` - Create SMTP credentials for a specific domain\n- `smtp-credentials:delete:all`\
\ - Delete any SMTP credentials\n- `smtp-credentials:delete:{domain}` - Delete SMTP credentials for a specific domain\n\
\n### Statistics Scopes\n- `statistics-transactional:read:all` - Read all transactional statistics\n- `statistics-transactional:read:{domain}`\
\ - Read transactional statistics for a specific domain\n\n### API Key Scopes\n- `api-keys:read` - Read API keys\n- `api-keys:write`\
\ - Create and update API keys\n- `api-keys:delete` - Delete API keys\n\n### Sub-Account Scopes\n- `sub-accounts:read`\
\ - List and read sub accounts under the parent\n- `sub-accounts:write` - Create and update sub accounts\n- `sub-accounts:delete`\
\ - Soft-delete sub accounts\n- `sub-accounts:suspend` - Suspend and unsuspend sub accounts\n- `sub-accounts:usage` -\
\ Read per-sub-account usage and allocated cost\n- `sub-account-api-keys:read` - List and read API keys owned by sub accounts\n\
- `sub-account-api-keys:write` - Create and update API keys owned by sub accounts\n- `sub-account-api-keys:delete` - Delete\
\ API keys owned by sub accounts\n\n## Rate Limiting\n- General API endpoints: 100 requests per second, 200 burst\n- Statistics\
\ endpoints: 1 request per second, 1 burst\n\n## Pagination\nList endpoints use cursor-based pagination with the following\
\ parameters:\n- `limit`: Maximum number of items to return (default: 100, max: 100)\n- `after`: Pass `pagination.next_cursor`\
\ to fetch the next page\n- `before`: Pass `pagination.previous_cursor` to fetch the previous page\n\n`after` and `before`\
\ are mutually exclusive. A legacy `cursor` query may be\naccepted by parts of the server for backwards compatibility,\
\ but it is not\npart of the v2 public contract.\n\n## Time Formats\nAll timestamps must be in RFC3339 format, e.g., `2023-12-25T10:30:00Z`\n\
\n## Idempotency\nThe operations that explicitly declare the optional `Idempotency-Key`\nheader support idempotency. Other\
\ POST operations do not gain idempotency\nimplicitly. When the header is provided:\n- A fresh execution does not return\
\ `Idempotent-Replayed`.\n- A completed stored response is replayed with its original status and body\n and `Idempotent-Replayed:\
\ true`.\n- An unexpired in-progress execution returns HTTP 409 with\n `Idempotent-Replayed: false` and a positive integer\
\ `Retry-After` header.\n- Reusing a key with a different HTTP method, resolved request path, or\n request body returns\
\ HTTP 422. That response has neither\n `Idempotent-Replayed` nor `Retry-After`.\n- For ordinary idempotent operations,\
\ deterministic 2xx and 4xx outcomes\n produced after the idempotency middleware are stored and replayed.\n Authentication\
\ and IP-allow-list failures happen before idempotency and\n are therefore not stored.\n- The two secret-bearing API-key\
\ create operations use manual encrypted\n completion. They store and replay a successful 201, including the same\n \
\ one-time `secret_key`; a controller-produced 4xx is not stored and leaves\n the key in progress until its execution\
\ lease expires.\n- Server errors (5xx), handler failures, and panics are not stored. The key\n is released so retrying\
\ the same request with the same key re-executes it.\n The v2 API does not use an HTTP 412 failed-key tombstone.\n- Idempotency\
\ keys for non-secret responses expire after 24 hours.\n- Encrypted API-key creation replay responses expire after 5 minutes.\n\
\n## IP Allow Lists\nEach API key can carry an `ip_allow_list`: a set of source IPs that restrict where the key may authenticate\
\ from.\n- Entries are CIDR blocks (e.g. `203.0.113.0/24`) or bare IPv4/IPv6 addresses (stored as a `/32` or `/128`).\
\ They are canonicalized and de-duplicated; the allow-all prefixes `0.0.0.0/0` and `::/0` are rejected, and at most 100\
\ entries are allowed after de-duplication (a longer list is rejected with HTTP 400).\n- An empty list (the default) places\
\ no restriction.\n- When the list is non-empty, any authenticated request whose client IP is not covered by an entry\
\ is rejected with HTTP 403 on every v2 endpoint, regardless of the key's scopes.\n- Manage the list with the `ip_allow_list`\
\ field on the API-key create and update endpoints (including the sub-account API-key endpoints).\n- When a key updates\
\ its own `ip_allow_list` to a value that excludes the caller's current IP, the update is rejected with HTTP 409 to prevent\
\ self-lockout. Updating a sub-account key from a parent key has no such guard.\n"
version: 2.0.0
contact:
email: support@ahasend.com
license:
name: MIT
identifier: MIT
servers:
- url: https://api.ahasend.com
description: Production server
security:
- BearerAuth: []
tags:
- name: Sub Accounts
description: Provision and manage isolated sub accounts under a parent account, including their API keys and usage.
paths:
/v2/accounts/{account_id}/sub-accounts:
get:
summary: List Sub Accounts
description: Returns a cursor-paginated list of sub accounts under the parent account. Soft-deleted sub accounts are
not included; usage billed for sub accounts deleted during the current period is reported by the usage endpoint's
`removed_sub_accounts` aggregate.
operationId: listSubAccounts
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
- name: limit
in: query
description: Maximum number of items to return (1-100)
schema:
type: integer
minimum: 1
maximum: 100
default: 100
- name: after
in: query
description: Pagination cursor for the next page. Provide the value from `next_cursor` in the response.
schema:
type: string
- name: before
in: query
description: Pagination cursor for the previous page. Provide the value from `previous_cursor` in the response.
schema:
type: string
security:
- BearerAuth:
- sub-accounts:read
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go\"\n \"\
github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/common\"\n \"github.com/google/uuid\"\
\n)\n\nfunc main() {\n // Create API client with authentication\n client := api.NewAPIClient(\n api.WithAPIKey(\"\
aha-sk-your-64-character-key\"),\n )\n\n accountID := uuid.New()\n\n // Create context for the API call\n ctx\
\ := context.Background()\n\n // List sub accounts (limit results to 50 per page)\n response, httpResp, err :=\
\ client.SubAccountsAPI.ListSubAccounts(ctx, accountID, &common.PaginationParams{Limit: ahasend.Int32(50)})\n if\
\ err != nil {\n log.Fatalf(\"Error listing sub accounts: %v\", err)\n }\n\n if httpResp.StatusCode == 200\
\ {\n fmt.Printf(\"✅ Sub accounts listed! Status: %d\\n\", httpResp.StatusCode)\n fmt.Printf(\"Found %d sub\
\ accounts\\n\", len(response.Data))\n for _, sub := range response.Data {\n fmt.Printf(\"- ID: %s, Name:\
\ %s, Status: %s\\n\", sub.ID, sub.Name, sub.Status)\n }\n } else {\n fmt.Printf(\"❌ Unexpected status code:\
\ %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (AhaSend SDK)
source: 'import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const page = await client.subAccounts.list({ limit: 20 });
console.log("Sub-accounts listed.", { count: page.data.length });
'
responses:
'200':
description: List of sub accounts
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedSubAccountsResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Parent account not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
summary: Create Sub Account
description: Creates a new sub account under the parent account
operationId: createSubAccount
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
- $ref: '#/components/parameters/IdempotencyKey'
security:
- BearerAuth:
- sub-accounts:write
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go\"\n \"\
github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\
\n)\n\nfunc main() {\n // Create API client with authentication\n client := api.NewAPIClient(\n api.WithAPIKey(\"\
aha-sk-your-64-character-key\"),\n )\n\n accountID := uuid.New()\n\n // Create context for the API call\n ctx\
\ := context.Background()\n\n // Create a sub account with an idempotency key for safe retries\n response, httpResp,\
\ err := client.SubAccountsAPI.CreateSubAccount(ctx, accountID, requests.CreateSubAccountRequest{\n Name: \
\ \"Acme Subsidiary\",\n Website: \"acme.example.com\",\n MonthlyCredit: ahasend.Int64(0),\n \
\ }, api.WithIdempotencyKey(\"subacct-20240101-acme\"))\n if err != nil {\n log.Fatalf(\"Error creating sub\
\ account: %v\", err)\n }\n\n if httpResp.StatusCode == 201 {\n fmt.Printf(\"✅ Sub account created! Status:\
\ %d\\n\", httpResp.StatusCode)\n if response != nil {\n fmt.Printf(\"ID: %s\\n\", response.ID)\n fmt.Printf(\"\
Name: %s\\n\", response.Name)\n fmt.Printf(\"Status: %s\\n\", response.Status)\n }\n } else {\n fmt.Printf(\"\
❌ Unexpected status code: %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (AhaSend SDK)
source: "import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\nconst subAccount\
\ = await client.subAccounts.create(\n { name: \"Example subsidiary\", website: \"subsidiary.example.com\" },\n\
\ { idempotencyKey: \"sdk-sample-create-sub-account\" },\n);\nconsole.log(\"Sub-account created.\", { id: subAccount.id,\
\ status: subAccount.status });\n"
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSubAccountRequest'
responses:
'201':
description: Sub account created successfully
headers:
Idempotent-Replayed:
$ref: '#/components/headers/IdempotentReplayed'
content:
application/json:
schema:
$ref: '#/components/schemas/SubAccount'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Parent account not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
$ref: '#/components/responses/IdempotencyConflict'
'422':
$ref: '#/components/responses/IdempotencyPayloadMismatch'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/v2/accounts/{account_id}/sub-accounts/usage:
get:
summary: Get Sub-Account Usage
description: Returns current billing-period usage and proportional allocated cost for the parent and active sub accounts
operationId: getSubAccountsUsage
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
security:
- BearerAuth:
- sub-accounts:usage
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go/api\"\n\
\ \"github.com/google/uuid\"\n)\n\nfunc main() {\n // Create API client with authentication\n client := api.NewAPIClient(\n\
\ api.WithAPIKey(\"aha-sk-your-64-character-key\"),\n )\n\n accountID := uuid.New()\n\n // Create context\
\ for the API call\n ctx := context.Background()\n\n response, httpResp, err := client.SubAccountsAPI.GetSubAccountsUsage(ctx,\
\ accountID)\n if err != nil {\n log.Fatalf(\"Error getting sub-accounts usage: %v\", err)\n }\n\n if httpResp.StatusCode\
\ == 200 {\n fmt.Printf(\"✅ Retrieved sub-accounts usage! Status: %d\\n\", httpResp.StatusCode)\n if response\
\ != nil {\n fmt.Printf(\"Currency: %s\\n\", response.Currency)\n fmt.Printf(\"Allocation method: %s\\\
n\", response.AllocationMethod)\n fmt.Printf(\"Total reception count: %d\\n\", response.Total.ReceptionCount)\n\
\ fmt.Printf(\"Total allocated cost: %.2f\\n\", response.Total.AllocatedCost)\n\n fmt.Printf(\"Sub-accounts:\
\ %d\\n\", len(response.SubAccounts))\n for i, sub := range response.SubAccounts {\n fmt.Printf(\" \
\ [%d] reception count: %d, allocated cost: %.2f\\n\", i, sub.ReceptionCount, sub.AllocatedCost)\n }\n }\n\
\ } else {\n fmt.Printf(\"❌ Unexpected status code: %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (AhaSend SDK)
source: "import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\nconst usage =\
\ await client.subAccounts.usage();\nconsole.log(\"Sub-account usage loaded.\", {\n currency: usage.currency,\n\
\ subAccountCount: usage.sub_accounts.length,\n});\n"
responses:
'200':
description: Sub-account usage breakdown
content:
application/json:
schema:
$ref: '#/components/schemas/SubAccountUsageResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Parent account not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/v2/accounts/{account_id}/sub-accounts/{sub_account_id}:
get:
summary: Get Sub Account
description: Returns a specific sub account under the parent account
operationId: getSubAccount
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
- name: sub_account_id
in: path
required: true
description: Sub account ID
schema:
type: string
format: uuid
security:
- BearerAuth:
- sub-accounts:read
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go/api\"\n\
\ \"github.com/google/uuid\"\n)\n\nfunc main() {\n // Create API client with authentication\n client := api.NewAPIClient(\n\
\ api.WithAPIKey(\"aha-sk-your-64-character-key\"),\n )\n\n accountID := uuid.New()\n subAccountID := uuid.New()\n\
\n // Create context for the API call\n ctx := context.Background()\n\n // Get a single sub account by ID\n \
\ response, httpResp, err := client.SubAccountsAPI.GetSubAccount(\n ctx,\n accountID,\n subAccountID,\n\
\ )\n if err != nil {\n log.Fatalf(\"Error getting sub account: %v\", err)\n }\n\n if httpResp.StatusCode\
\ == 200 {\n fmt.Printf(\"✅ Retrieved sub account. Status: %d\\n\", httpResp.StatusCode)\n if response !=\
\ nil {\n fmt.Printf(\"ID: %s\\n\", response.ID)\n fmt.Printf(\"Name: %s\\n\", response.Name)\n fmt.Printf(\"\
Website: %s\\n\", response.Website)\n fmt.Printf(\"Status: %s\\n\", response.Status)\n fmt.Printf(\"Domain\
\ count: %d\\n\", response.DomainCount)\n fmt.Printf(\"Member count: %d\\n\", response.MemberCount)\n }\n\
\ } else {\n fmt.Printf(\"❌ Unexpected status code: %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (AhaSend SDK)
source: 'import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const subAccountId = "00000000-0000-4000-8000-000000000004";
const subAccount = await client.subAccounts.get(subAccountId);
console.log("Sub-account found.", { id: subAccount.id, status: subAccount.status });
'
responses:
'200':
description: Sub account details
content:
application/json:
schema:
$ref: '#/components/schemas/SubAccount'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Sub account not found under the parent account
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
put:
summary: Update Sub Account
description: Updates a sub account's editable settings
operationId: updateSubAccount
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
- name: sub_account_id
in: path
required: true
description: Sub account ID
schema:
type: string
format: uuid
security:
- BearerAuth:
- sub-accounts:write
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go\"\n \"\
github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\
\n)\n\nfunc main() {\n // Create API client with authentication\n client := api.NewAPIClient(\n api.WithAPIKey(\"\
aha-sk-your-64-character-key\"),\n )\n\n accountID := uuid.New()\n subAccountID := uuid.New()\n\n // Create\
\ context for the API call\n ctx := context.Background()\n\n response, httpResp, err := client.SubAccountsAPI.UpdateSubAccount(ctx,\
\ accountID, subAccountID, requests.UpdateSubAccountRequest{Name: ahasend.String(\"Acme Subsidiary\"), MonthlyCredit:\
\ ahasend.Int64(50000)})\n if err != nil {\n log.Fatalf(\"Error updating sub account: %v\", err)\n }\n\n if\
\ httpResp.StatusCode == 200 {\n fmt.Printf(\"✅ Sub account updated! Status: %d\\n\", httpResp.StatusCode)\n\
\ if response != nil {\n fmt.Printf(\"ID: %s\\n\", response.ID)\n fmt.Printf(\"Name: %s\\n\", response.Name)\n\
\ fmt.Printf(\"MonthlyCredit: %d\\n\", response.MonthlyCredit)\n }\n } else {\n fmt.Printf(\"❌ Unexpected\
\ status code: %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (AhaSend SDK)
source: "import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\nconst subAccountId\
\ = \"00000000-0000-4000-8000-000000000004\";\nconst subAccount = await client.subAccounts.update(subAccountId,\
\ {\n name: \"Renamed subsidiary\",\n});\nconsole.log(\"Sub-account updated.\", { id: subAccount.id, status: subAccount.status\
\ });\n"
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateSubAccountRequest'
responses:
'200':
description: Sub account updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/SubAccount'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Sub account not found under the parent account
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
delete:
summary: Delete Sub Account
description: Soft-deletes a sub account under the parent account
operationId: deleteSubAccount
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
- name: sub_account_id
in: path
required: true
description: Sub account ID
schema:
type: string
format: uuid
security:
- BearerAuth:
- sub-accounts:delete
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go/api\"\n\
\ \"github.com/google/uuid\"\n)\n\nfunc main() {\n // Create API client with authentication\n client := api.NewAPIClient(\n\
\ api.WithAPIKey(\"aha-sk-your-64-character-key\"),\n )\n\n accountID := uuid.New()\n subAccountID := uuid.New()\n\
\n // Create context for the API call\n ctx := context.Background()\n\n // Soft-delete the sub account\n response,\
\ httpResp, err := client.SubAccountsAPI.DeleteSubAccount(ctx, accountID, subAccountID)\n if err != nil {\n \
\ log.Fatalf(\"Error deleting sub account: %v\", err)\n }\n\n if httpResp.StatusCode == 200 {\n fmt.Printf(\"\
✅ Sub account deleted! Status: %d\\n\", httpResp.StatusCode)\n if response != nil && response.Message != \"\"\
\ {\n fmt.Printf(\"Response: %s\\n\", response.Message)\n }\n } else {\n fmt.Printf(\"❌ Unexpected status\
\ code: %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (AhaSend SDK)
source: 'import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const subAccountId = "00000000-0000-4000-8000-000000000004";
const result = await client.subAccounts.delete(subAccountId);
console.log("Sub-account deleted.", { message: result.message });
'
responses:
'200':
description: Sub account deleted successfully
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
example:
message: sub account deleted
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Sub account not found under the parent account
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/v2/accounts/{account_id}/sub-accounts/{sub_account_id}/suspend:
post:
summary: Suspend Sub Account
description: Suspends a sub account under the parent account
operationId: suspendSubAccount
tags:
- Sub Accounts
parameters:
- name: account_id
in: path
required: true
description: Parent account ID
schema:
type: string
format: uuid
- name: sub_account_id
in: path
required: true
description: Sub account ID
schema:
type: string
format: uuid
security:
- BearerAuth:
- sub-accounts:suspend
x-code-samples:
- lang: go
label: AhaSend Go SDK
source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n\n \"github.com/AhaSend/ahasend-go/api\"\n\
\ \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\n)\n\nfunc main() {\n // Create\
\ API client with authentication\n client := api.NewAPIClient(\n api.WithAPIKey(\"aha-sk-your-64-character-key\"\
),\n )\n\n accountID := uuid.New()\n subAccountID := uuid.New()\n\n // Create context for the API call\n ctx\
\ := context.Background()\n\n response, httpResp, err := client.SubAccountsAPI.SuspendSubAccount(ctx, accountID,\
\ subAccountID, requests.SuspendSubAccountRequest{\n Reason: \"Customer requested temporary pause\",\n })\n\
\ if err != nil {\n log.Fatalf(\"Error suspending sub account: %v\", err)\n }\n\n if httpResp.StatusCode ==\
\ 200 {\n fmt.Printf(\"✅ Sub account suspended. Status: %d\\n\", httpResp.StatusCode)\n fmt.Printf(\"ID: %s\\\
n\", response.ID)\n fmt.Printf(\"Status: %s\\n\", response.Status)\n } else {\n fmt.Printf(\"❌ Unexpected\
\ status code: %d\\n\", httpResp.StatusCode)\n }\n}\n"
- lang: javascript
label: Node.js 22+ (Ah
# --- truncated at 32 KB (81 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/ahasend/refs/heads/main/openapi/ahasend-sub-accounts-api-openapi.yml