API Reference
createStash
createStash(config: StashConfig): {
payments: { create(input: PaymentCreateInput): Promise<Payment> }
webhooks: { parse(input: WebhookParseInput): ParsedWebhook }
}
Creates a configured Stash client with capability surfaces for payments and webhooks.
Test mode
testMode: true routes requests to provider sandbox endpoints. Set it to false for live production traffic.
Structured logging
Stash can emit canonical, structured log events for each payment action. Provide a logger when you create the client:
const stash = createStash({
provider: "payfast",
credentials: {
merchantId: process.env.PAYFAST_MERCHANT_ID,
merchantKey: process.env.PAYFAST_MERCHANT_KEY,
},
testMode: true,
logger: {
log: (event) => {
// Send to your logging pipeline
console.log(event);
},
},
});
Each event includes a correlation_id, event name (for example, payments.create.request), and safe metadata such as
amount, currency, and reference. Stash never logs credentials or raw webhook payloads.
payments.create
payments.create(input: PaymentCreateInput): Promise<Payment>
Creates a payment using the configured provider and returns a canonical Payment.
providerOptions mapping
Payfast
paymentMethod→payment_methodemailConfirmation→email_confirmationconfirmationAddress→confirmation_addressmPaymentId→m_payment_iditemName→item_nameitemDescription→item_description
Ozow
selectedBankId→SelectedBankIdcustomerIdentityNumber→CustomerIdentityNumberallowVariableAmount→AllowVariableAmountvariableAmountMin→VariableAmountMinvariableAmountMax→VariableAmountMax
Paystack
channels→channels
Amounts
Amounts are treated as major units by default (for example, "25.00"). For Paystack,
Stash converts major units to minor units automatically. To send minor units explicitly,
set amountUnit: "minor" in payments.create.
Currency values are normalized to uppercase and default to ZAR when omitted. Ozow and Payfast
only accept ZAR.
Required fields
Paystack requires customer.email for payments.create.
webhooks.parse
webhooks.parse(input: WebhookParseInput): ParsedWebhook
Verifies and normalizes provider webhook payloads. Throws StashError with code: "invalid_signature" on verification failure.
payments.verify
payments.verify(input: PaymentVerifyInput): Promise<VerificationResult>
Verifies payment status by reference. Supported providers:
- Ozow ✅
- Paystack ✅
- Payfast ❌ (
unsupported_capability)
subscriptions.plans.create
subscriptions.plans.create(input: SubscriptionPlanCreateInput): Promise<SubscriptionPlan>
Creates a subscription plan for the configured provider.
Supported providers:
- Paystack ✅
SubscriptionPlanCreateInput
type SubscriptionPlanCreateInput = {
name: string
interval: "hourly" | "daily" | "weekly" | "monthly" | "quarterly" | "biannually" | "annually"
amount: string | number
amountUnit?: "major" | "minor"
currency?: string
invoiceLimit?: number
provider?: "paystack"
}
subscriptions.create
subscriptions.create(input: SubscriptionCreateInput): Promise<Subscription>
Creates a subscription for an existing customer and plan.
Supported providers:
- Paystack ✅
SubscriptionCreateInput
type SubscriptionCreateInput = {
customer: string
plan: string
authorization?: string
startDate?: string
provider?: "paystack"
}
providerCapabilities
providerCapabilities: Record<PaymentProvider, ProviderCapabilities>
Static metadata describing provider capabilities for validation and docs.
| Provider | Currencies | Required fields | payments.verify |
|---|---|---|---|
| Ozow | ZAR | - | ✅ |
| Payfast | ZAR | - | ❌ |
| Paystack | Any | customer.email | ✅ |
VerificationResult
type VerificationResult = {
provider: "ozow" | "payfast" | "paystack"
status: "pending" | "paid" | "failed" | "unknown"
providerRef?: string
correlationId?: string
raw?: unknown
}
Payment (canonical)
type Payment = {
id: string
status: "pending" | "paid" | "failed"
amount: number
currency: string
redirectUrl?: string
provider: "ozow" | "payfast" | "paystack"
providerRef?: string
correlationId?: string
raw?: unknown
}
WebhookEvent (canonical)
type WebhookEvent = {
type: "payment.completed" | "payment.failed" | "payment.cancelled"
data: {
id?: string
providerRef?: string
reference: string
amount?: number
currency?: string
provider: "ozow" | "payfast" | "paystack"
raw: unknown
}
}
SubscriptionWebhookEvent (canonical)
type SubscriptionWebhookEvent = {
type:
| "subscription.created"
| "subscription.disabled"
| "subscription.not_renewing"
| "invoice.created"
| "invoice.updated"
| "invoice.payment_failed"
data: {
provider: "paystack"
subscriptionCode?: string
customerCode?: string
planCode?: string
invoiceCode?: string
status?: string
amount?: number
currency?: string
raw: unknown
}
}
ParsedWebhook
type ParsedWebhook = {
event: WebhookEvent | SubscriptionWebhookEvent
provider: "ozow" | "payfast" | "paystack"
correlationId?: string
raw: Record<string, unknown>
}
makePayment (deprecated)
makePayment(input: PaymentRequest): Promise<PaymentResponse>
Creates a payment request for Ozow or Payfast using a unified payload.
Deprecated: use createStash().payments.create.
verifyWebhookSignature (deprecated)
verifyWebhookSignature(input: WebhookVerifyInput): WebhookVerifyResult
Verifies the provider webhook signature for Ozow or Payfast.
Deprecated: use createStash().webhooks.parse.
Webhook utilities
buildFormEncoded(payload: Record<string, string | number | boolean | null | undefined>): string
parseFormBody(rawBody: string | Buffer): [string, string][]
parseFormEncoded(raw: string): [string, string][]
pairsToRecord(pairs: [string, string][]): Record<string, string>