TypeScript Package
@ocuula/validators
Zod schemas and inferred TypeScript types shared across the Orchestrator stack — backend, frontend, and consumer apps. The single source of truth for every API boundary.
Installation
pnpm add @ocuula/validators
Quick Start
Import any schema directly from the package. Each schema doubles as a runtime validator and a TypeScript type via z.infer.
import { TriggerSplitSchema, FeePreviewRequestSchema } from "@ocuula/validators"
const result = TriggerSplitSchema.safeParse({
routingRuleId: "rule_abc",
amountInPesewas: 10000,
})
if (!result.success) {
console.error(result.error.issues)
}Split Rule Schemas
Every split type has a dedicated Zod schema with built-in validation — percentage sums must equal 100, flat split totals cannot exceed the sentinel, and tier thresholds must be strictly ascending.
| Schema | ruleType | Description |
|---|---|---|
| PercentageRuleSchema | PERCENTAGE_SPLIT | Percentage-based splits that must sum to 100% |
| FlatRuleSchema | FIXED_FLAT_SPLIT | Fixed pesewa amounts with remainder routing |
| WaterfallRuleSchema | MILESTONE_WATERFALL | Milestone-gated percentage waterfall |
| DirectDebitMandateSchema | DIRECT_DEBIT | Recurring pull-based billing with cron schedule |
| TieredSplitSchema | TIERED_SPLIT | Volume-sensitive tiered percentage allocations |
The RuleConfigurationSchema discriminated union unions all five rule types by ruleType. Use CreateRuleSchema when creating rules programmatically — it validates the full payload including merchantId and name.
Fee & Pricing Schemas
Fee calculation is driven from the validator package so frontend and backend always agree on rates.
| Export | Description |
|---|---|
| FeeModeSchema | FROM_RECEIVED or GROSS_UP_TO_NET |
| FeePreviewRequestSchema | Validate feee preview request payload (amount, mode, volume, split count) |
| FeeBreakdownSchema | Moolre collection, network, orchestration, transfer fees + remainder |
| lookupRateBpsByVolume | Pure function — returns the basis-point rate for a given 30-day volume |
Provisioning & Sandbox
Merchant provisioning and sandbox top-ups are validated through shared schemas.
| Schema | Purpose |
|---|---|
| ProvisionMerchantSchema | Validate merchant signup — name, provision mode, Moolre credentials, plan, environment |
| SandboxTopupSchema | Validate sandbox wallet top-up amounts (max GHS 100,000 per operation) |
Moolre API Response Schemas
These schemas are used internally at the network boundary to parse Moolre API responses instead of trusting raw any from fetch(). They are also available for consumer apps that need to handle Moolre responses directly.
| Schema | Description |
|---|---|
| MoolreEnvelopeSchema | Standard Moolre response envelope (status, code, message, data) |
| MoolreTransferResponseSchema | Validate payout transfer responses (txstatus, receiver, transactionid, fees) |
| MoolrePaymentResponseSchema | Validate STK push / USSD collection responses |
| MoolreTransactionStatusSchema | Validate transfer/payment status check responses |
| MoolreWebhookPayloadSchema | Validate inbound Moolre payment webhook payloads including custom_metadata |
Utility: treeifyError
Zod's default error format is a flat list of issues that can be hard to read for nested payloads. treeifyError re-formats errors into a nested tree structure keyed by field path — useful for showing inline validation errors in forms or API responses.
import { treeifyError } from "@ocuula/validators"
const result = TriggerSplitSchema.safeParse({ amountInPesewas: -100 })
if (!result.success) {
console.log(treeifyError(result.error))
// {
// amountInPesewas: ["Number must be positive"],
// routingRuleId: ["Required"]
// }
}
