{
  "openapi": "3.0.3",
  "info": {
    "title": "SIMcloud API",
    "version": "1.0.0",
    "description": "Token-authenticated SIMcloud REST API. Use HTTPS over IPv4 and send amounts in rand (ZAR). Poll accepted orders by their returned identifier. Reconcile ambiguous POST outcomes before resubmitting. See the [API conventions](https://simcloud.co.za/api/index.html#conventions) for polling, timeouts and retries."
  },
  "servers": [
    {
      "url": "https://simcloud.co.za"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Registration"
    },
    {
      "name": "SMS"
    },
    {
      "name": "Airtime"
    },
    {
      "name": "Data"
    },
    {
      "name": "VAS"
    },
    {
      "name": "Electricity"
    },
    {
      "name": "Transaction History"
    },
    {
      "name": "Balance"
    },
    {
      "name": "Network Lookup"
    }
  ],
  "paths": {
    "/api/register.php": {
      "post": {
        "tags": [
          "Registration"
        ],
        "summary": "Register a normal SIMcloud child account",
        "description": "Creates a normal SIMcloud account under the authenticated parent account and returns the new child's API token. The child has its own wallet, orders and API access. Retrying with the same parent token and cell number returns the existing child token.",
        "operationId": "registerSimcloudUser",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "first_name",
                  "last_name",
                  "cell",
                  "email",
                  "password"
                ],
                "properties": {
                  "first_name": {
                    "type": "string",
                    "example": "Jane",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes.",
                    "minLength": 1
                  },
                  "last_name": {
                    "type": "string",
                    "example": "Doe",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes.",
                    "minLength": 1
                  },
                  "cell": {
                    "type": "string",
                    "description": "10-digit South African mobile number beginning with 0.",
                    "example": "0821234567",
                    "pattern": "^0[0-9]{9}$"
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "example": "jane@example.com",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes."
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes.",
                    "minLength": 1
                  },
                  "id_number": {
                    "type": "string",
                    "description": "Optional valid South African ID number.",
                    "pattern": "^(?:[0-9]{13})?$"
                  },
                  "business_name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes."
                  },
                  "business_reg": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes."
                  },
                  "vatno": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes."
                  },
                  "address": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Maximum 255 bytes."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing child account for the same parent and cell number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistrationResult"
                }
              }
            }
          },
          "201": {
            "description": "Child account created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistrationResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Registration blocked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Cell number already registered to another account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Upstream registration rejected the account details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "Upstream registration request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Registration temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/register.html"
        }
      }
    },
    "/api/sms.php": {
      "post": {
        "tags": [
          "SMS"
        ],
        "summary": "Queue an SMS",
        "operationId": "sendSms",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "recipient",
                  "message"
                ],
                "properties": {
                  "recipient": {
                    "$ref": "#/components/schemas/MobileNumber"
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 459,
                    "example": "Hello World!"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsQueued"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or wallet balance of R1 or less.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "description": "Unable to confirm the queued SMS. If code is confirmation_pending, query the returned sms_id. Otherwise check SMS history before resubmitting.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsQueueError"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/sms.html"
        }
      },
      "get": {
        "tags": [
          "SMS"
        ],
        "summary": "Query SMS status",
        "operationId": "getSmsStatus",
        "parameters": [
          {
            "name": "sms_id",
            "in": "query",
            "required": true,
            "description": "Identifier returned by POST.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SMS delivery status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsStatus"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "SMS not found for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/sms.html"
        },
        "description": "The first 15 seconds after creation report queued. Delivered and failed are final."
      }
    },
    "/api/airtime.php": {
      "post": {
        "tags": [
          "Airtime"
        ],
        "summary": "Queue an airtime order",
        "description": "The same MSISDN and amount cannot be ordered again within 5 minutes. Duplicate requests inside that window return HTTP 409.",
        "operationId": "createAirtimeOrder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "network",
                  "amount"
                ],
                "properties": {
                  "msisdn": {
                    "$ref": "#/components/schemas/MobileNumber"
                  },
                  "network": {
                    "$ref": "#/components/schemas/AirtimeNetwork"
                  },
                  "amount": {
                    "type": "number",
                    "minimum": 2,
                    "maximum": 999,
                    "description": "Amount in rand, rounded to two decimal places.",
                    "example": 10
                  },
                  "reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Your reference for the order.",
                    "example": "INV-10045"
                  },
                  "recipient": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/MobileNumber"
                      }
                    ],
                    "description": "Alias for msisdn."
                  },
                  "user_reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for reference."
                  },
                  "client_reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for reference."
                  }
                },
                "allOf": [
                  {
                    "anyOf": [
                      {
                        "required": [
                          "msisdn"
                        ]
                      },
                      {
                        "required": [
                          "recipient"
                        ]
                      }
                    ]
                  },
                  {
                    "anyOf": [
                      {
                        "required": [
                          "reference"
                        ]
                      },
                      {
                        "required": [
                          "user_reference"
                        ]
                      },
                      {
                        "required": [
                          "client_reference"
                        ]
                      }
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order queued. Persist request_id and poll for the delivery result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RechargeQueued"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or insufficient balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceAwareError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/DuplicateRecharge"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/QueueBusy"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/airtime.html"
        }
      },
      "get": {
        "tags": [
          "Airtime"
        ],
        "summary": "Query an airtime order",
        "operationId": "getAirtimeOrder",
        "parameters": [
          {
            "$ref": "#/components/parameters/RechargeRequestId"
          },
          {
            "$ref": "#/components/parameters/RechargeOrderNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Order delivery status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RechargeStatus"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Order not found for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/airtime.html"
        },
        "description": "Supply request_id or orderno. Poll until delivered or failed."
      }
    },
    "/api/data.php": {
      "post": {
        "tags": [
          "Data"
        ],
        "summary": "Queue a data order",
        "description": "The same MSISDN and amount cannot be ordered again within 5 minutes. Duplicate requests inside that window return HTTP 409.",
        "operationId": "createDataOrder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "network"
                ],
                "properties": {
                  "msisdn": {
                    "$ref": "#/components/schemas/MobileNumber"
                  },
                  "network": {
                    "$ref": "#/components/schemas/DataNetwork"
                  },
                  "amount": {
                    "type": "number",
                    "description": "Current catalogue sellvalue for the chosen network.",
                    "example": 25
                  },
                  "reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Your reference for the order.",
                    "example": "INV-10045"
                  },
                  "recipient": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/MobileNumber"
                      }
                    ],
                    "description": "Alias for msisdn."
                  },
                  "user_reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for reference."
                  },
                  "client_reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for reference."
                  },
                  "sellvalue": {
                    "type": "number",
                    "description": "Alias for amount. Use a current catalogue sellvalue."
                  }
                },
                "allOf": [
                  {
                    "anyOf": [
                      {
                        "required": [
                          "msisdn"
                        ]
                      },
                      {
                        "required": [
                          "recipient"
                        ]
                      }
                    ]
                  },
                  {
                    "anyOf": [
                      {
                        "required": [
                          "reference"
                        ]
                      },
                      {
                        "required": [
                          "user_reference"
                        ]
                      },
                      {
                        "required": [
                          "client_reference"
                        ]
                      }
                    ]
                  },
                  {
                    "anyOf": [
                      {
                        "required": [
                          "amount"
                        ]
                      },
                      {
                        "required": [
                          "sellvalue"
                        ]
                      }
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order queued. Persist request_id and poll for the delivery result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RechargeQueued"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or insufficient balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceAwareError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/DuplicateRecharge"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/QueueBusy"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/data.html"
        }
      },
      "get": {
        "tags": [
          "Data"
        ],
        "summary": "List data products or query a data order",
        "description": "Without request_id or orderno, returns the current data bundle product catalog. Add network to filter the catalog. With request_id or orderno, returns the authenticated account's data order status.",
        "operationId": "getDataOrder",
        "parameters": [
          {
            "$ref": "#/components/parameters/RechargeRequestId"
          },
          {
            "$ref": "#/components/parameters/RechargeOrderNumber"
          },
          {
            "name": "products",
            "in": "query",
            "required": false,
            "description": "Optional catalogue flag. Omit order identifiers to list products.",
            "schema": {
              "type": "integer",
              "enum": [
                1
              ]
            }
          },
          {
            "name": "network",
            "in": "query",
            "required": false,
            "description": "Filter the data catalogue by network.",
            "schema": {
              "$ref": "#/components/schemas/DataNetwork"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order status or data product catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RechargeStatus"
                    },
                    {
                      "$ref": "#/components/schemas/DataCatalogue"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Order not found for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/data.html"
        }
      }
    },
    "/api/vas.php": {
      "get": {
        "tags": [
          "VAS"
        ],
        "summary": "List VAS products or query a VAS order",
        "description": "Without query parameters, returns the active VAS product catalog. With order_id or transaction_id, returns an API-created VAS order owned by the authenticated account.",
        "operationId": "getVas",
        "parameters": [
          {
            "in": "query",
            "name": "order_id",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "in": "query",
            "name": "transaction_id",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "VAS catalogue or order status.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/VasCatalogue"
                    },
                    {
                      "$ref": "#/components/schemas/VasStatus"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Order not found for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/vas.html"
        }
      },
      "post": {
        "tags": [
          "VAS"
        ],
        "summary": "Queue a VAS voucher order",
        "operationId": "createVasOrder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount"
                ],
                "properties": {
                  "product_id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Product ID from the catalogue. Takes precedence over voucher_type.",
                    "example": 12
                  },
                  "voucher_type": {
                    "type": "string",
                    "description": "Exact voucher type or slug returned by the catalog endpoint. Required if product_id is not supplied.",
                    "example": "checkers"
                  },
                  "amount": {
                    "type": "number",
                    "minimum": 0,
                    "exclusiveMinimum": true,
                    "description": "A denomination from available_amounts in the catalogue.",
                    "example": 100
                  },
                  "reference": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Order reference, up to 200 bytes.",
                    "example": "INV-10045"
                  },
                  "product": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for voucher_type."
                  },
                  "voucher_supplier": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for voucher_type."
                  },
                  "user_reference": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Alias for reference."
                  },
                  "client_reference": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Alias for reference."
                  }
                },
                "allOf": [
                  {
                    "anyOf": [
                      {
                        "required": [
                          "product_id"
                        ]
                      },
                      {
                        "required": [
                          "voucher_type"
                        ]
                      },
                      {
                        "required": [
                          "product"
                        ]
                      },
                      {
                        "required": [
                          "voucher_supplier"
                        ]
                      }
                    ]
                  },
                  {
                    "anyOf": [
                      {
                        "required": [
                          "reference"
                        ]
                      },
                      {
                        "required": [
                          "user_reference"
                        ]
                      },
                      {
                        "required": [
                          "client_reference"
                        ]
                      }
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Voucher queued. Poll by order_id or transaction_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VasQueued"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, unavailable denomination or insufficient balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VasOrderError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "Unable to verify the wallet balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/vas.html"
        }
      }
    },
    "/api/electricity.php": {
      "post": {
        "tags": [
          "Electricity"
        ],
        "summary": "Submit an electricity order",
        "description": "Use a unique client reference for each intended purchase. If the outcome is unknown, poll the original purchase by client reference. Do not submit the purchase again with a new reference.",
        "operationId": "createElectricityOrder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount"
                ],
                "properties": {
                  "meter_number": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9]+$",
                    "maxLength": 50,
                    "example": "01234567890"
                  },
                  "amount": {
                    "type": "integer",
                    "minimum": 55,
                    "maximum": 1000,
                    "description": "Total customer amount in whole rand (no cents). The fee is amount times 3 / 103, capped at R10 and rounded down to whole rand.",
                    "example": 150
                  },
                  "client_reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Unique per intended purchase and account. Reuse it with identical purchase details to retrieve the recorded result.",
                    "example": "INV-10045"
                  },
                  "recipient": {
                    "$ref": "#/components/schemas/MobileNumber"
                  },
                  "send_sms": {
                    "type": "boolean",
                    "default": true,
                    "description": "Send the SIMcloud completion SMS for a successful order.",
                    "example": true
                  },
                  "sms_company_name": {
                    "type": "string",
                    "maxLength": 100,
                    "pattern": "^[a-zA-Z0-9 &'().,-]*$",
                    "example": "acme power"
                  },
                  "deviceId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9]+$",
                    "maxLength": 50,
                    "example": "01234567890",
                    "description": "Alias for meter_number."
                  },
                  "electricity_order_reference": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Alias for client_reference.",
                    "example": "INV-10045"
                  },
                  "smsRecipientMsisdn": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/MobileNumber"
                      }
                    ],
                    "description": "Alias for recipient."
                  }
                },
                "allOf": [
                  {
                    "anyOf": [
                      {
                        "required": [
                          "meter_number"
                        ]
                      },
                      {
                        "required": [
                          "deviceId"
                        ]
                      }
                    ]
                  },
                  {
                    "anyOf": [
                      {
                        "required": [
                          "client_reference"
                        ]
                      },
                      {
                        "required": [
                          "electricity_order_reference"
                        ]
                      }
                    ]
                  },
                  {
                    "anyOf": [
                      {
                        "required": [
                          "recipient"
                        ]
                      },
                      {
                        "required": [
                          "smsRecipientMsisdn"
                        ]
                      }
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Electricity order accepted. Poll GET for voucher details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElectricityAccepted"
                }
              }
            }
          },
          "202": {
            "$ref": "#/components/responses/ElectricityReconciliation"
          },
          "400": {
            "description": "Invalid request, insufficient balance or municipality rejection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceAwareError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "Duplicate meter purchase, reference conflict, or reference already being processed. Check the existing order.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ElectricityDuplicate"
                    },
                    {
                      "$ref": "#/components/schemas/ElectricityReferenceConflict"
                    },
                    {
                      "$ref": "#/components/schemas/ElectricityRequestInProgress"
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "Electricity purchase temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/electricity.html"
        }
      },
      "get": {
        "tags": [
          "Electricity"
        ],
        "summary": "Check an electricity meter or query an electricity order",
        "description": "Provide meter_number for a meter check or one of the three order identifiers to query an order owned by the authenticated account.",
        "operationId": "getElectricityOrder",
        "parameters": [
          {
            "in": "query",
            "name": "meter_number",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]+$",
              "maxLength": 50,
              "example": "01234567890"
            },
            "description": "Meter number to validate before placing an order. When supplied, the endpoint returns meter support details instead of order status. A supplier internal error returns status unknown and supported null; retry later rather than treating the meter as unsupported."
          },
          {
            "in": "query",
            "name": "order_id",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "in": "query",
            "name": "client_reference",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Use the reference returned by POST or the original submitted reference."
          },
          {
            "in": "query",
            "name": "order_reference_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "required": false,
            "description": "Alias for meter_number.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]+$",
              "maxLength": 50,
              "example": "01234567890"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Meter check or electricity purchase status.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ElectricityMeter"
                    },
                    {
                      "$ref": "#/components/schemas/ElectricityPending"
                    },
                    {
                      "$ref": "#/components/schemas/ElectricityFulfilled"
                    },
                    {
                      "$ref": "#/components/schemas/ElectricityFailed"
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "$ref": "#/components/responses/ElectricityReconciliation"
          },
          "400": {
            "description": "Invalid query parameters or recorded purchase rejection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Order not found for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Recorded duplicate meter purchase.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElectricityDuplicate"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "Municipality meter check failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Meter check temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/electricity.html"
        }
      }
    },
    "/api/transactions.php": {
      "get": {
        "tags": [
          "Transaction History"
        ],
        "summary": "List account transaction history",
        "description": "Returns account-owned web, CSV, recurring and API transactions for airtime, data, SMS, VAS and electricity. Prices, fulfilment details, recipients and message content are not returned.",
        "operationId": "getTransactionHistory",
        "parameters": [
          {
            "in": "query",
            "name": "date_from",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start date in Africa/Johannesburg time.",
            "example": "2026-07-01"
          },
          {
            "in": "query",
            "name": "date_to",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end date in Africa/Johannesburg time. The maximum range is 90 days.",
            "example": "2026-07-31"
          },
          {
            "in": "query",
            "name": "type",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/TransactionService"
              }
            },
            "description": "Optional comma-separated service filter: airtime, data, electricity, vas and sms.",
            "example": [
              "airtime",
              "data"
            ],
            "style": "form",
            "explode": false
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor returned by the previous response. Reuse it with the same date range and type filter."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction history page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionHistory"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range, service filter, limit or cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/transactions.html"
        }
      }
    },
    "/api/balance.php": {
      "get": {
        "tags": [
          "Balance"
        ],
        "summary": "Get wallet balance",
        "operationId": "getWalletBalance",
        "responses": {
          "200": {
            "description": "Last known wallet balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletBalance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/balance.html"
        }
      }
    },
    "/api/network.php": {
      "get": {
        "tags": [
          "Network Lookup"
        ],
        "summary": "Look up a mobile network",
        "operationId": "lookupNetwork",
        "parameters": [
          {
            "in": "query",
            "name": "msisdn",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/MobileNumber"
            },
            "example": "0821234567"
          }
        ],
        "responses": {
          "200": {
            "description": "Detected mobile network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkLookup"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "The number did not match a network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "externalDocs": {
          "url": "https://simcloud.co.za/api/network.html"
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Token"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "status",
          "message"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "BalanceAwareError": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Error"
          },
          {
            "type": "object",
            "properties": {
              "required_balance": {
                "type": "number",
                "description": "Required rand balance, included on balance precheck failure."
              },
              "available_balance": {
                "type": "number",
                "description": "Last known rand balance, included on balance precheck failure."
              }
            }
          }
        ]
      },
      "VasOrderError": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BalanceAwareError"
          },
          {
            "type": "object",
            "properties": {
              "available_amounts": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "description": "Available denominations, included when the amount is unavailable."
              }
            }
          }
        ]
      },
      "MobileNumber": {
        "type": "string",
        "pattern": "^(?:0|\\+27|27)?[0-9]{9}$",
        "description": "South African mobile number. Prefer +27 followed by nine digits. Encode + as %2B in query parameters.",
        "example": "+27821234567"
      },
      "LocalTimestamp": {
        "type": "string",
        "description": "Local timestamp in Africa/Johannesburg, using YYYY-MM-DD HH:MM:SS.",
        "example": "2026-07-29 09:31:20"
      },
      "NullableLocalTimestamp": {
        "type": "string",
        "description": "Local timestamp in Africa/Johannesburg, using YYYY-MM-DD HH:MM:SS.",
        "example": "2026-07-29 09:31:20",
        "nullable": true
      },
      "SupplierOrderNumber": {
        "description": "Platform order number. Treat it as an identifier.",
        "oneOf": [
          {
            "type": "integer"
          },
          {
            "type": "string",
            "pattern": "^[0-9]+$"
          }
        ]
      },
      "SmsId": {
        "description": "SMS identifier. POST returns a decimal string. GET may serialize it as an integer.",
        "oneOf": [
          {
            "type": "integer",
            "minimum": 1
          },
          {
            "type": "string",
            "pattern": "^[0-9]+$"
          }
        ]
      },
      "AirtimeNetwork": {
        "type": "string",
        "description": "Network values are matched case-insensitively after trimming.",
        "enum": [
          "mtn",
          "cellc",
          "cell-c",
          "cell c",
          "vodacom",
          "telkom",
          "heita",
          "p-mtn",
          "p-cellc",
          "p-vodacom",
          "p-heita"
        ],
        "example": "mtn"
      },
      "DataNetwork": {
        "type": "string",
        "description": "Network values are matched case-insensitively after trimming.",
        "enum": [
          "mtn",
          "cellc",
          "cell-c",
          "cell c",
          "vodacom",
          "telkom",
          "heita",
          "pd-mtn",
          "pd-cellc",
          "pd-vodacom",
          "pd-heita"
        ],
        "example": "mtn"
      },
      "RegistrationResult": {
        "type": "object",
        "required": [
          "status",
          "message",
          "user_id",
          "username",
          "api_token",
          "existing"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "message": {
            "type": "string"
          },
          "user_id": {
            "type": "integer",
            "minimum": 1
          },
          "username": {
            "type": "string"
          },
          "api_token": {
            "type": "string",
            "description": "Child account Bearer token. Store securely."
          },
          "existing": {
            "type": "boolean",
            "description": "True on HTTP 200, false on HTTP 201."
          }
        }
      },
      "SmsQueued": {
        "type": "object",
        "required": [
          "status",
          "message",
          "sms_id",
          "sms_count",
          "timestamp"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "message": {
            "type": "string"
          },
          "sms_id": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "sms_count": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3
          },
          "timestamp": {
            "$ref": "#/components/schemas/LocalTimestamp"
          }
        }
      },
      "SmsStatus": {
        "type": "object",
        "required": [
          "sms_id",
          "status"
        ],
        "properties": {
          "sms_id": {
            "$ref": "#/components/schemas/SmsId"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "pending",
              "sent",
              "failed",
              "delivered",
              "staged",
              "unknown"
            ]
          }
        }
      },
      "SmsQueueError": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Error"
          },
          {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "confirmation_pending"
                ]
              },
              "sms_id": {
                "type": "string",
                "pattern": "^[0-9]+$"
              }
            }
          }
        ]
      },
      "RechargeQueued": {
        "type": "object",
        "required": [
          "status",
          "message",
          "service",
          "request_id",
          "msisdn",
          "network",
          "amount",
          "reference",
          "queue_status",
          "timestamp"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "message": {
            "type": "string"
          },
          "service": {
            "type": "string",
            "enum": [
              "airtime",
              "data"
            ]
          },
          "request_id": {
            "type": "integer",
            "minimum": 1
          },
          "msisdn": {
            "type": "string"
          },
          "network": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "reference": {
            "type": "string"
          },
          "queue_status": {
            "type": "string",
            "enum": [
              "queued"
            ]
          },
          "timestamp": {
            "$ref": "#/components/schemas/LocalTimestamp"
          }
        }
      },
      "RechargeStatus": {
        "type": "object",
        "required": [
          "status",
          "service",
          "request_id",
          "msisdn",
          "network",
          "amount",
          "reference",
          "platform_order_number",
          "queue_status",
          "final_order_id",
          "final_order_status",
          "error",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "pending",
              "delivered",
              "failed"
            ]
          },
          "service": {
            "type": "string",
            "enum": [
              "airtime",
              "data"
            ]
          },
          "request_id": {
            "type": "integer",
            "minimum": 1
          },
          "msisdn": {
            "type": "string"
          },
          "network": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "reference": {
            "type": "string"
          },
          "platform_order_number": {
            "description": "Null before placement.",
            "oneOf": [
              {
                "type": "integer",
                "nullable": true
              },
              {
                "type": "string",
                "pattern": "^[0-9]+$"
              }
            ]
          },
          "queue_status": {
            "type": "string",
            "nullable": true
          },
          "final_order_id": {
            "type": "integer",
            "nullable": true
          },
          "final_order_status": {
            "type": "string",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "$ref": "#/components/schemas/LocalTimestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/LocalTimestamp"
          }
        }
      },
      "DataCatalogue": {
        "type": "object",
        "required": [
          "status",
          "service",
          "count",
          "products"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "service": {
            "type": "string",
            "enum": [
              "data"
            ]
          },
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "products": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataProduct"
            }
          }
        }
      },
      "DataProduct": {
        "type": "object",
        "required": [
          "product_id",
          "network",
          "network_name",
          "description",
          "groupname",
          "amount",
          "sellvalue"
        ],
        "properties": {
          "product_id": {
            "type": "integer",
            "minimum": 1
          },
          "network": {
            "type": "string"
          },
          "network_name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "groupname": {
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/DataPrice"
          },
          "sellvalue": {
            "$ref": "#/components/schemas/DataPrice"
          }
        }
      },
      "DataPrice": {
        "description": "Catalogue sell value in rand. Numeric prices are returned as numbers.",
        "oneOf": [
          {
            "type": "number"
          },
          {
            "type": "string"
          }
        ]
      },
      "VasQueued": {
        "type": "object",
        "required": [
          "status",
          "message",
          "service",
          "order_id",
          "transaction_id",
          "product_id",
          "voucher_type",
          "amount",
          "fee",
          "total_billed_amount",
          "reference",
          "process_status",
          "billing_status",
          "timestamp"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "message": {
            "type": "string"
          },
          "service": {
            "type": "string",
            "enum": [
              "vas"
            ]
          },
          "order_id": {
            "type": "integer",
            "minimum": 1
          },
          "transaction_id": {
            "type": "string",
            "format": "uuid"
          },
          "product_id": {
            "type": "integer",
            "minimum": 1
          },
          "voucher_type": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "fee": {
            "type": "number"
          },
          "total_billed_amount": {
            "type": "number"
          },
          "reference": {
            "type": "string"
          },
          "process_status": {
            "type": "string",
            "enum": [
              "Pending",
              "Submitted",
              "Completed",
              "Failed",
              "Reconcile"
            ]
          },
          "billing_status": {
            "type": "string",
            "enum": [
              "pending",
              "billed",
              "failed",
              "not_required"
            ]
          },
          "timestamp": {
            "$ref": "#/components/schemas/LocalTimestamp"
          }
        }
      },
      "VasStatus": {
        "type": "object",
        "required": [
          "status",
          "message",
          "service",
          "order_id",
          "transaction_id",
          "product_id",
          "voucher_type",
          "amount",
          "fee",
          "total_billed_amount",
          "reference",
          "process_status",
          "billing_status",
          "supplier_http_status",
          "supplier_error",
          "created_at",
          "submitted_at",
          "completed_at",
          "updated_at"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "failed"
            ]
          },
          "message": {
            "type": "string"
          },
          "service": {
            "type": "string",
            "enum": [
              "vas"
            ]
          },
          "order_id": {
            "type": "integer",
            "minimum": 1
          },
          "transaction_id": {
            "type": "string",
            "format": "uuid"
          },
          "product_id": {
            "type": "integer",
            "minimum": 1,
            "nullable": true
          },
          "voucher_type": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "fee": {
            "type": "number"
          },
          "total_billed_amount": {
            "type": "number"
          },
          "reference": {
            "type": "string"
          },
          "process_status": {
            "type": "string",
            "enum": [
              "Pending",
              "Submitted",
              "Completed",
              "Failed",
              "Reconcile"
            ]
          },
          "billing_status": {
            "type": "string",
            "enum": [
              "pending",
              "billed",
              "failed",
              "not_required"
            ]
          },
          "supplier_http_status": {
            "type": "integer",
            "nullable": true
          },
          "supplier_error": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "$ref": "#/components/schemas/LocalTimestamp"
          },
          "submitted_at": {
            "$ref": "#/components/schemas/NullableLocalTimestamp"
          },
          "completed_at": {
            "$ref": "#/components/schemas/NullableLocalTimestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/LocalTimestamp"
          },
          "vouchers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VasVoucher"
            },
            "description": "Returned on success."
          }
        }
      },
      "VasVoucher": {
        "type": "object",
        "required": [
          "voucher_type",
          "voucher_code",
          "value",
          "expiry_date"
        ],
        "properties": {
          "voucher_type": {
            "type": "string",
            "nullable": true
          },
          "voucher_code": {
            "type": "string"
          },
          "value": {
            "type": "number",
            "nullable": true
          },
          "expiry_date": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "VasCatalogue": {
        "type": "object",
        "required": [
          "status",
          "service",
          "count",
          "products"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "service": {
            "type": "string",
            "enum": [
              "vas"
            ]
          },
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "products": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VasProduct"
            }
          }
        }
      },
      "VasProduct": {
        "type": "object",
        "required": [
          "product_id",
          "voucher_type",
          "slug",
          "default_amount",
          "available_amounts",
          "logo_url"
        ],
        "properties": {
          "product_id": {
            "type": "integer",
            "minimum": 1
          },
          "voucher_type": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "default_amount": {
            "type": "number"
          },
          "available_amounts": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "logo_url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        }
      },
      "ElectricityAccepted": {
        "type": "object",
        "required": [
          "status",
          "message",
          "order_id",
          "client_reference",
          "submitted_reference",
          "order_reference_id",
          "meter_number",
          "recipient",
          "send_sms",
          "sms_company_name",
          "amount",
          "electricity_amount",
          "fee",
          "process_status",
          "billing_status",
          "timestamp"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "message": {
            "type": "string"
          },
          "order_id": {
            "type": "integer",
            "minimum": 1
          },
          "client_reference": {
            "type": "string"
          },
          "submitted_reference": {
            "type": "string"
          },
          "order_reference_id": {
            "$ref": "#/components/schemas/SupplierOrderNumber"
          },
          "meter_number": {
            "type": "string"
          },
          "recipient": {
            "type": "string"
          },
          "send_sms": {
            "type": "boolean"
          },
          "sms_company_name": {
            "type": "string"
          },
          "amount": {
            "type": "integer"
          },
          "electricity_amount": {
            "type": "number"
          },
          "fee": {
            "type": "number"
          },
          "process_status": {
            "type": "string",
            "enum": [
              "Pending"
            ]
          },
          "billing_status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "timestamp": {
            "$ref": "#/components/schemas/LocalTimestamp"
          }
        }
      },
      "ElectricityReconciliation": {
        "type": "object",
        "required": [
          "status",
          "code",
          "message",
          "client_reference"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "code": {
            "type": "string",
            "enum": [
              "reconciliation_pending"
            ]
          },
          "message": {
            "type": "string"
          },
          "client_reference": {
            "type": "string"
          },
          "submitted_reference": {
            "type": "string"
          }
        }
      },
      "ElectricityDuplicate": {
        "type": "object",
        "required": [
          "status",
          "code",
          "message"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "code": {
            "type": "string",
            "enum": [
              "duplicate_transaction"
            ]
          },
          "message": {
            "type": "string"
          },
          "retry_after_seconds": {
            "type": "integer",
            "enum": [
              300
            ],
            "description": "Included when the five-minute duplicate rule applies."
          }
        }
      },
      "ElectricityReferenceConflict": {
        "type": "object",
        "required": [
          "status",
          "code",
          "message"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "code": {
            "type": "string",
            "enum": [
              "reference_conflict"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ElectricityRequestInProgress": {
        "type": "object",
        "required": [
          "status",
          "code",
          "message"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "code": {
            "type": "string",
            "enum": [
              "request_in_progress"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ElectricityMeter": {
        "type": "object",
        "required": [
          "status",
          "message",
          "meter_number",
          "supported",
          "provider"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success",
              "unsupported",
              "unknown"
            ]
          },
          "message": {
            "type": "string"
          },
          "meter_number": {
            "type": "string"
          },
          "supported": {
            "type": "boolean",
            "nullable": true,
            "description": "True for success, false for unsupported, null for unknown."
          },
          "provider": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ElectricityPending": {
        "type": "object",
        "required": [
          "status",
          "message"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ElectricityFulfilled": {
        "type": "object",
        "required": [
          "status",
          "order_id",
          "message",
          "transaction_details",
          "entry_instructions",
          "recharge_pin_information"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "order_id": {
            "type": "integer",
            "minimum": 1
          },
          "message": {
            "type": "string"
          },
          "transaction_details": {
            "$ref": "#/components/schemas/ElectricityTransactionDetails"
          },
          "entry_instructions": {
            "type": "string"
          },
          "recharge_pin_information": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/ElectricityPin"
            },
            "description": "PINs in the order they must be entered."
          }
        }
      },
      "ElectricityFailed": {
        "type": "object",
        "required": [
          "status",
          "order_id",
          "message",
          "transaction_details"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "failed",
              "cancelled"
            ]
          },
          "order_id": {
            "type": "integer",
            "minimum": 1
          },
          "message": {
            "type": "string"
          },
          "transaction_details": {
            "$ref": "#/components/schemas/ElectricityTransactionDetails"
          }
        }
      },
      "ElectricityTransactionDetails": {
        "type": "object",
        "required": [
          "reference",
          "amount",
          "recipient",
          "meter_number",
          "network",
          "date",
          "utility"
        ],
        "properties": {
          "reference": {
            "$ref": "#/components/schemas/SupplierValue"
          },
          "amount": {
            "$ref": "#/components/schemas/SupplierValue"
          },
          "recipient": {
            "$ref": "#/components/schemas/SupplierValue"
          },
          "meter_number": {
            "$ref": "#/components/schemas/SupplierValue"
          },
          "network": {
            "type": "string",
            "enum": [
              "Electricity"
            ]
          },
          "date": {
            "$ref": "#/components/schemas/NullableLocalTimestamp"
          },
          "utility": {
            "type": "string"
          }
        }
      },
      "SupplierValue": {
        "description": "Value as supplied by the municipality, or null when unavailable.",
        "oneOf": [
          {
            "type": "string",
            "nullable": true
          },
          {
            "type": "number"
          }
        ]
      },
      "ElectricityPin": {
        "type": "object",
        "required": [
          "entry_order",
          "description",
          "pin",
          "units"
        ],
        "properties": {
          "entry_order": {
            "type": "integer",
            "nullable": true
          },
          "description": {
            "type": "string",
            "enum": [
              "KEY-CHANGE-1",
              "KEY-CHANGE-2",
              "PURCHASE",
              "FREE_UNITS",
              "PIN"
            ]
          },
          "pin": {
            "type": "string"
          },
          "units": {
            "type": "string"
          }
        }
      },
      "WalletBalance": {
        "type": "object",
        "required": [
          "status",
          "user_id",
          "username",
          "name",
          "balance",
          "updated_at"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "user_id": {
            "type": "integer",
            "minimum": 1
          },
          "username": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string"
          },
          "balance": {
            "type": "number",
            "description": "Last known balance in rand."
          },
          "updated_at": {
            "$ref": "#/components/schemas/NullableLocalTimestamp"
          }
        }
      },
      "NetworkLookup": {
        "type": "object",
        "required": [
          "status",
          "msisdn",
          "network"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "msisdn": {
            "type": "string"
          },
          "network": {
            "type": "string",
            "description": "Detected network name as returned by the lookup provider.",
            "example": "mtn"
          }
        }
      },
      "TransactionService": {
        "type": "string",
        "enum": [
          "airtime",
          "data",
          "electricity",
          "vas",
          "sms"
        ]
      },
      "TransactionHistory": {
        "type": "object",
        "required": [
          "status",
          "date_from",
          "date_to",
          "type",
          "transactions",
          "pagination"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "date_from": {
            "type": "string",
            "format": "date"
          },
          "date_to": {
            "type": "string",
            "format": "date"
          },
          "type": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionService"
            },
            "nullable": true,
            "description": "Active service filter, or null when all services are included."
          },
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transaction"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/TransactionPagination"
          }
        }
      },
      "Transaction": {
        "type": "object",
        "required": [
          "id",
          "service",
          "status",
          "reason",
          "reference",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "service": {
            "$ref": "#/components/schemas/TransactionService"
          },
          "status": {
            "type": "string",
            "enum": [
              "success",
              "failed",
              "pending"
            ]
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "reference": {
            "type": "string"
          },
          "created_at": {
            "$ref": "#/components/schemas/LocalTimestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/NullableLocalTimestamp"
          }
        }
      },
      "TransactionPagination": {
        "type": "object",
        "required": [
          "limit",
          "next_cursor"
        ],
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass unchanged with the same dates and service filter. Null marks the last page."
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid Bearer token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Missing or invalid request parameters.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DuplicateRecharge": {
        "description": "An order for the same MSISDN and amount already exists within the five-minute duplicate window. Check the existing order before resubmitting.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "API temporarily unavailable. Honour Retry-After when present.",
        "headers": {
          "Retry-After": {
            "description": "Suggested delay in seconds before retrying a read request.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QueueBusy": {
        "description": "The order queue is busy. Check for an existing request before retrying.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ElectricityReconciliation": {
        "description": "Purchase reconciliation pending. Poll GET with the original or returned client reference.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ElectricityReconciliation"
            }
          }
        }
      }
    },
    "parameters": {
      "RechargeRequestId": {
        "name": "request_id",
        "in": "query",
        "required": false,
        "description": "Queue identifier returned by POST. Takes precedence over orderno when both are supplied.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "RechargeOrderNumber": {
        "name": "orderno",
        "in": "query",
        "required": false,
        "description": "Platform order number from platform_order_number in a status response.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      }
    }
  }
}
