OpenAPI 3.0 specification for the MojoPay Omni API. Import the raw YAML file into Postman, Insomnia, or your codegen tool.
openapi: 3.0.3
info:
title: MojoPay Omni API
version: "1.0"
description: |
HTTPS JSON API for collections, hosted checkout, payouts, bank and mobile verification, mandates, reference metadata, and wallet balance.
Errors return an `ApiError` object: `error.code`, `error.message`, `error.request_id`, and optional `error.doc_url` for more detail.
`request_id` values look like `REQ_` + 12 uppercase alphanumeric characters.
On POST requests that create or move money (or create checkout sessions or mandates), send an `Idempotency-Key` header. Reuse the same key only when safely retrying the **same** JSON body.
**Integration quick start:** See `/doc` for credentials setup, hosted checkout curl examples, webhook signature verification (PHP/Node), and an integration checklist. Sample JSON bodies: `/doc/samples.json`. Portal Mojo Ai can help debug Omni API payloads against the same guide.
**Testing mode:** New merchants start in Testing mode on live rails. Money-in (`POST /v1/collections` and fixed-amount `POST /v1/checkout/sessions`, plus amounts entered on `/pay/{id}`) is capped to a per-country max until Go Live. `amount_mode: open` is not allowed while Testing. Details: `/doc#testing-mode`.
**Required headers on authenticated requests:** `Authorization: Bearer {token}`, `Content-Type: application/json`, `Accept: application/json`.
**Sub-accounts (when enabled for your merchant):** also send `X-Mojo-Account-Ref` with the target account ref on every request except `GET /v1/metadata/*` and `GET /v1/balance`. Use `GET /v1/account` to verify the resolved account.
**Money-moving POSTs also require:** `Idempotency-Key` (UUID recommended; reuse only when retrying the same body).
**Webhooks** (configured per API client in the merchant portal): at-least-once delivery with `MojoPay-Signature` to the client that created the resource. Event types (v1.0): `collection.processing|succeeded|failed`, `checkout_session.processing|succeeded|failed`, `payout.processing|succeeded|failed`, `mandate.processing|succeeded|cancelled`, `mandate_debit.processing|succeeded|failed`, and subscription lifecycle events (`subscription.created`, `subscription.active`, `subscription.cancelled`, `subscription.failed`, `subscription.charge_failed`) when linked to plans. Event `id` values look like `EVT_` + 24 uppercase alphanumeric characters. Verify HMAC on `{timestamp}.{raw_body}`; reject timestamps outside ±300 seconds. Portal-created pay links do not emit outbound webhooks.
**Security:** Bearer tokens are merchant-scoped; resource lookups never expose another tenant’s data (404). Optional API IP allowlist is configured in the portal. Portal **Team member** users can view activity but cannot change API clients, webhooks, or financial settings.
**Wallet balance (`GET /v1/balance`):** `collection_wallet` is the **available** (T+1-released) collection balance; `collection_wallet_actual` is total succeeded credits; `collection_wallet_held` is still within the T+1 hold. Payouts draw from `payout_wallet`. Merchants move funds via the portal settlement page or approved auto-settlement.
Rate limits apply to keep the API reliable. When exceeded, responses use HTTP 429 and error code `rate_limited`. OAuth token requests are limited per client; authenticated calls are limited per merchant account.
servers:
- url: https://omni.mojo-pay.com
description: Current application (APP_URL)
- url: https://api.mojopay.com
description: Production
tags:
- name: OAuth
- name: Collections
- name: Checkout
- name: Transactions
- name: Payouts
- name: Verifications
- name: Mandates
- name: Subscriptions
- name: Metadata
- name: Balance
- name: Accounts
paths:
/v1/oauth/token:
post:
tags: [OAuth]
summary: Issue access token (client_credentials)
operationId: oauthToken
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthTokenRequest"
responses:
"200":
description: Bearer token issued
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthTokenResponse"
"400":
description: invalid_parameter
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: invalid_client
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Forbidden (e.g. invalid credentials or product not enabled for your account)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"429":
description: rate_limited
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/collections:
post:
tags: [Collections]
summary: Create collection (wallet collection)
operationId: createCollection
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateCollectionRequest"
responses:
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/Collection"
"400":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"409":
description: idempotency_key_mismatch
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"429":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
get:
tags: [Collections]
summary: Get collection by merchant_reference
operationId: getCollectionByMerchantReference
security: [{ bearerAuth: [] }]
parameters:
- name: merchant_reference
in: query
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Collection"
"400":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/collections/{id}:
get:
tags: [Collections]
summary: Get collection by id
operationId: getCollectionById
security: [{ bearerAuth: [] }]
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Collection"
"401":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/checkout/sessions:
post:
tags: [Checkout]
summary: Create hosted checkout session
operationId: createCheckoutSession
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateCheckoutSessionRequest"
responses:
"201":
description: Created (slim create payload)
content:
application/json:
schema:
$ref: "#/components/schemas/CheckoutSessionCreate"
"400":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"409":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/checkout/sessions/{id}:
get:
tags: [Checkout]
summary: Get checkout session
operationId: getCheckoutSession
security: [{ bearerAuth: [] }]
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/CheckoutSession"
"404":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/transactions/verify/{merchant_reference}:
get:
tags: [Transactions]
summary: Unified verify by merchant_reference
operationId: verifyTransaction
security: [{ bearerAuth: [] }]
parameters:
- name: merchant_reference
in: path
required: true
schema:
type: string
responses:
"200":
description: Collection, payout, or checkout snapshot
content:
application/json:
schema:
type: object
additionalProperties: true
"404":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/payouts:
post:
tags: [Payouts]
summary: Create payout
operationId: createPayout
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreatePayoutRequest"
responses:
"201":
content:
application/json:
schema:
$ref: "#/components/schemas/Payout"
"400":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"409":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/payouts/{merchant_reference}:
get:
tags: [Payouts]
summary: Get payout by merchant_reference
operationId: getPayout
security: [{ bearerAuth: [] }]
parameters:
- name: merchant_reference
in: path
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Payout"
"404":
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/verifications/msisdn:
post:
tags: [Verifications]
summary: MSISDN / mobile name check
operationId: verifyMsisdn
security: [{ bearerAuth: [] }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [mobile]
properties:
mobile:
type: string
pattern: "^\\d{10,15}$"
provider:
type: string
maxLength: 64
responses:
"200":
description: Verification outcome
content:
application/json:
schema:
$ref: "#/components/schemas/VerificationResult"
"502":
description: gateway_error (upstream KYC provider failure)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/verifications/bank_accounts:
post:
tags: [Verifications]
summary: Bank account name check
operationId: verifyBankAccount
security: [{ bearerAuth: [] }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [bank_code, account_number]
properties:
bank_code:
type: string
maxLength: 32
description: Bank code from metadata banks.
account_number:
type: string
maxLength: 64
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/VerificationResult"
"502":
description: gateway_error
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/mandates:
post:
tags: [Mandates]
summary: Create mandate
operationId: createMandate
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateMandateRequest"
responses:
"201":
content:
application/json:
schema:
type: object
additionalProperties: true
get:
tags: [Mandates]
summary: List / get mandate by merchant_reference
operationId: listMandates
security: [{ bearerAuth: [] }]
parameters:
- name: merchant_reference
in: query
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
type: object
additionalProperties: true
/v1/mandates/{mandate_id}/cancel:
post:
tags: [Mandates]
summary: Cancel mandate
operationId: cancelMandate
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
- name: mandate_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [mobile, reason]
properties:
mobile:
type: string
reason:
type: string
responses:
"200":
content:
application/json:
schema:
type: object
additionalProperties: true
/v1/mandates/{mandate_id}/debits:
post:
tags: [Mandates]
summary: Create mandate debit
operationId: createMandateDebit
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
- name: mandate_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [amount, currency, merchant_reference, provider]
properties:
amount:
type: string
currency:
type: string
minLength: 3
maxLength: 3
merchant_reference:
type: string
maxLength: 255
provider:
type: string
maxLength: 64
responses:
"201":
content:
application/json:
schema:
type: object
additionalProperties: true
/v1/mandate_debits/status:
get:
tags: [Mandates]
summary: Mandate debit status
operationId: mandateDebitStatus
security: [{ bearerAuth: [] }]
parameters:
- name: mandate_id
in: query
required: true
schema:
type: string
- name: merchant_reference
in: query
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
type: object
additionalProperties: true
/v1/subscription_plans:
get:
tags: [Subscriptions]
summary: List active subscription plans
description: Requires the subscriptions product to be enabled for your merchant.
operationId: listSubscriptionPlans
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/MerchantAccountRef"
responses:
"200":
content:
application/json:
schema:
type: object
required: [object, data]
properties:
object:
type: string
example: list
data:
type: array
items:
$ref: "#/components/schemas/SubscriptionPlan"
"403":
description: forbidden (subscriptions not enabled)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/subscriptions:
post:
tags: [Subscriptions]
summary: Enroll a subscription
description: Creates a subscriber and starts mandate enrollment for a subscription plan.
operationId: createSubscription
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
- $ref: "#/components/parameters/MerchantAccountRef"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateSubscriptionRequest"
responses:
"201":
content:
application/json:
schema:
$ref: "#/components/schemas/Subscription"
"403":
description: forbidden (subscriptions not enabled)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"422":
description: validation_error (e.g. invalid or inactive plan_id)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
get:
tags: [Subscriptions]
summary: Get subscription by merchant_reference
operationId: getSubscription
security: [{ bearerAuth: [] }]
parameters:
- name: merchant_reference
in: query
required: true
schema:
type: string
- $ref: "#/components/parameters/MerchantAccountRef"
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Subscription"
"404":
description: not_found
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
/v1/metadata/banks:
get:
tags: [Metadata]
summary: Bank reference list
operationId: metadataBanks
security: [{ bearerAuth: [] }]
responses:
"200":
content:
application/json:
schema:
type: object
additionalProperties: true
/v1/metadata/mobile_providers:
get:
tags: [Metadata]
summary: Mobile money providers
operationId: metadataMobileProviders
security: [{ bearerAuth: [] }]
responses:
"200":
content:
application/json:
schema:
type: object
additionalProperties: true
/v1/balance:
get:
tags: [Balance]
summary: Wallet balance
operationId: getBalance
security: [{ bearerAuth: [] }]
parameters:
- name: currency
in: query
required: false
schema:
type: string
minLength: 3
maxLength: 3
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/BalanceSnapshot"
/v1/account:
get:
tags: [Accounts]
summary: Resolved merchant account context
description: Returns the authenticated merchant and the sub-account resolved from `X-Mojo-Account-Ref` when sub-accounts are enabled.
operationId: getAccountContext
security: [{ bearerAuth: [] }]
parameters:
- $ref: "#/components/parameters/MerchantAccountRef"
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/AccountContext"
"400":
description: invalid_parameter (missing account header when required)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: not_found (unknown account ref)
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: opaque
description: Short-lived access token from POST /v1/oauth/token
parameters:
IdempotencyKey:
name: Idempotency-Key
in: header
required: true
schema:
type: string
maxLength: 255
example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
description: Required for money-moving and session/mandate creates; replays must use the same body.
MerchantAccountRef:
name: X-Mojo-Account-Ref
in: header
required: false
schema:
type: string
pattern: '^[a-z0-9][a-z0-9_-]{2,63}$'
example: accra-branch
description: Required when sub-accounts are enabled for the merchant (except metadata and balance routes). Targets the sub-account for this request.
schemas:
AccountContext:
type: object
required: [object, merchant]
properties:
object:
type: string
example: account_context
merchant:
type: object
properties:
id:
type: integer
name:
type: string
sub_accounts_enabled:
type: boolean
account:
type: object
nullable: true
properties:
id:
type: string
example: MAC_ABCDEF123456
object:
type: string
example: merchant_account
account_ref:
type: string
example: accra-branch
name:
type: string
status:
type: string
example: active
ApiError:
type: object
required: [error]
properties:
error:
type: object
required: [code, message, request_id]
properties:
code:
type: string
description: Stable machine-readable error code.
message:
type: string
doc_url:
type: string
format: uri
description: Optional URL with more detail for this error.
request_id:
type: string
description: Correlation id, e.g. REQ_8F3A2C1B9D0E
example: REQ_8F3A2C1B9D0E
OAuthTokenRequest:
type: object
required: [client_id, client_secret]
properties:
grant_type:
type: string
enum: [client_credentials]
client_id:
type: string
client_secret:
type: string
OAuthTokenResponse:
type: object
required: [access_token, token_type, expires_in]
properties:
access_token:
type: string
description: Opaque 64-character bearer token (not a JWT).
example: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2
token_type:
type: string
example: Bearer
expires_in:
type: integer
example: 1200
example:
access_token: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2
token_type: Bearer
expires_in: 1200
CreateCollectionRequest:
type: object
required: [amount, currency, merchant_reference, mobile, provider]
properties:
amount:
type: string
description: >
Merchant principal to receive. While the merchant is in Testing mode, must be at or below the
country testing max amount (see `/doc#testing-mode`).
currency:
type: string
minLength: 3
maxLength: 3
merchant_reference:
type: string
mobile:
type: string
provider:
type: string
description:
type: string
Collection:
type: object
description: >
Includes id, status, amounts, and references; fields may vary by payment rail and lifecycle.
`amount` is credited to the merchant on success. When fees apply, `fee_amount` is charged to the payer on top,
and `amount_payable` is the gross collected (`amount` + `fee_amount`).
additionalProperties: true
properties:
fee_amount:
type: string
description: Platform fee added on top of `amount` (same currency).
amount_payable:
type: string
description: Gross amount the payer pays (`amount` + `fee_amount`).
CreateCheckoutSessionRequest:
type: object
required: [currency, merchant_reference, success_url, cancel_url]
properties:
amount_mode:
type: string
enum: [fixed, open]
default: fixed
description: >
`fixed` (default) requires `amount` at create time. `open` lets the customer enter the amount on the hosted pay page.
`open` is not available while the merchant is in Testing mode (use `fixed` at or below the country testing max, or Go Live).
See `/doc#testing-mode`.
amount:
type: string
description: >
Required when `amount_mode` is `fixed` (or omitted). Omit for `open`.
In Testing mode, fixed amounts must be at or below the country testing max.
currency:
type: string
merchant_reference:
type: string
payment_rail:
type: string
nullable: true
enum: [mobile_money, card]
description: >
`mobile_money` locks the session to mobile money; `mobile` is then required at create unless pre-filled later on the hosted page.
When the key is omitted, the session stores `null` and the customer chooses mobile money on `/pay/{id}` (portal pay links send explicit JSON `null`).
Card is not accepted on hosted checkout in v1.0.
mobile:
type: string
description: >
Required when `payment_rail` is `mobile_money` at create time.
Omit when the customer will enter wallet details on the hosted page.
provider:
type: string
description: Mobile money provider code when required for the chosen rail (metadata mobile_providers).
success_url:
type: string
format: uri
cancel_url:
type: string
format: uri
description:
type: string
CheckoutSessionCreate:
type: object
required: [id, object, status, url, expires_at]
description: >
Fixed-amount creates include `currency`, `amount_mode`, `amount`, `fee_amount`, and `amount_payable` when fees are computed at create time.
Open-amount creates omit amount fields until the customer submits an amount on the hosted pay page.
`expires_at` is typically one hour after create.
properties:
id:
type: string
example: CS_4NQP81ABCDEF
object:
type: string
enum: [checkout_session]
status:
type: string
enum: [processing]
currency:
type: string
example: GHS
amount_mode:
type: string
enum: [fixed, open]
amount:
type: string
description: Merchant principal; present for fixed amount at create time.
fee_amount:
type: string
description: Platform fee added on top of `amount` when fees apply.
amount_payable:
type: string
description: Gross amount the payer pays (`amount` + `fee_amount`).
url:
type: string
format: uri
expires_at:
type: string
format: date-time
example:
id: CS_4NQP81ABCDEF
object: checkout_session
status: processing
currency: GHS
amount_mode: fixed
amount: "1.00"
fee_amount: "0.02"
amount_payable: "1.02"
url: https://checkout.example.com/pay/CS_4NQP81ABCDEF
expires_at: "2026-04-15T11:00:00Z"
CheckoutSession:
type: object
additionalProperties: true
properties:
id:
type: string
object:
type: string
enum: [checkout_session]
status:
type: string
currency:
type: string
amount_mode:
type: string
enum: [fixed, open]
amount:
type: string
nullable: true
fee_amount:
type: string
amount_payable:
type: string
nullable: true
merchant_reference:
type: string
mobile:
type: string
nullable: true
payment_rail:
type: string
nullable: true
provider:
type: string
nullable: true
card_scheme:
type: string
nullable: true
VerificationResult:
type: object
required: [status]
properties:
status:
type: string
enum: [verified, invalid]
profile:
type: object
nullable: true
properties:
first_name:
type: string
last_name:
type: string
BalanceSnapshot:
type: object
required: [currency, available, collection_wallet, collection_wallet_actual, collection_wallet_held, payout_wallet, pending]
properties:
currency:
type: string
available:
type: string
description: Total across available collection_wallet and payout_wallet.
collection_wallet:
type: string
description: Available collection balance (released after T+1; movable without instant settlement fee).
collection_wallet_actual:
type: string
description: Total succeeded collection credits on record (actual collection wallet).
collection_wallet_held:
type: string
description: Collection funds still held until the next T+1 release window.
payout_wallet:
type: string
pending:
type: string
provider_float:
type: string
description: Present when upstream float query succeeds.
CreatePayoutRequest:
type: object
required: [type, currency, amount, merchant_reference]
properties:
type:
type: string
enum: [mobile_money, bank]
currency:
type: string
amount:
type: string
merchant_reference:
type: string
mobile:
type: string
provider:
type: string
account_number:
type: string
bank_code:
type: string
narration:
type: string
transaction_type:
type: string
transaction_date:
type: string
expires_at:
type: string
Payout:
type: object
additionalProperties: true
CreateMandateRequest:
type: object
required: [mobile, provider, currency, amount, frequency, starts_at, ends_at, merchant_reference]
properties:
mobile:
type: string
provider:
type: string
currency:
type: string
amount:
type: string
frequency:
type: string
enum: [DAILY, WEEKLY, MONTHLY]
starts_at:
type: string
format: date-time
ends_at:
type: string
format: date-time
merchant_reference:
type: string
description:
type: string
plan_id:
type: string
description: When set, links the mandate to a subscription plan and creates a subscriber.
customer_name:
type: string
description: Required when plan_id is set.
customer_email:
type: string
format: email
description: Required when plan_id is set.
notes:
type: string
SubscriptionPlan:
type: object
required: [object, plan_id, name, currency, amount, frequency, status]
properties:
object:
type: string
example: subscription_plan
plan_id:
type: string
example: PLN_ABCDEF123456
name:
type: string
description:
type: string
currency:
type: string
minLength: 3
maxLength: 3
amount:
type: string
frequency:
type: string
enum: [DAILY, WEEKLY, MONTHLY]
duration_type:
type: string
duration_months:
type: integer
nullable: true
status:
type: string
example: active
CreateSubscriptionRequest:
type: object
required: [plan_id, merchant_reference, customer_name, customer_email, mobile, provider]
properties:
plan_id:
type: string
example: PLN_ABCDEF123456
merchant_reference:
type: string
customer_name:
type: string
customer_email:
type: string
format: email
mobile:
type: string
pattern: "^\\d{10,15}$"
provider:
type: string
notes:
type: string
Subscription:
type: object
additionalProperties: true
properties:
object:
type: string
example: subscription
subscription_id:
type: string
example: SUB_ABCDEF123456
status:
type: string
merchant_reference:
type: string
plan_id:
type: string
mandate_id:
type: string