Guide
Guide React pour déclencher le flux de transaction YKNPG depuis une page (démo de développement).
Guide React pour déclencher le flux de transaction YKNPG depuis une page (démo de développement).
Note sécurité
- Le jeton bearer doit rester côté serveur. En production, créez un petit endpoint backend qui ajoute l'en-tête Authorization. L'exemple ci-dessous utilise le jeton depuis
.env.localuniquement pour les tests locaux.
Pré-requis
- Node.js 18+, npm.
- Créer l'app
npm create vite@latest demo-react -- --template reactcd demo-react && npm installnpm install axios
- Ajouter l'environnement
- Fichier :
.env.local
VITE_YKNPG_API_TOKEN=remplacez-par-votre-jeton
VITE_YKNPG_BASE_URL=https://yknpg.ngoul.com/api/v1
- Ajouter un client API helper
- Fichier :
src/api.js
import axios from "axios";
const client = axios.create({
baseURL: import.meta.env.VITE_YKNPG_BASE_URL || "https://yknpg.ngoul.com/api/v1",
headers: { Authorization: `Bearer ${import.meta.env.VITE_YKNPG_API_TOKEN}` },
timeout: 10000,
});
export async function startTransaction(amount, phone) {
const createPayload = {
amount,
provider: "ORANGE_MONEY",
user_infos: { number: phone },
callback_url: "http://example.com",
callback_method: "POST",
your_message: "pay this",
your_order_ref: "demo-1",
provider_fees_on_customer: true,
};
const { data: created } = await client.post("/transactions/", createPayload);
const { data: paid } = await client.post(`/transactions/${created.uuid}/pay/`);
let status = paid.status;
while (status === "new" || status === "paying") {
await new Promise((r) => setTimeout(r, 5000));
const { data } = await client.get(`/transactions/${created.uuid}/`);
status = data.status;
}
return { created, paid, finalStatus: status };
}
- Créer l'UI
- Fichier :
src/App.jsx
import { useState } from "react";
import { startTransaction } from "./api";
function App() {
const [phone, setPhone] = useState("");
const [amount, setAmount] = useState(1000);
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const submit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
const data = await startTransaction(Number(amount), phone);
setResult(data);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<main style={{ maxWidth: 480, margin: "2rem auto", fontFamily: "sans-serif" }}>
<h1>Start payment</h1>
<form onSubmit={submit}>
<label>Phone</label>
<input value={phone} onChange={(e) => setPhone(e.target.value)} required />
<label>Amount</label>
<input
type="number"
value={amount}
min="1"
onChange={(e) => setAmount(e.target.value)}
required
/>
<button type="submit" disabled={loading}>
{loading ? "Processing..." : "Pay"}
</button>
</form>
{error && <p style={{ color: "red" }}>{String(error)}</p>}
{result && (
<section>
<p>Gateway instructions: {result.created.instructions}</p>
<p>Post-pay instructions: {result.paid.instructions}</p>
<p>Final status: {result.finalStatus}</p>
</section>
)}
</main>
);
}
export default App;
- Exécuter
npm run dev- Ouvrez l'URL locale affichée et testez.
Remarques
- Déplacez le jeton vers une API backend avant de publier auprès des utilisateurs.