Skip to content

OpenAPI 3.1 ​

The SOAMTAR API is described by an OpenAPI 3.1 specification published at:

Import it into Postman, Insomnia, Stoplight, Bruno or any compatible SDK generator (openapi-generator, openapi-typescript, oapi-codegen).

Overview ​

yaml
openapi: 3.1.0
info:
  title: SOAMTAR API
  version: 1.0.0
  description: |
    Public API to collect and pay out with Orange Money Sierra Leone through SOAMTAR.
  contact:
    name: SOAMTAR support
    email: support@so-amtar.com
    url: https://app.so-amtar.com/docs
servers:
  - url: https://app.so-amtar.com/v1
    description: Production and sandbox (the key's mode selects the environment)

security:
  - bearerAuth: []

paths:
  /payments:
    post:
      summary: Create a payment
      tags: [Payments]
      parameters:
        - in: header
          name: Idempotency-Key
          required: false
          schema: { type: string, maxLength: 255 }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/PaymentCreate' }
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TransactionEnvelope' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '409': { $ref: '#/components/responses/IdempotencyConflict' }
        '422': { $ref: '#/components/responses/Unprocessable' }
    get:
      summary: List payments
      tags: [Payments]
      parameters:
        - { in: query, name: status, schema: { type: string } }
        - { in: query, name: provider, schema: { type: string } }
        - { in: query, name: created_from, schema: { type: string, format: date } }
        - { in: query, name: per_page, schema: { type: integer, default: 25, maximum: 100 } }
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TransactionList' }

  /payments/{id}:
    get:
      summary: Retrieve a payment
      tags: [Payments]
      parameters: [{ in: path, name: id, required: true, schema: { type: string } }]
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TransactionEnvelope' }
        '404': { $ref: '#/components/responses/NotFound' }

  /payments/{id}/verify:
    post:
      summary: Force verification with Orange Money
      tags: [Payments]
      parameters: [{ in: path, name: id, required: true, schema: { type: string } }]
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TransactionEnvelope' }

  /payments/{id}/splits:
    post:
      summary: Create marketplace splits
      tags: [Splits]
    get:
      summary: List splits
      tags: [Splits]

  /refunds:
    post:
      summary: Refund a payment (full or partial)
      description: Requires the `can_refund` scope. Credited back to the payer's Orange Money number; asynchronous.
      tags: [Refunds]
      parameters:
        - in: header
          name: Idempotency-Key
          required: false
          schema: { type: string, maxLength: 255 }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/RefundCreate' }
      responses:
        '201':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/RefundEnvelope' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '422': { $ref: '#/components/responses/Unprocessable' }
    get:
      summary: List refunds
      tags: [Refunds]
      parameters:
        - { in: query, name: status, schema: { type: string, enum: [pending, processing, success, failed] } }
        - { in: query, name: transaction_id, schema: { type: string } }
        - { in: query, name: per_page, schema: { type: integer, default: 25, maximum: 100 } }
        - { in: query, name: page, schema: { type: integer } }
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/RefundList' }

  /refunds/{id}:
    get:
      summary: Retrieve a refund (id or REF- reference)
      tags: [Refunds]
      parameters: [{ in: path, name: id, required: true, schema: { type: string } }]
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/RefundEnvelope' }
        '404': { $ref: '#/components/responses/NotFound' }

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: sk_(test|live)_

  schemas:
    PaymentCreate:
      type: object
      required: [merchant_ref, amount]
      properties:
        merchant_ref: { type: string, maxLength: 255 }
        amount: { type: string, format: decimal, example: '150.00' }
        currency: { type: string, enum: [SLE, USD, EUR], default: SLE }
        provider: { type: string, enum: [orange_money_sl] }
        phone: { type: string, pattern: '^\+?232\d{8}$', example: '+23276123456' }
        payer:
          type: object
          properties:
            phone: { type: string, example: '+23276123456' }
            email: { type: string, format: email }
            name: { type: string, maxLength: 150 }
            country: { type: string, minLength: 2, maxLength: 2, example: SL }
        success_url: { type: string, format: uri }
        failed_url: { type: string, format: uri }
        callback_url: { type: string, format: uri, description: HTTPS URL that also receives every webhook event of this transaction (same payload and signature) }
        metadata: { type: object, additionalProperties: true }

    Transaction:
      type: object
      properties:
        id: { type: string, format: uuid }
        object: { type: string, const: transaction }
        reference: { type: string }
        merchant_ref: { type: string }
        provider_ref: { type: string, nullable: true }
        type: { type: string, enum: [payment] }
        payment_method: { type: string, nullable: true }
        status:
          type: string
          enum: [initiated, pending, processing, success, failed, cancelled, expired, partially_refunded, refunded]
        next_action:
          type: object
          nullable: true
          additionalProperties: true
        amount: { type: string, format: decimal }
        fee_amount: { type: string, format: decimal }
        net_amount: { type: string, format: decimal }
        currency: { type: string }
        payer:
          type: object
          properties:
            phone: { type: string, nullable: true }
            email: { type: string, nullable: true }
            name: { type: string, nullable: true }
            country: { type: string, nullable: true }
        payment_url: { type: string, format: uri }
        is_test: { type: boolean }
        metadata: { type: object, nullable: true }
        initiated_at: { type: string, format: date-time }
        paid_at: { type: string, format: date-time, nullable: true }
        expires_at: { type: string, format: date-time }

    RefundCreate:
      type: object
      required: [transaction_id]
      properties:
        transaction_id: { type: string, description: Payment id or reference (alias `payment_id`) }
        amount: { type: string, format: decimal, description: Omit to refund the full remaining amount }
        reason: { type: string, maxLength: 100 }
        description: { type: string, maxLength: 500 }

    Refund:
      type: object
      properties:
        id: { type: string, format: uuid }
        object: { type: string, const: refund }
        reference: { type: string, example: REF-XXXXXXXXXXXXXXXX }
        transaction_id: { type: string, format: uuid }
        amount: { type: string, format: decimal, example: '400.00' }
        currency: { type: string, example: SLE }
        reason: { type: string, nullable: true }
        description: { type: string, nullable: true }
        status: { type: string, enum: [pending, processing, success, failed] }
        fee_refunded: { type: boolean }
        fee_refunded_amount: { type: string, format: decimal, nullable: true }
        tax_refunded_amount: { type: string, format: decimal, nullable: true }
        failure_reason: { type: string, nullable: true }
        processed_at: { type: string, format: date-time, nullable: true }
        failed_at: { type: string, format: date-time, nullable: true }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    RefundEnvelope:
      type: object
      properties:
        data: { $ref: '#/components/schemas/Refund' }

    RefundList:
      type: object
      properties:
        data:
          type: array
          items: { $ref: '#/components/schemas/Refund' }
        pagination: { $ref: '#/components/schemas/Pagination' }

    TransactionEnvelope:
      type: object
      properties:
        data: { $ref: '#/components/schemas/Transaction' }
        livemode: { type: boolean }

    TransactionList:
      type: object
      properties:
        data:
          type: array
          items: { $ref: '#/components/schemas/Transaction' }
        pagination: { $ref: '#/components/schemas/Pagination' }

    Pagination:
      type: object
      properties:
        total: { type: integer }
        per_page: { type: integer }
        current_page: { type: integer }
        last_page: { type: integer }

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code: { type: string }
            message: { type: string }
            documentation_url: { type: string, format: uri }

  responses:
    BadRequest:        { description: Bad request,        content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    Unauthorized:      { description: Unauthorized,       content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    Forbidden:         { description: Insufficient scope, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    NotFound:          { description: Not found,          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    Unprocessable:     { description: Validation failed,  content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    IdempotencyConflict: { description: Idempotency conflict, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }

Generating an SDK ​

bash
# TypeScript / JavaScript
npx openapi-typescript https://app.so-amtar.com/docs/openapi.yaml -o soamtar-types.ts

# Python
openapi-generator-cli generate -i https://app.so-amtar.com/docs/openapi.yaml -g python -o ./soamtar-py

# Go
oapi-codegen -package soamtar https://app.so-amtar.com/docs/openapi.yaml > soamtar.gen.go

Postman ​

A ready-to-import collection is available: download soamtar-api.postman_collection.json and import it with Postman → Import → File. You can also import the specification directly:

  1. Postman → Import → Link
  2. Paste https://app.so-amtar.com/docs/openapi.yaml

Client-side validation ​

Use Schemathesis (Python) to fuzz your integration against the sandbox:

bash
schemathesis run https://app.so-amtar.com/docs/openapi.yaml \
  --base-url https://app.so-amtar.com/v1 \
  --header "Authorization: Bearer sk_test_xxx"

SOAMTAR Payment API Documentation.