Quickstart
Take your first Moosyl payment in the sandbox: create keys, create a payment request on your server, let the customer pay in their bank app, and handle the webhook.
This guide takes you from a new account to a completed sandbox payment. You need a Moosyl account and a server that can make HTTPS requests.
1. Create sandbox keys
In the dashboard, make sure the Sandbox environment is selected, open API Keys and click Create API Key. Create two keys:
- a secret key for your server
- a publishable key for your app or website
Store them as environment variables. Never put the secret key in frontend or mobile code.
MOOSYL_SECRET_KEY=YOUR_SECRET_KEY
MOOSYL_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY2. Create payment request (backend)
A payment request says how much to charge and links the payment to your own order through transactionId. Create it from your server with the secret key. The key goes in the Authorization header as is, without Bearer.
const response = await fetch("https://api.moosyl.com/payment-request", {
method: "POST",
headers: {
Authorization: process.env.MOOSYL_SECRET_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
transactionId: "order_123", // your own ID, unique per environment
amount: 1000, // in MRU
}),
});
const { data } = await response.json();
// data.id → the payment request ID
// data.transactionId → "order_123"3. Let the customer pay
Pick one way to collect the payment. The customer chooses their bank app and confirms in it.
Create a checkout session on your server and redirect the customer to checkoutUrl. Install the TypeScript SDK with npm install moosyl-sdk.
import { Moosyl } from "moosyl-sdk";
const moosyl = new Moosyl(process.env.MOOSYL_SECRET_KEY!);
const session = await moosyl.createCheckoutSession({
paymentRequestId: data.id, // from step 2
successUrl: "https://example.com/orders/123/paid",
cancelUrl: "https://example.com/orders/123",
expiresInMinutes: 30,
});
// Redirect the customer to session.checkoutUrlYou can also skip step 2 and create the session straight from a transactionId, amount and phoneNumber. See Checkout Session.
Add moosyl_flutter to your app and open the payment screen with the publishable key and the transactionId from step 2.
import 'package:moosyl_flutter/moosyl.dart';
final paid = await MoosylFlutter.show(
context,
publishableApiKey: 'YOUR_PUBLISHABLE_KEY',
transactionId: 'order_123',
);
if (paid == true) {
// Show your confirmation screen. Fulfil the order from the webhook.
}Add moosyl-react-native to your app and render MoosylView with the publishable key and the transactionId from step 2.
import { MoosylView } from "moosyl-react-native";
<MoosylView
apiKey="YOUR_PUBLISHABLE_KEY"
transactionId="order_123"
onPaySuccess={() => {
// Show your confirmation screen. Fulfil the order from the webhook.
}}
/>;4. Handle the webhook
Webhooks tell your server when a payment is created or its status changes. In the dashboard, open Webhooks, click Create Webhook, enter your endpoint URL and a secret of your choice, and select the payment-created and payment-updated events.
Verify the signature on the raw request body with that webhook secret, then fulfil the order when the payment status is completed:
import express from "express";
import { Moosyl, WebhookSignatureError } from "moosyl-sdk";
const app = express();
const moosyl = new Moosyl(process.env.MOOSYL_SECRET_KEY!);
app.post("/webhooks/moosyl", express.raw({ type: "application/json" }), async (req, res) => {
let event;
try {
event = moosyl.constructWebhookEvent(
req.body, // raw body, not parsed JSON
req.headers["x-webhook-signature"] as string,
process.env.MOOSYL_WEBHOOK_SECRET!
);
} catch (error) {
if (error instanceof WebhookSignatureError) {
return res.status(401).send("Invalid signature");
}
throw error;
}
if (
(event.event === "payment-created" || event.event === "payment-updated") &&
event.data.status === "completed"
) {
await markOrderPaid(event.data.transactionId); // "order_123"
}
res.json({ received: true });
});Depending on the bank app, a payment can arrive already completed in payment-created, or move from pending to completed in a later payment-updated. Checking data.status handles both. Webhooks guide
To receive webhooks on your machine, expose your local server with a tunnel such as ngrok http 3000 and use the public URL as the webhook endpoint.
5. Test in the sandbox
Pay with phone number 22222222, 33333333 or 44444444 to get a completed payment. Any other number fails. Some bank apps need a simulated transfer instead; Testing explains which.
Check the result under Payments in the dashboard and confirm your webhook endpoint received the event.
6. Go live
- Once your business is approved, a Production environment is available in the dashboard. Switch to it.
- Create a production secret key and publishable key, and replace the sandbox keys in your environment variables.
- Create the webhook again in Production. Webhooks and keys belong to one environment.
- Take a small real payment to confirm everything end to end.
Next steps
- Checkout Session: hosted payment page options
- Webhooks: events, payloads and retries
- Subscriptions: recurring billing
- API reference: every endpoint
Introduction
Moosyl is one API for Bankily, Sedad, Masrvi, BimBank, BCI Pay and Amanty, with Click coming soon. Create a payment, let your customer pay in their bank app, and get notified the moment it's paid.
API Keys
Create and manage your Moosyl API keys: when to use a secret or a publishable key, Sandbox vs Production, and how to replace a key safely.