@maxnate/provider-snippe
v0.1.1
Published
Snippe.sh payment provider for @maxnate/payments-core. Supports Mobile Money (M-Pesa, Airtel, Mixx, Halotel), Card, and Dynamic QR payments in Tanzania.
Maintainers
Readme
@maxnate/provider-snippe
Snippe.sh payment provider for @maxnate/payments-core.
Supports receiving payments only (collection). Payouts/disbursements are not part of this package.
Payment Types
| Type | paymentType | Flow |
|---|---|---|
| Mobile Money | "mobile" | USSD push to customer phone |
| Card | "card" | Redirect to payment_url |
| Dynamic QR | "dynamic-qr" | Scan QR code with mobile money app |
Supported Features
- Mobile Money (Airtel Money, M-Pesa, Mixx by Yas, Halotel)
- Card payments (Visa, Mastercard, local debit cards)
- Dynamic QR payments
- Webhook signature verification with replay attack protection
- Idempotency key support (30-char max per Snippe API)
Usage
import { createPaymentProviderRegistry } from '@maxnate/payments-core'
import { SnippeProvider } from '@maxnate/provider-snippe'
const registry = createPaymentProviderRegistry()
// Configure the provider
registry.setConfig({
id: 'snippe',
name: 'Snippe',
type: 'mobile_money',
enabled: true,
testMode: false,
credentials: {
apiKey: process.env.SNIPPE_API_KEY!
},
webhookSecret: process.env.SNIPPE_WEBHOOK_SECRET,
currencies: ['TZS'],
countries: ['TZ']
})
// Create a mobile money payment
const result = await registry.createPaymentIntent('snippe', {
orderId: 'ORD-001',
amount: 5000,
currency: 'TZS',
paymentType: 'mobile',
customerEmail: '[email protected]',
customerPhone: '255712345678',
metadata: {
webhook_url: 'https://mysite.com/webhooks/snippe'
}
})Webhook Endpoint
import { handlePaymentWebhook } from '@maxnate/payments-core'
// In your webhook handler (Express, Nuxt, etc.):
app.post('/webhooks/snippe', async (req, res) => {
// Pass the RAW body as string, not parsed JSON
const rawBody = JSON.stringify(req.body)
const signature = req.headers['x-webhook-signature']
const headers = {
'x-webhook-timestamp': req.headers['x-webhook-timestamp'],
'x-webhook-event': req.headers['x-webhook-event']
}
const result = await handlePaymentWebhook(
rawBody,
signature,
'snippe',
registry,
{
findPaymentIntent: (id) => db.payments.findById(id),
updatePaymentIntent: (id, data) => db.payments.update(id, data),
hasProcessedWebhookEvent: (providerId, eventId) => db.webhookLogs.exists(providerId, eventId),
recordProcessedWebhookEvent: (providerId, eventId) => db.webhookLogs.create(providerId, eventId)
},
headers
)
if (result.success) {
res.status(200).send('OK')
} else {
res.status(400).send(result.error)
}
})