> ## Documentation Index
> Fetch the complete documentation index at: https://docs.afriex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Register SME

> Registers a business as its own SME so that dedicated virtual accounts are issued under the business's own legal entity rather than the shared default. The flow is stateful and driven by this single endpoint: the `step` field selects the payload carried in `data`. Call the steps in order — `INITIATE` (triggers a one-time passcode to the supplied mobile number), `CONFIRM_OTP`, then `SUBMIT` (company details, directors and documents). Upload each document first via `POST /api/v1/media/url` and pass the returned object keys in the `SUBMIT` payload. Requires an API key with admin permission.

Register your business as its own SME so that virtual accounts are issued under your legal entity instead of the shared Afriex default. This is a **stateful, step-based** flow driven by a single endpoint: the `step` field selects which payload shape goes in `data`.

<Note>
  Requires an API key with **admin** permission. Only Limited Liability Companies are supported today, so `businessType` must be `2` in the `INITIATE` step.
</Note>

## Flow

<Steps>
  <Step title="INITIATE">
    Send the business `mobile`, `email`, and `businessType`. Afriex creates an onboarding request, returns an `onboardingRequestId`, and sends a one-time passcode to the supplied mobile number.
  </Step>

  <Step title="CONFIRM_OTP">
    Post back the `onboardingRequestId` from step 1 and the 6-digit `otp` the customer received.
  </Step>

  <Step title="SUBMIT">
    Submit company details, `directors[]`, and optional `organizationShareholders[]` / `media[]`. Every file field is an **object key** returned by [Generate Upload URL](/api-reference/endpoint/media/generate-upload-url). Upload each file first, then reference the returned `key` here.
  </Step>
</Steps>

<Tip>
  Track progress in `status`: `OTP_PENDING` after `INITIATE`, `DETAILS_PENDING` after `CONFIRM_OTP`, and `SUBMITTED` after `SUBMIT`. The `nextStep` field tells you what to call next; `expiresAt` is the deadline for that step (OTP window after `INITIATE`, submit window after `CONFIRM_OTP`).
</Tip>

Once submitted, poll [Get SME Registration Status](/api-reference/endpoint/sme-registration/status) for the review outcome. Virtual accounts under your entity are issued only after the review reaches **Approved** (`reviewStatus: 3`).


## OpenAPI

````yaml POST /api/v1/sme-registration
openapi: 3.1.0
info:
  title: Afriex Business API
  version: 1.0.8
  description: >-
    Welcome to the Afriex Business API. This API allows you to manage customers,
    process payments, handle payouts, and receive real-time notifications via
    webhooks.


    For detailed guidance on authentication, pagination, error handling, and
    webhooks, please refer to the [dedicated guides](https://docs.afriex.com) in
    the top bar. The guide provides a step-by-step instructions to help you
    integrate seamlessly.
  termsOfService: https://www.afriex.com/terms-and-condition
  contact:
    name: Afriex API Support
    email: eng@afriex.co
    url: https://docs.afriex.com
  license:
    name: Proprietary
    url: https://www.afriex.com/terms-and-condition
servers:
  - url: https://sandbox.api.afriex.com
    description: Staging Base URL
  - url: https://api.afriex.com
    description: Production Base URL
security:
  - ApiKey: []
tags:
  - name: Customers
    description: Create and manage your customers.
  - name: Payment Methods
    description: Register and resolve customer payout and collection methods.
  - name: Transactions
    description: Create and track deposits, withdrawals, and swaps.
  - name: Balance
    description: View and top up your business wallet balances.
  - name: Rates
    description: Fetch real-time exchange rates.
  - name: Checkout Sessions
    description: Create hosted checkout sessions.
  - name: Webhooks
    description: Webhook event payloads and sandbox webhook testing.
  - name: Media
    description: Generate presigned URLs for secure file uploads.
paths:
  /api/v1/sme-registration:
    parameters:
      - $ref: '#/components/parameters/x-api-version'
    post:
      tags:
        - SME Registration
      summary: Register a business as an SME (step-based)
      description: >-
        Registers a business as its own SME so that dedicated virtual accounts
        are issued under the business's own legal entity rather than the shared
        default. The flow is stateful and driven by this single endpoint: the
        `step` field selects the payload carried in `data`. Call the steps in
        order — `INITIATE` (triggers a one-time passcode to the supplied mobile
        number), `CONFIRM_OTP`, then `SUBMIT` (company details, directors and
        documents). Upload each document first via `POST /api/v1/media/url` and
        pass the returned object keys in the `SUBMIT` payload. Requires an API
        key with admin permission.
      operationId: smeRegistration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - step
                - data
              properties:
                step:
                  type: string
                  enum:
                    - INITIATE
                    - CONFIRM_OTP
                    - SUBMIT
                  description: Selects the payload shape carried in `data`.
                data:
                  type: object
                  description: >-
                    Step-specific payload. `INITIATE`: `mobile`, `email`,
                    `businessType` (must be `2` — only Limited Liability
                    Companies are supported at this time). `CONFIRM_OTP`:
                    `onboardingRequestId`, `otp`. `SUBMIT`: company details,
                    `directors[]`, and optional `organizationShareholders[]` /
                    `media[]`, where every file field is an object key returned
                    by `POST /api/v1/media/url`.
            examples:
              initiate:
                summary: Step 1 — initiate and trigger the OTP
                value:
                  step: INITIATE
                  data:
                    mobile: '254712345678'
                    email: admin@company.co.ke
                    businessType: 2
              confirm-otp:
                summary: Step 2 — confirm the OTP
                value:
                  step: CONFIRM_OTP
                  data:
                    onboardingRequestId: obr-12345
                    otp: '483921'
      responses:
        '200':
          description: Step processed successfully.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      onboardingRequestId:
                        type: string
                      step:
                        type: string
                        enum:
                          - INITIATE
                          - CONFIRM_OTP
                          - SUBMIT
                      status:
                        type: string
                        enum:
                          - OTP_PENDING
                          - DETAILS_PENDING
                          - SUBMITTED
                          - REJECTED
                          - EXPIRED
                      nextStep:
                        type: string
                        nullable: true
                        enum:
                          - CONFIRM_OTP
                          - SUBMIT
                      expiresAt:
                        type: string
                        format: date-time
                        description: >-
                          Deadline for the current step — OTP window after
                          INITIATE, submit window after CONFIRM_OTP.
        '400':
          description: Invalid request body or a step called out of order.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized - Invalid business API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  parameters:
    x-api-version:
      name: x-api-version
      in: header
      required: false
      description: >-
        API version in ISO 8601 format (e.g. 2025-12-28). Defaults to latest
        stable.
      schema:
        type: string
  schemas:
    ErrorResponse:
      type: object
      properties:
        code:
          type: string
          description: Machine-readable error code.
        error:
          type: string
          description: Human-readable error message.
        details:
          $ref: '#/components/schemas/ErrorDetails'
    ErrorDetails:
      type: object
      properties:
        errorMessage:
          type: string
          description: Detailed/technical error message.
        friendlyMessage:
          type: string
          description: User-facing error message safe to display.
        data:
          type: object
          description: >-
            Optional caller-safe context for the error. On a customer-create
            uniqueness conflict (EMAIL_ALREADY_EXISTS /
            PHONE_NUMBER_ALREADY_EXISTS) this carries the existing customer's
            id, so you can adopt it without a follow-up lookup.
          properties:
            customerId:
              type: string
              description: Id of the existing customer (on a create conflict).
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Static business API key issued from the dashboard. A business can
        provision **multiple API keys**, each scoped to a configurable set of
        **permissions** (e.g. read transactions, create deposits, etc).
        Permissions are chosen per key at creation time in the dashboard and may
        be revoked by deleting the key. Requests made with a key that does not
        include the permission required by the target endpoint will be rejected
        with a `403 Forbidden` response; an unrecognised, malformed or revoked
        key returns `401 Unauthorized`. Manage your keys and their permissions
        under **Developer → API keys** in the dashboard.

````