AhaSend Sub Accounts API

Provision and manage isolated sub accounts under a parent account, their API keys, and their usage.

Operations 13

GET /v2/accounts/{account_id}/sub-accounts List Sub Accounts #
POST /v2/accounts/{account_id}/sub-accounts Create Sub Account #
GET /v2/accounts/{account_id}/sub-accounts/usage Get Sub-Account Usage #
GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id} Get Sub Account #
PUT /v2/accounts/{account_id}/sub-accounts/{sub_account_id} Update Sub Account #
DELETE /v2/accounts/{account_id}/sub-accounts/{sub_account_id} Delete Sub Account #
POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/suspend Suspend Sub Account #
POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/unsuspend Unsuspend Sub Account #
GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys List Sub-Account API Keys #
POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys Create Sub-Account API Key #
GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id} Get Sub-Account API Key #
PUT /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id} Update Sub-Account API Key #
DELETE /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id} Delete Sub-Account API Key #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • 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.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/ahasend-sub-accounts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

ahasend-sub-accounts-api-openapi.yml Raw ↑
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