{
  "openapi": "3.0.0",
  "info": {
    "title": "Amabills - Whoosh Core API",
    "version": "1.1.0",
    "description": "The Whoosh Innovations Pty. Core API provides electricity vending and traffic fine services for South African municipalities.\n"
  },
  "servers": [
    {
      "url": "https://api-test.amabills.co.za/api",
      "description": "Testing"
    },
    {
      "url": "https://api.amabills.co.za/api",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-KEY"
      }
    },
    "schemas": {
      "SuccessEnvelopeBoolean": {
        "type": "object",
        "description": "Standard response envelope used by Electricity endpoints.",
        "properties": {
          "success": {
            "example": true,
            "type": "boolean",
            "description": "`true` - action successful, result is in `data`. `false` - error occurred, details are in `error` and `errorNo`."
          },
          "data": {
            "description": "Result payload. `null` when `success` is `false`.",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true,
            "example": "999 - Internal server error",
            "description": "Human-readable error message. `null` when `success` is `true`."
          },
          "errorNo": {
            "type": "integer",
            "nullable": true,
            "example": 999,
            "description": "Error code. `null` when `success` is `true`."
          }
        }
      },
      "Municipality": {
        "type": "string",
        "enum": [
          "tshwane_prepaid",
          "zeerust_prepaid",
          "mogale_prepaid",
          "ngwathe_prepaid",
          "mogale_postpaid",
          "tshwane_postpaid"
        ],
        "description": "Municipality identifier. Municipalities ending in `_prepaid` support token vending;  Municipalities ending in `_postpaid` supports postpaid bill payments."
      },
      "BillMunicipality": {
        "type": "string",
        "enum": [
          "mogale_postpaid",
          "tshwane_postpaid"
        ],
        "description": "Postpaid municipal account issuer. Accepted by the Bills endpoints only."
      },
      "ElectricityCustomer": {
        "type": "object",
        "description": "Details of the meter owner returned by ConfirmCustomer.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Meter number (same as `meter_number`).",
            "example": "142567423303"
          },
          "meter_number": {
            "type": "string",
            "description": "Meter number.",
            "example": "142567423303"
          },
          "meter_source": {
            "$ref": "#/components/schemas/Municipality"
          },
          "name": {
            "type": "string",
            "description": "Surname of the meter owner.",
            "example": "TSHITAMBA"
          },
          "phone_number": {
            "type": "string",
            "nullable": true,
            "description": "Phone number of the meter owner. `null` if not provided by the municipality."
          },
          "email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "description": "Email of the meter owner. `null` if not provided by the municipality."
          },
          "provider_specific": {
            "type": "object",
            "description": "Municipality-specific metadata. Shape varies per provider.",
            "properties": {
              "token": {
                "type": "string",
                "description": "Printable slip that can be presented to the customer."
              },
              "name": {
                "type": "string"
              },
              "firstName": {
                "type": "string"
              },
              "pocName": {
                "type": "string"
              },
              "minLimit": {
                "type": "integer"
              },
              "maxLimit": {
                "type": "integer"
              },
              "tarrifIndex": {
                "type": "integer"
              },
              "sgc": {
                "type": "integer"
              },
              "krn": {
                "type": "integer"
              },
              "keyExpiryNumber": {
                "type": "integer"
              },
              "tokenTechnology": {
                "type": "integer"
              },
              "units": {
                "type": "number"
              }
            }
          }
        }
      },
      "ConfirmCustomerResult": {
        "type": "object",
        "properties": {
          "exists": {
            "type": "boolean",
            "description": "`true` if the meter number was validated and can be used to vend electricity or pay bills."
          },
          "municipality": {
            "$ref": "#/components/schemas/Municipality"
          },
          "customer": {
            "$ref": "#/components/schemas/ElectricityCustomer"
          }
        }
      },
      "PurchaseElectricityResult": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Full name of the person linked to the meter.",
            "example": "MR. A J KWINDA"
          },
          "amount": {
            "type": "number",
            "description": "Amount transacted.",
            "example": 50
          },
          "meter": {
            "type": "string",
            "description": "Meter number used for the transaction.",
            "example": "81114926223"
          },
          "date": {
            "type": "string",
            "description": "Date-time string. Format: \"DD mmm YYYY hh:mm:ss AM/PM\".",
            "example": "22 Mar 2026 3:24:11 PM"
          },
          "timestamp": {
            "type": "integer",
            "format": "int64",
            "description": "Transaction date-time as a UNIX timestamp in milliseconds.",
            "example": 1774193051166
          },
          "token": {
            "type": "string",
            "nullable": true,
            "description": "**Prepaid only.** The vended token including the full printable receipt. `null` for postpaid municipalities."
          },
          "tokenCount": {
            "type": "integer",
            "nullable": true,
            "description": "Total number of new tokens generated. `null` for postpaid.",
            "example": 1
          },
          "units": {
            "type": "number",
            "nullable": true,
            "description": "Total electricity units vended. `null` for postpaid.",
            "example": 2.9
          },
          "receipt": {
            "type": "string",
            "nullable": true,
            "description": "**Postpaid only.** URL with the purchase receipt proving bill offset. `null` for prepaid municipalities."
          },
          "municipality": {
            "$ref": "#/components/schemas/Municipality"
          },
          "mode": {
            "type": "integer",
            "description": "`0` = prepaid token vend, `1` = postpaid bill payment.",
            "example": 0
          },
          "details": {
            "type": "object",
            "description": "Low-level transaction details from the municipality gateway.",
            "properties": {
              "balance": {
                "type": "number"
              },
              "code": {
                "type": "integer"
              },
              "date": {
                "type": "string"
              },
              "desc": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "refno": {
                "type": "string"
              },
              "time": {
                "type": "string"
              },
              "trDetails": {
                "type": "object",
                "properties": {
                  "amt": {
                    "type": "number"
                  },
                  "date": {
                    "type": "string"
                  },
                  "no": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string"
                  },
                  "time": {
                    "type": "string"
                  },
                  "vat": {
                    "type": "number"
                  }
                }
              },
              "voucher": {
                "type": "object",
                "properties": {
                  "amounts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "desc": {
                          "type": "string"
                        },
                        "amt": {
                          "type": "number"
                        },
                        "outstanding": {
                          "type": "number"
                        }
                      }
                    }
                  },
                  "elecamt": {
                    "type": "number"
                  },
                  "message": {
                    "type": "string"
                  },
                  "meterno": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "receiptdesc": {
                    "type": "string"
                  },
                  "receiptno": {
                    "type": "string"
                  },
                  "receiver": {
                    "type": "string"
                  },
                  "token": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "token": {
                          "type": "string"
                        },
                        "info": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "units": {
                    "type": "number"
                  },
                  "vatno": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "meterDetails": {
            "type": "object",
            "properties": {
              "msno": {
                "type": "string"
              },
              "sgc": {
                "type": "integer"
              },
              "krn": {
                "type": "integer"
              },
              "ti": {
                "type": "integer"
              }
            }
          }
        }
      },
      "BalanceService": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "number",
            "description": "Current balance for this service."
          },
          "type": {
            "type": "string",
            "description": "Service type name (e.g. `prepaid-electricity`)."
          },
          "service_specification": {
            "type": "string",
            "description": "Municipality identifier for this service slot."
          },
          "nTransactions": {
            "type": "integer",
            "description": "Total number of transactions recorded against this service."
          },
          "receipts": {
            "type": "array",
            "nullable": true,
            "description": "Transactions within the requested period. Only present when `printReceipts` is `true`.",
            "items": {
              "$ref": "#/components/schemas/VasReceipt"
            }
          }
        }
      },
      "VasReceipt": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "topup",
              "deposited"
            ]
          },
          "timestamp": {
            "type": "integer",
            "format": "int64"
          },
          "amount": {
            "type": "number"
          },
          "meterNumber": {
            "type": "string",
            "nullable": true
          },
          "receipt": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ReceiptsConfiguration": {
        "type": "object",
        "required": [
          "from"
        ],
        "properties": {
          "from": {
            "type": "integer",
            "format": "int64",
            "description": "UNIX timestamp (ms) – start of the period."
          },
          "to": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "UNIX timestamp (ms) – end of the period. Defaults to now if omitted."
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "number",
            "description": "Total balance across all consumed prepaid VAS services."
          },
          "payments": {
            "type": "object",
            "properties": {
              "lastPaymentValue": {
                "type": "number"
              },
              "nPayments": {
                "type": "integer"
              },
              "paymentsTotal": {
                "type": "number"
              }
            }
          },
          "services": {
            "type": "array",
            "description": "Balance breakdown per prepaid service.",
            "items": {
              "$ref": "#/components/schemas/BalanceService"
            }
          },
          "timestamp": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ErrorMessage": {
        "type": "object",
        "description": "Unified error type returned in the `error` field of all Traffic Fine responses when `success` is `true`."
      },
      "ErrorMessagePayment": {
        "type": "object",
        "description": "Unified error type returned in the `error` field of all Traffic Fine responses when `success` is `1`.",
        "properties": {
          "code": {
            "type": "integer",
            "description": "Error code.\n| Code | Meaning | |------|---------| | 1 | Authentication failed | | 2 | Service unavailable – try again; contact support if it persists | | 3 | Service error – contact support | | 5 | Invalid ID | | 6 | ID must be numeric | | 7 | ID number check digit must be valid | | 8 | The identified infringer does not exist | | 9 | No infringement found for the identification type or number | | 10 | The check digit of the infringement notice number must be valid | | 11 | The infringement notice number must be payable at a registering authority | | 12 | The infringement notice number does not exist | | 13 | The infringement notice number does not exist | | 14 | The infringement notice number may not be in status 10 (court case) | | 15 | Elected to be tried in court with a successful court application status | | 16 | Transaction not allowed – nomination of driver is pending | | 17 | Partially paid fine must be settled at a registering authority or DLTS | | 18 | The infringement may not be in status 13 (partially paid) | | 23 | Validation error |",
            "example": 9
          },
          "message": {
            "type": "string",
            "description": "Well-explained error message.",
            "example": "No infringement found for the provided ID number."
          },
          "validationMessage": {
            "type": "array",
            "nullable": true,
            "description": "Descriptive list of validation error messages. Present when `code` is `23`.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "IssAuthority": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Authority code.",
            "example": "4065"
          },
          "description": {
            "type": "string",
            "description": "Authority name.",
            "example": "GP Dept of Community Safety."
          }
        }
      },
      "InfringementLocation": {
        "type": "object",
        "properties": {
          "cityTown": {
            "type": "string",
            "description": "City or town where the infringement took place.",
            "example": "JOHANNESBURG"
          },
          "issAuthority": {
            "$ref": "#/components/schemas/IssAuthority"
          },
          "streetName": {
            "type": "string",
            "description": "Street on which the infringement took place.",
            "example": "N1"
          },
          "suburb": {
            "type": "string",
            "description": "Suburb in which the infringement was recorded.",
            "example": "JOHANNESBURG"
          }
        }
      },
      "InfringementCharge": {
        "type": "object",
        "properties": {
          "classification": {
            "type": "string",
            "description": "Fine classification.",
            "example": "Operated a vehicle without displaying..."
          },
          "demeritPoints": {
            "type": "integer",
            "description": "Demerit points tied to this infringement.",
            "example": 0
          },
          "description": {
            "type": "string",
            "description": "Detailed description of the charge.",
            "example": "Operated a vehicle without displaying the licence disc of said vehicle"
          }
        }
      },
      "InfringementDetail": {
        "type": "object",
        "properties": {
          "vehicleLicenseNumber": {
            "type": "string",
            "description": "Licence number of the vehicle that infringed.",
            "example": "JR47HJGP"
          },
          "noticeNumber": {
            "type": "string",
            "description": "Notice number tied to the infringement.",
            "example": "0100110373510309"
          },
          "charge": {
            "$ref": "#/components/schemas/InfringementCharge"
          },
          "date": {
            "type": "string",
            "description": "Date on which the infringement took place (YYYY-MM-DD).",
            "example": "2023-01-22"
          },
          "time": {
            "type": "string",
            "description": "Time at which the infringement took place (hh:mm:ss).",
            "example": "10:38:00"
          },
          "location": {
            "$ref": "#/components/schemas/InfringementLocation"
          },
          "netFineAmnt": {
            "type": "number",
            "description": "Net fine amount for this infringement.",
            "example": 560
          },
          "vendorFeeAmnt": {
            "type": "number",
            "description": "Vendor processing fee for this infringement.",
            "example": 14
          },
          "grossAmnt": {
            "type": "number",
            "description": "Total amount to charge the customer (net + vendor fee).",
            "example": 574
          },
          "isPaid": {
            "type": "boolean",
            "description": "Whether this infringement has already been paid.",
            "example": false
          }
        }
      },
      "QueryByIdNumberResult": {
        "type": "object",
        "properties": {
          "idNumber": {
            "type": "string",
            "description": "The ID number used in the query.",
            "example": "9710226013089"
          },
          "hasFinesToPay": {
            "type": "boolean",
            "description": "Whether there are outstanding fines for this ID.",
            "example": true
          },
          "netFinesAmnt": {
            "type": "number",
            "description": "Total net amount for all outstanding fines.",
            "example": 560
          },
          "vendorFeeAmnt": {
            "type": "number",
            "description": "Total vendor processing fee for all outstanding fines.",
            "example": 14
          },
          "grossAmnt": {
            "type": "number",
            "description": "Total amount to charge the customer across all outstanding fines.",
            "example": 574
          },
          "infringements": {
            "type": "array",
            "description": "List of infringements tied to the ID number.",
            "items": {
              "$ref": "#/components/schemas/InfringementDetail"
            }
          }
        }
      },
      "QueryByNoticeNumberResult": {
        "type": "object",
        "properties": {
          "noticeNumber": {
            "type": "string",
            "description": "The notice number used in the query.",
            "example": "0100110373510309"
          },
          "hasFinesToPay": {
            "type": "boolean",
            "description": "Whether there are outstanding fines for this notice number.",
            "example": true
          },
          "netFinesAmnt": {
            "type": "number",
            "description": "Total net amount for all outstanding fines.",
            "example": 560
          },
          "vendorFeeAmnt": {
            "type": "number",
            "description": "Total vendor processing fee.",
            "example": 14
          },
          "grossAmnt": {
            "type": "number",
            "description": "Total amount to charge the customer.",
            "example": 574
          },
          "infringements": {
            "type": "array",
            "description": "Infringements tied to the notice number.",
            "items": {
              "$ref": "#/components/schemas/InfringementDetail"
            }
          }
        }
      },
      "MarkFineAsPaidCommand": {
        "type": "object",
        "required": [
          "noticeNumber",
          "amount",
          "currency"
        ],
        "properties": {
          "noticeNumber": {
            "type": "string",
            "description": "Notice number of the fine being marked as paid.",
            "example": "0100110373510309"
          },
          "amount": {
            "type": "number",
            "description": "Gross amount paid for this fine (net fine + vendor fee).",
            "example": 574
          },
          "currency": {
            "type": "string",
            "description": "Currency code.",
            "example": "ZAR"
          }
        }
      },
      "PaidFine": {
        "type": "object",
        "properties": {
          "noticeNumber": {
            "type": "string",
            "description": "Notice number of the paid fine.",
            "example": "240990007600759"
          },
          "invoiceNumber": {
            "type": "string",
            "description": "AARTO invoice number.",
            "example": "47280000005V"
          },
          "receiptNumber": {
            "type": "string",
            "description": "AARTO receipt number.",
            "example": "4728000000N1"
          },
          "netFinesAmntPaid": {
            "type": "number",
            "description": "Net fine amount attributed to this fine.",
            "example": 1600
          },
          "vendorFeeAmntPaid": {
            "type": "number",
            "description": "Vendor fee attributed to this fine.",
            "example": 14
          },
          "grossAmntPaid": {
            "type": "number",
            "description": "Total amount paid for this fine.",
            "example": 1614
          }
        }
      },
      "MarkTrafficFinesAsPaidResult": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Whoosh order ID referencing the complete transaction.",
            "example": "b89a1717-5266-43c7-93cc-7e51c0fe01fb"
          },
          "grossAmntPaid": {
            "type": "number",
            "description": "Total gross amount paid across all fines in this transaction.",
            "example": 1614
          },
          "netFinesAmntPaid": {
            "type": "number",
            "description": "Total net fine amount paid.",
            "example": 1600
          },
          "vendorFeeAmntPaid": {
            "type": "number",
            "description": "Total vendor fee paid.",
            "example": 14
          },
          "merchantFeePaid": {
            "type": "number",
            "description": "Merchant fee charged for this transaction.",
            "example": 7.5
          },
          "finesPaid": {
            "type": "array",
            "description": "Breakdown of each fine paid including AARTO receipt details.",
            "items": {
              "$ref": "#/components/schemas/PaidFine"
            }
          }
        }
      },
      "ValidatePaymentResult": {
        "type": "object",
        "properties": {
          "amntToPay": {
            "type": "number",
            "description": "Correct gross amount that should be charged for the selected fines.",
            "example": 574
          },
          "difference": {
            "type": "number",
            "description": "Difference between the proposed amount and the correct amount. `0` means the proposed amount is correct. If the proposed amount is less than the amtToPay then this value will be negative",
            "example": 0
          },
          "isCorrectAmount": {
            "type": "boolean",
            "description": "`true` if the proposed amount matches the expected gross amount for the selected fines.",
            "example": true
          }
        }
      },
      "TransactionDto": {
        "type": "object",
        "description": "A single MPGS transaction returned in the end-of-day ledger.",
        "properties": {
          "paymentReference": {
            "type": "string",
            "description": "Payment reference for the transaction.",
            "example": "ORD-20240401-001"
          },
          "transactionStatus": {
            "type": "string",
            "description": "MPGS transaction status.",
            "example": "SUCCESS"
          },
          "transactionAmount": {
            "type": "number",
            "description": "Transaction amount.",
            "example": 150
          },
          "transactionCurrency": {
            "type": "string",
            "description": "ISO 4217 currency code.",
            "example": "ZAR"
          },
          "transactionTime": {
            "type": "string",
            "format": "date-time",
            "description": "ISO timestamp of when the transaction occurred.",
            "example": "2024-04-01T14:32:00+02:00"
          }
        }
      },
      "VerificationErrorDto": {
        "type": "object",
        "description": "A reconciliation or verification error.",
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable error details.",
            "example": "Transaction amount mismatch detected."
          }
        }
      },
      "EndOfDayLedgerResponse": {
        "type": "object",
        "description": "Response body for the End of Day Ledger endpoint.",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "`true` when the request was processed successfully.",
            "example": true
          },
          "merchantId": {
            "type": "string",
            "description": "Merchant identifier derived from the API key.",
            "example": "MERCH-001"
          },
          "timezone": {
            "type": "string",
            "description": "Always `Africa/Johannesburg`.",
            "example": "Africa/Johannesburg"
          },
          "businessDate": {
            "type": "string",
            "format": "date",
            "description": "The reconciled business date (YYYY-MM-DD).",
            "example": "2024-04-01"
          },
          "periodStart": {
            "type": "string",
            "format": "date-time",
            "description": "Start of the business day as an ISO timestamp.",
            "example": "2024-04-01T00:00:00+02:00"
          },
          "periodEnd": {
            "type": "string",
            "format": "date-time",
            "description": "End of the business day as an ISO timestamp.",
            "example": "2024-04-01T23:59:59+02:00"
          },
          "generatedOn": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when this response was generated.",
            "example": "2024-04-02T06:05:00+02:00"
          },
          "transactionCount": {
            "type": "integer",
            "description": "Total number of transactions returned.",
            "example": 42
          },
          "totalAmount": {
            "type": "number",
            "description": "Sum of all transaction amounts.",
            "example": 8750
          },
          "verificationErrorCount": {
            "type": "integer",
            "description": "Number of verification errors encountered.",
            "example": 0
          },
          "transactions": {
            "type": "array",
            "description": "List of MPGS transactions for the business day.",
            "items": {
              "$ref": "#/components/schemas/TransactionDto"
            }
          },
          "verificationErrors": {
            "type": "array",
            "description": "List of verification errors, if any.",
            "items": {
              "$ref": "#/components/schemas/VerificationErrorDto"
            }
          }
        }
      },
      "OrderPaymentStatusResponse": {
        "type": "object",
        "description": "Response body for the Order Payment Status endpoint.",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "`true` when the request was processed successfully.",
            "example": true
          },
          "merchantId": {
            "type": "string",
            "description": "Merchant identifier derived from the API key.",
            "example": "MERCH-001"
          },
          "orderId": {
            "type": "string",
            "description": "The order ID that was checked.",
            "example": "ORD-20240401-001"
          },
          "checkedOn": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the status verification was performed.",
            "example": "2024-04-02T06:10:00+02:00"
          },
          "paymentStatus": {
            "type": "string",
            "description": "Overall payment status for the order.",
            "enum": [
              "PAID",
              "PENDING",
              "FAILED",
              "NO_ATTEMPT",
              "VERIFICATION_ERROR"
            ],
            "example": "PAID"
          },
          "paymentReference": {
            "type": "string",
            "description": "Primary transaction reference (same as `orderId`).",
            "example": "ORD-20240401-001"
          },
          "transactionStatus": {
            "type": "string",
            "description": "Raw MPGS transaction status.",
            "example": "SUCCESS"
          },
          "transactionAmount": {
            "type": "number",
            "description": "Transaction amount.",
            "example": 150
          },
          "transactionCurrency": {
            "type": "string",
            "description": "ISO 4217 currency code.",
            "example": "ZAR"
          },
          "transactionTime": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the transaction.",
            "example": "2024-04-01T14:32:00+02:00"
          },
          "verificationErrors": {
            "type": "array",
            "description": "Verification errors, if any.",
            "items": {
              "$ref": "#/components/schemas/VerificationErrorDto"
            }
          }
        }
      },
      "OrderPaymentStatusErrorResponse": {
        "type": "object",
        "description": "Error response body for the Order Payment Status endpoint (400, 403, 404 and 500). Same shape as `OrderPaymentStatusResponse` plus `id` and `referrer`, which are always empty strings on error.",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "id": {
            "type": "string",
            "example": ""
          },
          "referrer": {
            "type": "string",
            "example": ""
          },
          "merchantId": {
            "type": "string"
          },
          "orderId": {
            "type": "string"
          },
          "checkedOn": {
            "type": "string",
            "format": "date-time"
          },
          "paymentStatus": {
            "type": "string",
            "enum": [
              "VERIFICATION_ERROR"
            ],
            "example": "VERIFICATION_ERROR"
          },
          "paymentReference": {
            "type": "string",
            "example": ""
          },
          "transactionStatus": {
            "type": "string",
            "example": "UNKNOWN"
          },
          "transactionAmount": {
            "type": "number",
            "example": 0
          },
          "transactionCurrency": {
            "type": "string",
            "example": "ZAR"
          },
          "transactionTime": {
            "type": "string",
            "format": "date-time"
          },
          "verificationErrors": {
            "type": "array",
            "description": "Always contains exactly one entry describing the failure.",
            "items": {
              "$ref": "#/components/schemas/VerificationErrorDto"
            }
          }
        }
      },
      "LineItemDto": {
        "type": "object",
        "description": "An individual product or service line item within an order.",
        "required": [
          "id",
          "productId",
          "name",
          "unitPrice",
          "currency",
          "quantity"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Line item ID (internal reference).",
            "example": "MOG-123456"
          },
          "productId": {
            "type": "string",
            "description": "Product or service ID.",
            "example": "municipal-bill"
          },
          "name": {
            "type": "string",
            "description": "Display name of the item shown on checkout and receipts.",
            "example": "Municipal Bill Payment"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Optional item description shown on checkout and receipts.",
            "example": "Municipal bill payment for MOG-123456 of amount 1200"
          },
          "unitPrice": {
            "type": "number",
            "description": "Price per unit.",
            "example": 1200
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code. Must match the order currency.",
            "enum": [
              "ZAR"
            ],
            "example": "ZAR"
          },
          "quantity": {
            "type": "number",
            "description": "Number of units purchased.",
            "example": 1
          },
          "lineTotal": {
            "type": "number",
            "nullable": true,
            "description": "Total for this line item (`unitPrice × quantity`).",
            "example": 1200
          },
          "vat": {
            "type": "number",
            "nullable": true,
            "description": "VAT percentage applied to this line item.",
            "example": 0
          },
          "vatAmount": {
            "type": "number",
            "nullable": true,
            "description": "VAT amount for this line item.",
            "example": 0
          },
          "discount": {
            "type": "array",
            "nullable": true,
            "description": "Discounts applied to this line item.",
            "items": {
              "type": "number"
            }
          },
          "imageUrls": {
            "type": "array",
            "nullable": true,
            "description": "Product image URLs for UI display.",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "descriptions": {
            "type": "array",
            "nullable": true,
            "description": "Additional descriptions for UI display.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "OrderDto": {
        "type": "object",
        "description": "Commercial transaction details for the order being submitted for payment.",
        "required": [
          "id",
          "date",
          "orderDescription",
          "orderTotal",
          "currency",
          "products"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Vendor's internal order ID. Maps to `order.reference` in the Whoosh Payment Gateway.",
            "example": "TRF-20240215-001"
          },
          "refferer": {
            "type": "string",
            "nullable": true,
            "description": "Original order reference for reference mapping.",
            "example": "TRF-20240215-001"
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Order creation timestamp.",
            "example": "2024-02-15T10:30:00Z"
          },
          "dueDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Optional due date for the order.",
            "example": "2024-02-15T10:30:00Z"
          },
          "orderDescription": {
            "type": "string",
            "description": "Description shown on checkout and receipts.",
            "example": "Municipal Bill Payment"
          },
          "orderTotal": {
            "type": "number",
            "description": "Total payable amount. Maps to `order.amount` in the Whoosh Payment Gateway.",
            "example": 2450
          },
          "vatTotal": {
            "type": "number",
            "nullable": true,
            "description": "VAT portion of the order total.",
            "example": 0
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 transaction currency.",
            "enum": [
              "ZAR"
            ],
            "example": "ZAR"
          },
          "products": {
            "type": "array",
            "description": "Order line items used for receipts, reporting, and customer transparency.",
            "items": {
              "$ref": "#/components/schemas/LineItemDto"
            }
          }
        }
      },
      "PutOrderCommand": {
        "type": "object",
        "description": "Request body for creating an order and generating a Whoosh Payment Gateway hosted checkout URL.",
        "required": [
          "merchantId",
          "order",
          "redirectSuccess",
          "redirectCancel"
        ],
        "properties": {
          "merchantId": {
            "type": "string",
            "description": "Identifies the merchant creating the order. Use `staging` for the test environment. A production `merchantId` will be issued before go-live.",
            "example": "staging"
          },
          "order": {
            "$ref": "#/components/schemas/OrderDto"
          },
          "redirectSuccess": {
            "type": "string",
            "format": "uri",
            "description": "URL the customer is redirected to after a successful payment. Maps to `successUrl` in the Whoosh Payment Gateway.",
            "example": "https://placeholder.com"
          },
          "redirectCancel": {
            "type": "string",
            "format": "uri",
            "description": "URL the customer is redirected to after cancellation or failure. Maps to `cancelUrl` in the Whoosh Payment Gateway.",
            "example": "https://placeholder.com"
          },
          "platform": {
            "type": "string",
            "nullable": true,
            "description": "Source platform identifier used for reconciliation reporting.",
            "example": "MOG"
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "Arbitrary key-value pairs stored by Whoosh for reporting. Not forwarded to the Whoosh Payment Gateway.",
            "additionalProperties": true,
            "example": {
              "orgId": "TEST-ORG-001",
              "userId": "JABS78t8ABK"
            }
          }
        }
      },
      "PutOrderResponse": {
        "type": "object",
        "description": "Response returned after successfully creating an order.",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Internal Whoosh order ID.",
            "example": "whoosh-order-abc123"
          },
          "referredId": {
            "type": "string",
            "description": "Vendor's original order ID (echoed back).",
            "example": "TRF-20240215-001"
          },
          "paymentPageUrl": {
            "type": "string",
            "format": "uri",
            "description": "Whoosh Payment Gateway hosted checkout URL to redirect the customer to for payment.",
            "example": "https://payments.whoosh.example.com/pay/abc123"
          },
          "successCallback": {
            "type": "string",
            "format": "uri",
            "description": "Final success redirect URL.",
            "example": "https://placeholder.com"
          },
          "failCallback": {
            "type": "string",
            "format": "uri",
            "description": "Final failure redirect URL.",
            "example": "https://placeholder.com"
          }
        }
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Electricity",
      "description": "Prepaid token vending for Tshwane, Mogale, Zeerust, and Ngwathe municipalities. `Purchase` and `ConfirmCustomer` also still accept postpaid meter numbers for backwards compatibility — new integrations should use the `Bills` endpoints for postpaid municipal accounts instead."
    },
    {
      "name": "Bills",
      "description": "Postpaid municipal bill payments for Tshwane and Mogale accounts, identified by account number rather than meter number."
    },
    {
      "name": "VAS",
      "description": "Value-added services (airtime, data, etc.)."
    },
    {
      "name": "Traffic Fines",
      "description": "Traffic fine lookups, payment validation, and payment marking via the AARTO system."
    },
    {
      "name": "Whoosh Payments",
      "description": "Order creation and Whoosh Payment Gateway checkout initiation. Use these endpoints to create an order on the Whoosh platform and obtain a payment URL to redirect customers for secure card capture.\nThere also reconciliation and payment status verification endpoints. Use these to retrieve end-of-day transaction ledgers and verify the payment status of individual orders."
    }
  ],
  "paths": {
    "/v2/Electricity/ConfirmCustomer": {
      "post": {
        "operationId": "confirmCustomer",
        "summary": "Confirm Customer",
        "description": "Verifies that a meter number exists and is eligible for electricity vending or bill payment. Call this before purchasing to avoid higher latency — if you vend with an unknown meter number the system runs an implicit lookup first.",
        "tags": [
          "Electricity"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "meterNumber"
                ],
                "properties": {
                  "meterNumber": {
                    "type": "string",
                    "description": "Meter number to confirm.",
                    "example": "142567423303"
                  },
                  "municipality": {
                    "$ref": "#/components/schemas/Municipality",
                    "description": "Municipality the meter belongs to. If omitted the system multi-casts to all known municipalities (slower)."
                  },
                  "amount": {
                    "type": "number",
                    "description": "Intended purchase amount (used for credit pre-checking)."
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "cash",
                      "card"
                    ],
                    "description": "Intended payment method."
                  }
                }
              },
              "example": {
                "meterNumber": "0171001182",
                "municipality": "tshwane_prepaid"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer confirmation response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelopeBoolean"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ConfirmCustomerResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "exists": true,
                    "municipality": "tshwane_prepaid",
                    "customer": {
                      "id": "142567423303",
                      "meter_number": "142567423303",
                      "meter_source": "tshwane_prepaid",
                      "name": "TSHITAMBA",
                      "phone_number": null,
                      "email": null,
                      "provider_specific": {
                        "token": "Mr. MT TSHITAMBA\n72 MONOKANE CRESCENT\nLOTUS GARDENS X02\n...",
                        "name": "TSHITAMBA",
                        "firstName": "MT",
                        "pocName": "002303736",
                        "minLimit": 3000,
                        "maxLimit": 0,
                        "tarrifIndex": -1,
                        "sgc": 225,
                        "krn": 1,
                        "keyExpiryNumber": 255,
                        "tokenTechnology": 2,
                        "units": 0
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v2/Electricity/Purchase": {
      "post": {
        "operationId": "purchaseElectricity",
        "summary": "Purchase / Vend Token / Pay Bills",
        "description": "Vends an electricity token (prepaid) or marks a payment against a postpaid running balance.\n\n- **Prepaid** (`tshwane_prepaid`, `mogale_prepaid`, `zeerust_prepaid`, `ngwathe_prepaid`):\n  returns a token string the customer enters into their meter.\n\n- **Postpaid** (`mogale_postpaid`, `tshwane_postpaid`): returns a receipt URL proving bill offset.\n\nUse the `idempotency` field to safely retry failed requests without risk of duplicate vends.\n> **Postpaid bill payments:** if you already know you're paying a postpaid municipal account, prefer the dedicated `Bills/Purchase` and `Bills/ConfirmCustomer` endpoints — they identify the account by `accountNumber` rather than `meterNumber` and drop fields that only apply to prepaid vending.",
        "tags": [
          "Electricity"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "meterNumber",
                  "amount",
                  "method",
                  "municipality"
                ],
                "properties": {
                  "meterNumber": {
                    "type": "string",
                    "example": "04235758721"
                  },
                  "municipality": {
                    "$ref": "#/components/schemas/Municipality"
                  },
                  "amount": {
                    "type": "number",
                    "example": 400
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "cash",
                      "card"
                    ],
                    "example": "cash"
                  },
                  "idempotency": {
                    "type": "string",
                    "description": "Unique string to prevent duplicate vends. A second request with the same value will not result in a second transaction.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  }
                }
              },
              "example": {
                "meterNumber": "04235758721",
                "municipality": "zeerust_prepaid",
                "amount": 400,
                "method": "cash",
                "idempotency": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purchase response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelopeBoolean"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PurchaseElectricityResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "name": "MR. A J KWINDA",
                    "amount": 50,
                    "meter": "81114926223",
                    "date": "22 Mar 2026 3:24:11 PM",
                    "timestamp": 1774193051166,
                    "token": "        City of Tshwane\n        ---------------\nReceipt No.: 109707/29\n...",
                    "tokenCount": 1,
                    "units": 2.9,
                    "receipt": null,
                    "municipality": "tshwane_prepaid",
                    "mode": 0,
                    "details": {
                      "balance": 1,
                      "code": 0,
                      "date": "22 Mar 2026",
                      "desc": "OK",
                      "message": "-",
                      "refno": "7128f265-dc3f-4666-a700-161d50037283",
                      "time": "3:24:11 PM",
                      "trDetails": {
                        "amt": 50,
                        "date": "22 Mar 2026",
                        "no": "109707/871224",
                        "status": "OK",
                        "time": "3:24:11 PM",
                        "vat": 6.52
                      },
                      "voucher": {
                        "amounts": [
                          {
                            "desc": "Arrears",
                            "amt": 0,
                            "outstanding": 0
                          },
                          {
                            "desc": "VAT",
                            "amt": 6.52
                          }
                        ],
                        "elecamt": 43.48,
                        "meterno": "07/07/07064470565",
                        "name": "MR. A J KWINDA",
                        "receiptdesc": "-",
                        "receiptno": "109707/871224",
                        "receiver": "City of TSHWANE",
                        "token": [
                          {
                            "token": "1529 6469 6769 5938 000",
                            "info": "Electricity Credit(2.9)",
                            "type": "CRED"
                          }
                        ],
                        "units": 2.9,
                        "vatno": 4000142267
                      }
                    },
                    "meterDetails": {
                      "msno": "07/07/07064470565",
                      "sgc": 225,
                      "krn": 2,
                      "ti": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v2/Bills/ConfirmCustomer": {
      "post": {
        "operationId": "confirmBillCustomer",
        "summary": "Confirm Customer",
        "description": "Verifies that a postpaid municipal account number exists and returns its current running balance. Call this before `Purchase` to avoid higher latency — if you pay a bill for an unknown account number the system runs an implicit lookup first.",
        "tags": [
          "Bills"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accountNumber"
                ],
                "properties": {
                  "accountNumber": {
                    "type": "string",
                    "description": "Account number to confirm.",
                    "example": "04235758721"
                  },
                  "municipality": {
                    "$ref": "#/components/schemas/BillMunicipality",
                    "description": "Municipality the account belongs to. If omitted the system multi-casts to all known bill municipalities (slower)."
                  },
                  "amount": {
                    "type": "number",
                    "description": "Intended payment amount (used for credit pre-checking)."
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "cash",
                      "card"
                    ],
                    "description": "Intended payment method."
                  }
                }
              },
              "example": {
                "accountNumber": "04235758721",
                "municipality": "mogale_postpaid"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer confirmation response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelopeBoolean"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ConfirmCustomerResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "exists": true,
                    "municipality": "mogale_postpaid",
                    "customer": {
                      "id": "04235758721",
                      "account_number": "04235758721",
                      "account_source": "mogale_postpaid",
                      "name": "MR. A J KWINDA",
                      "balance": 1850,
                      "last_update": "22 Mar 2026 3:24:11 PM",
                      "last_update_timestamp": 1774193051166,
                      "address": "72 MONOKANE CRESCENT, LOTUS GARDENS X02"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v2/Bills/Purchase": {
      "post": {
        "operationId": "purchaseBill",
        "summary": "Purchase / Pay Bill",
        "description": "Pays down a postpaid municipal account's running balance. Unlike `Electricity/Purchase`, no token or kWh amount is returned — only the account's remaining balance.\nThe account is identified by `accountNumber` rather than `meterNumber`, and the request carries none of the prepaid/POS-only fields (`arrears`, `sgc`, `tarrifIndex`, `krn`) accepted by `Electricity/Purchase`.\nUse the `idempotency` field to safely retry failed requests without risk of duplicate payments.",
        "tags": [
          "Bills"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accountNumber",
                  "amount",
                  "method",
                  "municipality",
                  "idempotency"
                ],
                "properties": {
                  "accountNumber": {
                    "type": "string",
                    "description": "Account number of the postpaid bill to pay.",
                    "example": "04235758721"
                  },
                  "municipality": {
                    "$ref": "#/components/schemas/BillMunicipality"
                  },
                  "amount": {
                    "type": "number",
                    "example": 400
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "cash",
                      "card"
                    ],
                    "example": "cash"
                  },
                  "idempotency": {
                    "type": "string",
                    "description": "Unique string to prevent duplicate payments. A second request with the same value will not result in a second transaction.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  }
                }
              },
              "example": {
                "accountNumber": "04235758721",
                "municipality": "mogale_postpaid",
                "amount": 400,
                "method": "cash",
                "idempotency": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bill payment response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelopeBoolean"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PurchaseElectricityResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "name": "MR. A J KWINDA",
                    "amount": 400,
                    "account_number": "04235758721",
                    "date": "22 Mar 2026 3:24:11 PM",
                    "timestamp": 1774193051166,
                    "balance": 1850,
                    "address": "72 MONOKANE CRESCENT, LOTUS GARDENS X02",
                    "municipality": "mogale_postpaid"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/Merchant/CheckBalance": {
      "post": {
        "operationId": "checkBalance",
        "summary": "Check Balance",
        "description": "Returns the authenticated merchant's current credit balance across all consumed prepaid VAS services. Optionally includes a transaction breakdown for a specified period.",
        "tags": [
          "Electricity"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "printReceipts": {
                    "type": "boolean",
                    "default": false,
                    "description": "If `true`, include topup and vend receipts per service for the period defined in `receipts`."
                  },
                  "receipts": {
                    "$ref": "#/components/schemas/ReceiptsConfiguration",
                    "description": "Required when `printReceipts` is `true`."
                  }
                }
              },
              "example": {
                "printReceipts": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balance response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelopeBoolean"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BalanceResponse"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "balance": -10908,
                    "payments": {
                      "lastPaymentValue": 0,
                      "nPayments": 0,
                      "paymentsTotal": 0
                    },
                    "services": [
                      {
                        "balance": 7668,
                        "nTransactions": 149,
                        "type": "prepaid-electricity",
                        "service_specification": "tshwane_prepaid"
                      },
                      {
                        "balance": 944,
                        "nTransactions": 40,
                        "type": "prepaid-electricity",
                        "service_specification": "mogale_prepaid"
                      },
                      {
                        "balance": 1910,
                        "nTransactions": 16,
                        "type": "prepaid-electricity",
                        "service_specification": "zeerust_prepaid"
                      },
                      {
                        "balance": 40,
                        "nTransactions": 2,
                        "type": "prepaid-electricity",
                        "service_specification": "eskom_prepaid"
                      }
                    ],
                    "timestamp": 1774193070098
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/VAS/Confirm": {
      "post": {
        "operationId": "confirmVas",
        "summary": "Confirm VAS",
        "tags": [
          "VAS"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "productID": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "string"
                  },
                  "reference": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "productID": "dde67d01-73ff-4f20-acb2-212e1b22ffcd",
                "amount": "500",
                "reference": "[10,20,30,36,1,4,5,8]"
              }
            }
          }
        },
        "responses": {
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/VAS/Purchase": {
      "post": {
        "operationId": "purchaseVas",
        "summary": "Purchase VAS",
        "tags": [
          "VAS"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "productID": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "string"
                  },
                  "reference": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "productID": "dde67d01-73ff-4f20-acb2-212e1b22ffcd",
                "amount": "500",
                "reference": "[10,20,30,36,1,4,5,8]"
              }
            }
          }
        },
        "responses": {
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/TrafficFine/ViewByIDnumber": {
      "post": {
        "operationId": "viewTrafficFineByID",
        "summary": "Query by ID Number",
        "description": "Returns all recorded traffic fines for a given South African national ID number or Foreign ID number.",
        "tags": [
          "Traffic Fines"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "idNumber"
                ],
                "properties": {
                  "idNumber": {
                    "type": "string",
                    "description": "South African national ID number or Foreign ID number.",
                    "example": "9710226013089"
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "local",
                      "foreign"
                    ],
                    "description": "Optional parameter to determine whether the ID you are searching with is local or foreing. Please note that foreign ID is not the same as a passport number. If left empty it will default to `local`",
                    "example": "foreign"
                  }
                }
              },
              "example": {
                "idNumber": "9710226013089",
                "type": "local"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Traffic fine query by ID response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "`true` = success, `false` = error."
                    },
                    "idNumber": {
                      "nullable": true,
                      "type": "string",
                      "description": "The ID number used in the query. `null` if the type was foreign"
                    },
                    "foreignId": {
                      "nullable": true,
                      "type": "string",
                      "description": "The foreign ID number that was used in the query. `null` if the type was local or type was empty"
                    },
                    "result": {
                      "nullable": true,
                      "type": "object",
                      "description": "Query result. `null` when `success` is `false`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/QueryByIdNumberResult"
                        }
                      ]
                    },
                    "error": {
                      "nullable": true,
                      "type": "object",
                      "description": "Error details. `null` when `success` is `true`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": true,
                  "idNumber": "9710226013089",
                  "result": {
                    "infringements": [
                      {
                        "vehicleLicenseNumber": "JR47HJGP",
                        "charge": {
                          "classification": "Failed to license a vehicle with the ...",
                          "demeritPoints": 1,
                          "description": "Failed to license a vehicle in accordance with Chapter III Part I of Road Traffic Regulations 2000 with the appropriate registering authority"
                        },
                        "date": "2023-01-22",
                        "time": "10:38:00",
                        "noticeNumber": "0100110373510309",
                        "location": {
                          "cityTown": "JOHANNESBURG",
                          "issAuthority": {
                            "code": "4065",
                            "description": "GP Dept of Community Safety."
                          },
                          "streetName": "N1",
                          "suburb": "JOHANNESBURG"
                        },
                        "netFineAmnt": 560,
                        "vendorFeeAmnt": 14,
                        "grossAmnt": 574,
                        "isPaid": false
                      }
                    ],
                    "hasFinesToPay": true,
                    "netFinesAmnt": 560,
                    "vendorFeeAmnt": 14,
                    "grossAmnt": 574,
                    "idNumber": "9710226013089"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "idNumber": {
                      "type": "string"
                    },
                    "error": {
                      "type": "object",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": false,
                  "idNumber": "9710226013089",
                  "error": {
                    "code": 999,
                    "message": "999 - Internal server error",
                    "validationMessages": [
                      "999 - Internal server error"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/TrafficFine/ViewByBusinessRegistration": {
      "post": {
        "operationId": "viewTrafficFineByBRN",
        "summary": "Query by Business Registration Number",
        "description": "Returns all recorded traffic fines for a given business registration number (BRN).",
        "tags": [
          "Traffic Fines"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "brn"
                ],
                "properties": {
                  "idNumber": {
                    "type": "string",
                    "description": "Business registration number.",
                    "example": "0402555070058"
                  }
                }
              },
              "example": {
                "brn": "F141235290013"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Traffic fine query by BRN response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "brn": {
                      "type": "string"
                    },
                    "result": {
                      "nullable": true,
                      "type": "object",
                      "description": "Query result. `null` when `success` is `false`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/QueryByIdNumberResult"
                        }
                      ]
                    },
                    "error": {
                      "nullable": true,
                      "type": "object",
                      "description": "Error details. `null` when `success` is `true`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "brn": {
                      "type": "string"
                    },
                    "error": {
                      "type": "object",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": false,
                  "brn": "2019/123456/07",
                  "error": {
                    "code": 999,
                    "message": "999 - Internal server error",
                    "validationMessages": [
                      "999 - Internal server error"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/TrafficFine/ViewByNoticeNumber": {
      "post": {
        "operationId": "viewTrafficFineByNoticeNumber",
        "summary": "Query by Notice Number",
        "description": "Returns the details of a specific traffic fine by its AARTO notice number.",
        "tags": [
          "Traffic Fines"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "noticeNumber"
                ],
                "properties": {
                  "noticeNumber": {
                    "type": "string",
                    "description": "AARTO notice number of the traffic fine.",
                    "example": "0100110373510309"
                  }
                }
              },
              "example": {
                "noticeNumber": "0100110373510309"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Traffic fine query by notice number response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "noticeNumber": {
                      "type": "string",
                      "description": "The notice number used in the query."
                    },
                    "result": {
                      "nullable": true,
                      "type": "object",
                      "description": "Query result. `null` when `success` is `false`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/QueryByNoticeNumberResult"
                        }
                      ]
                    },
                    "error": {
                      "type": "object",
                      "nullable": true,
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": true,
                  "noticeNumber": "0100110373510309",
                  "result": {
                    "infringements": [
                      {
                        "vehicleLicenseNumber": "JR47HJGP",
                        "charge": {
                          "classification": "Operated a vehicle without displaying...",
                          "demeritPoints": 0,
                          "description": "Operated a vehicle without displaying the licence disc of said vehicle"
                        },
                        "date": "2023-01-22",
                        "time": "10:38:00",
                        "noticeNumber": "0100110373510309",
                        "location": {
                          "cityTown": "JOHANNESBURG",
                          "issAuthority": {
                            "code": "4065",
                            "description": "GP Dept of Community Safety."
                          },
                          "streetName": "N1",
                          "suburb": "JOHANNESBURG"
                        },
                        "netFineAmnt": 560,
                        "vendorFeeAmnt": 14,
                        "grossAmnt": 574,
                        "isPaid": false
                      }
                    ],
                    "hasFinesToPay": true,
                    "netFinesAmnt": 560,
                    "vendorFeeAmnt": 14,
                    "grossAmnt": 574,
                    "noticeNumber": "0100110373510309"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "noticeNumber": {
                      "type": "string"
                    },
                    "error": {
                      "type": "object",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": false,
                  "noticeNumber": "0100110373510309",
                  "error": {
                    "code": 999,
                    "message": "999 - Internal server error",
                    "validationMessages": [
                      "999 - Internal server error"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/TrafficFine/ValidateMarkTrafficFinesAsPaid": {
      "post": {
        "operationId": "validateMarkTrafficFinesAsPaid",
        "summary": "Validate Traffic Fine Payment",
        "description": "Validates that the proposed payment amount matches the expected gross amount for the selected fines. Call this before `MarkTrafficFineAsPaid` to confirm the correct amount.",
        "tags": [
          "Traffic Fines"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "paymentReference",
                  "paymentType",
                  "finesPaid"
                ],
                "properties": {
                  "paymentReference": {
                    "type": "string",
                    "description": "Merchant-side reference for this order.",
                    "example": "myreference"
                  },
                  "paymentType": {
                    "type": "string",
                    "enum": [
                      "CARD",
                      "EFT"
                    ],
                    "example": "CARD"
                  },
                  "finesPaid": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/MarkFineAsPaidCommand"
                    }
                  }
                }
              },
              "example": {
                "paymentReference": "myreference",
                "paymentType": "CARD",
                "finesPaid": [
                  {
                    "noticeNumber": "0100110373510309",
                    "amount": 574,
                    "currency": "ZAR"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment validation response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "integer",
                      "enum": [
                        0,
                        1
                      ]
                    },
                    "amntProposed": {
                      "type": "number",
                      "description": "The amount that was proposed for validation."
                    },
                    "reference": {
                      "type": "string",
                      "description": "The `paymentReference` echoed back."
                    },
                    "result": {
                      "type": "object",
                      "nullable": true,
                      "description": "Query result. `null` when `success` is `0`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ValidatePaymentResult"
                        }
                      ]
                    },
                    "error": {
                      "type": "object",
                      "nullable": true,
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessagePayment"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": 1,
                  "amntProposed": 574,
                  "reference": "myreference",
                  "result": {
                    "amntToPay": 574,
                    "difference": 0,
                    "isCorrectAmount": true
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "amntProposed": {
                      "type": "number"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "error": {
                      "type": "object",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessagePayment"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": 0,
                  "amntProposed": 0,
                  "reference": "myreference",
                  "error": {
                    "code": 999,
                    "message": "999 - Internal server error",
                    "validationMessages": [
                      "999 - Internal server error"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/TrafficFine/MarkTrafficFineAsPaid": {
      "post": {
        "operationId": "markTrafficFineAsPaid",
        "summary": "Mark Traffic Fines as Paid",
        "description": "Marks one or more traffic fines as paid on behalf of a customer. The merchant declares that they received the gross amount (net fine + vendor fee) from the customer and wishes to clear the fines with AARTO.\n\nCalling this endpoint will result in a Whoosh invoice for the gross transaction value of all fines marked paid, issued at the end of each billing cycle.\n\n> **Recommended:** Call `ValidateMarkTrafficFinesAsPaid` first to confirm the correct amount before calling this endpoint.",
        "tags": [
          "Traffic Fines"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "paymentReference",
                  "paymentType",
                  "finesPaid"
                ],
                "properties": {
                  "paymentReference": {
                    "type": "string",
                    "description": "Merchant-side reference to tie the result to an order.",
                    "example": "myreference"
                  },
                  "paymentType": {
                    "type": "string",
                    "enum": [
                      "CARD",
                      "EFT"
                    ],
                    "description": "How the transaction was paid.",
                    "example": "CARD"
                  },
                  "finesPaid": {
                    "type": "array",
                    "description": "List of fines paid to the merchant to be cleared with AARTO.",
                    "items": {
                      "$ref": "#/components/schemas/MarkFineAsPaidCommand"
                    }
                  }
                }
              },
              "example": {
                "paymentReference": "myreference",
                "paymentType": "CARD",
                "finesPaid": [
                  {
                    "noticeNumber": "0240060000000458",
                    "amount": 1614,
                    "currency": "ZAR"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Mark as paid response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "integer",
                      "enum": [
                        0,
                        1
                      ]
                    },
                    "reference": {
                      "type": "string",
                      "description": "The `paymentReference` echoed back."
                    },
                    "result": {
                      "nullable": true,
                      "type": "object",
                      "description": "Transaction result. `null` when `success` is `0`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/MarkTrafficFinesAsPaidResult"
                        }
                      ]
                    },
                    "error": {
                      "nullable": true,
                      "type": "object",
                      "description": "Error details. `null` when `success` is `1`.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": 1,
                  "reference": "myreference",
                  "result": {
                    "orderId": "b89a1717-5266-43c7-93cc-7e51c0fe01fb",
                    "grossAmntPaid": 1614,
                    "netFinesAmntPaid": 1600,
                    "vendorFeeAmntPaid": 14,
                    "merchantFeePaid": 7.5,
                    "finesPaid": [
                      {
                        "invoiceNumber": "47280000005V",
                        "netFinesAmntPaid": 1600,
                        "noticeNumber": "240990007600759",
                        "receiptNumber": "4728000000N1",
                        "vendorFeeAmntPaid": 14,
                        "grossAmntPaid": 1614
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "reference": {
                      "type": "string"
                    },
                    "error": {
                      "type": "object",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ErrorMessage"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": 0,
                  "reference": "myreference",
                  "error": {
                    "code": 999,
                    "message": "999 - Internal server error",
                    "validationMessages": [
                      "999 - Internal server error"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/putOrder": {
      "post": {
        "operationId": "putOrderV2",
        "summary": "Create Order",
        "description": "Creates an order on the Whoosh platform and returns a Whoosh Payment Gateway hosted checkout URL to redirect the customer to for secure card payment.\n\nWhoosh orchestrates order creation and reconciliation, and the Whoosh Payment Gateway manages card capture, authorization, and payment security.\n\n> **Staging environment:** Always use `merchantId: staging` when calling the test base URL. A production `merchantId` will be issued before go-live.",
        "tags": [
          "Whoosh Payments"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutOrderCommand"
              },
              "example": {
                "merchantId": "staging",
                "order": {
                  "id": "TRF-20240215-001",
                  "refferer": "TRF-20240215-001",
                  "date": "2024-02-15T10:30:00Z",
                  "dueDate": "2024-02-15T10:30:00Z",
                  "orderDescription": "Municipal Bill Payment",
                  "orderTotal": 2450,
                  "vatTotal": 0,
                  "currency": "ZAR",
                  "products": [
                    {
                      "id": "MOG-123456",
                      "productId": "municipal-bill",
                      "name": "Municipal Bill Payment",
                      "description": "Municipal bill payment for MOG-123456 of amount 1200",
                      "unitPrice": 1200,
                      "lineTotal": 1200,
                      "vatAmount": 0,
                      "currency": "ZAR",
                      "quantity": 1
                    },
                    {
                      "id": "MOG-654321",
                      "productId": "municipal-bill",
                      "name": "Municipal Bill Payment",
                      "description": "Municipal bill payment for MOG-654321 of amount 1250",
                      "unitPrice": 1250,
                      "lineTotal": 1250,
                      "vatAmount": 0,
                      "currency": "ZAR",
                      "quantity": 1
                    }
                  ]
                },
                "redirectSuccess": "https://placeholder.com",
                "redirectCancel": "https://placeholder.com",
                "platform": "MOG",
                "metadata": {
                  "orgId": "TEST-ORG-001",
                  "userId": "JABS78t8ABK"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order created successfully. Redirect the customer to `paymentPageUrl`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PutOrderResponse"
                },
                "example": {
                  "orderId": "whoosh-order-abc123",
                  "referredId": "TRF-20240215-001",
                  "paymentPageUrl": "https://payments.whoosh.example.com/pay/abc123",
                  "successCallback": "https://placeholder.com",
                  "failCallback": "https://placeholder.com"
                }
              }
            }
          },
          "400": {
            "description": "Bad request – order validation failed. Returns a `{ status, message, data }` wrapper. `data` is normally an empty object, since the underlying error's `message` is not enumerable and is not preserved on serialization.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "example": 400
                    },
                    "message": {
                      "type": "string",
                      "description": "One of: \"Account is not a merchant account\" (merchant exists but is not of merchant type); \"Incomplete order details! Amount and description are required and cannot be empty\" (missing/empty `order.orderTotal` or `order.orderDescription`); \"Order with ID {referrer} has already been registered on merchant {merchantId}\" (an order with the same `refferer`/`id` was already put for this merchant)."
                    },
                    "data": {
                      "type": "object",
                      "description": "Always an empty object in practice, since the underlying `Error`'s `message`/`stack` are non-enumerable and are dropped on JSON serialization.",
                      "example": {}
                    }
                  }
                },
                "examples": {
                  "notAMerchantAccount": {
                    "summary": "Account is not a merchant account",
                    "value": {
                      "status": 400,
                      "message": "Account is not a merchant account",
                      "data": {}
                    }
                  },
                  "incompleteOrderDetails": {
                    "summary": "Missing amount or description",
                    "value": {
                      "status": 400,
                      "message": "Incomplete order details! Amount and description are required and cannot be empty",
                      "data": {}
                    }
                  },
                  "duplicateOrder": {
                    "summary": "Order already registered for this merchant",
                    "value": {
                      "status": 400,
                      "message": "Order with ID TRF-20240215-001 has already been registered on merchant staging",
                      "data": {}
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error – for example when no merchant exists for the given `merchantId`. This case is not caught by the handler's own error handling, so the exact body is not guaranteed; treat any non-2xx, non-400/401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v2/whooshEndOfDayLedger": {
      "post": {
        "operationId": "whooshEndOfDayLedger",
        "summary": "End of Day Ledger",
        "description": "Returns all MPGS transactions for the previous South Africa business day, including reconciliation metadata and any verification errors.\n\nNo request body is required. The merchant is identified automatically from the `x-api-key` header.",
        "tags": [
          "Whoosh Payments"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved previous business day transactions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndOfDayLedgerResponse"
                },
                "example": {
                  "success": true,
                  "merchantId": "MERCH-001",
                  "timezone": "Africa/Johannesburg",
                  "businessDate": "2024-04-01",
                  "periodStart": "2024-04-01T00:00:00+02:00",
                  "periodEnd": "2024-04-01T23:59:59+02:00",
                  "generatedOn": "2024-04-02T06:05:00+02:00",
                  "transactionCount": 2,
                  "totalAmount": 300,
                  "verificationErrorCount": 0,
                  "transactions": [
                    {
                      "paymentReference": "ORD-20240401-001",
                      "transactionStatus": "SUCCESS",
                      "transactionAmount": 150,
                      "transactionCurrency": "ZAR",
                      "transactionTime": "2024-04-01T10:15:00+02:00"
                    },
                    {
                      "paymentReference": "ORD-20240401-002",
                      "transactionStatus": "SUCCESS",
                      "transactionAmount": 150,
                      "transactionCurrency": "ZAR",
                      "transactionTime": "2024-04-01T14:32:00+02:00"
                    }
                  ],
                  "verificationErrors": []
                }
              }
            }
          },
          "400": {
            "description": "Missing `merchantId` in request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndOfDayLedgerResponse"
                },
                "example": {
                  "success": false,
                  "merchantId": "",
                  "timezone": "Africa/Johannesburg",
                  "businessDate": "2024-04-01",
                  "periodStart": "2024-04-01T00:00:00+02:00",
                  "periodEnd": "2024-04-01T23:59:59+02:00",
                  "generatedOn": "2024-04-02T06:05:00+02:00",
                  "transactionCount": 0,
                  "totalAmount": 0,
                  "verificationErrorCount": 1,
                  "transactions": [],
                  "verificationErrors": [
                    {
                      "message": "Missing merchantId in request body."
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "403": {
            "description": "The `merchantId` resolved from the API key does not match, and is not a registered sub-merchant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndOfDayLedgerResponse"
                },
                "example": {
                  "success": false,
                  "merchantId": "MERCH-001",
                  "timezone": "Africa/Johannesburg",
                  "businessDate": "2024-04-01",
                  "periodStart": "2024-04-01T00:00:00+02:00",
                  "periodEnd": "2024-04-01T23:59:59+02:00",
                  "generatedOn": "2024-04-02T06:05:00+02:00",
                  "transactionCount": 0,
                  "totalAmount": 0,
                  "verificationErrorCount": 1,
                  "transactions": [],
                  "verificationErrors": [
                    {
                      "message": "Provided merchantId does not match the authenticated API key and is not a registered sub-merchant."
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No MPGS channel configured for this merchant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndOfDayLedgerResponse"
                },
                "example": {
                  "success": false,
                  "merchantId": "MERCH-001",
                  "timezone": "Africa/Johannesburg",
                  "businessDate": "2024-04-01",
                  "periodStart": "2024-04-01T00:00:00+02:00",
                  "periodEnd": "2024-04-01T23:59:59+02:00",
                  "generatedOn": "2024-04-02T06:05:00+02:00",
                  "transactionCount": 0,
                  "totalAmount": 0,
                  "verificationErrorCount": 1,
                  "transactions": [],
                  "verificationErrors": [
                    {
                      "message": "No MPGS channel configured for merchant MERCH-001"
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/v2/whooshCheckOrderPaymentStatus": {
      "post": {
        "operationId": "whooshCheckOrderPaymentStatus",
        "summary": "Order Payment Status",
        "description": "Verifies the payment status of a specific order by checking its associated MPGS payment sessions.",
        "tags": [
          "Whoosh Payments"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "orderId"
                ],
                "properties": {
                  "orderId": {
                    "type": "string",
                    "description": "The order ID to verify payment status for.",
                    "example": "ORD-20240401-001"
                  }
                }
              },
              "example": {
                "orderId": "ORD-20240401-001"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment status successfully retrieved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPaymentStatusResponse"
                },
                "example": {
                  "success": true,
                  "merchantId": "MERCH-001",
                  "orderId": "ORD-20240401-001",
                  "checkedOn": "2024-04-02T06:10:00+02:00",
                  "paymentStatus": "PAID",
                  "paymentReference": "ORD-20240401-001",
                  "transactionStatus": "SUCCESS",
                  "transactionAmount": 150,
                  "transactionCurrency": "ZAR",
                  "transactionTime": "2024-04-01T14:32:00+02:00",
                  "verificationErrors": []
                }
              }
            }
          },
          "400": {
            "description": "Missing or empty `merchantId` or `orderId`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPaymentStatusErrorResponse"
                },
                "example": {
                  "success": false,
                  "id": "",
                  "referrer": "",
                  "merchantId": "",
                  "orderId": "",
                  "checkedOn": "2024-04-02T06:10:00+02:00",
                  "paymentStatus": "VERIFICATION_ERROR",
                  "paymentReference": "",
                  "transactionStatus": "UNKNOWN",
                  "transactionAmount": 0,
                  "transactionCurrency": "ZAR",
                  "transactionTime": "2024-04-02T06:10:00+02:00",
                  "verificationErrors": [
                    {
                      "message": "Missing merchantId or orderId in request body."
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "401-4 - Unauthorized. No API key set"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "401-4 - Unauthorized. No API key set"
                }
              }
            }
          },
          "403": {
            "description": "The `merchantId` in the request does not match the authenticated API key and is not a registered sub-merchant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPaymentStatusErrorResponse"
                },
                "example": {
                  "success": false,
                  "id": "",
                  "referrer": "",
                  "merchantId": "MERCH-001",
                  "orderId": "ORD-20240401-001",
                  "checkedOn": "2024-04-02T06:10:00+02:00",
                  "paymentStatus": "VERIFICATION_ERROR",
                  "paymentReference": "",
                  "transactionStatus": "UNKNOWN",
                  "transactionAmount": 0,
                  "transactionCurrency": "ZAR",
                  "transactionTime": "2024-04-02T06:10:00+02:00",
                  "verificationErrors": [
                    {
                      "message": "Provided merchantId does not match the authenticated API key and is not a registered sub-merchant."
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No MPGS channel configured for the merchant, or no order found for the given `orderId`/merchant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPaymentStatusErrorResponse"
                },
                "example": {
                  "success": false,
                  "id": "",
                  "referrer": "",
                  "merchantId": "MERCH-001",
                  "orderId": "ORD-20240401-001",
                  "checkedOn": "2024-04-02T06:10:00+02:00",
                  "paymentStatus": "VERIFICATION_ERROR",
                  "paymentReference": "",
                  "transactionStatus": "UNKNOWN",
                  "transactionAmount": 0,
                  "transactionCurrency": "ZAR",
                  "transactionTime": "2024-04-02T06:10:00+02:00",
                  "verificationErrors": [
                    {
                      "message": "No order ORD-20240401-001 found for merchant MERCH-001."
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error. The exact message may vary; treat any non-2xx, non-401 response as a generic failure.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "999 - Internal server error"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "999 - Internal server error"
                }
              }
            }
          }
        }
      }
    }
  }
}