OpenAPI 3.1
The SOAMTAR API is described by an OpenAPI 3.1 specification published at:
- YAML: openapi.yaml
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.goPostman
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:
- Postman → Import → Link
- 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"