JavaScript / TypeScript Examples
Complete examples for integrating EasySlip API with JavaScript and TypeScript.
Installation
bash
# No external dependencies required for fetch API (Node.js 18+)
# For file uploads in Node.js:
npm install form-dataAPI Client Class
TypeScript
typescript
// easyslip.ts
interface SlipData {
payload: string;
transRef: string;
date: string;
amount: {
amount: number;
local?: { amount: number; currency: string };
};
sender: {
bank: { id: string; name: string; short: string };
account: { name: { th?: string; en?: string } };
};
receiver: {
bank: { id: string; name: string; short: string };
account: { name: { th?: string; en?: string } };
};
}
interface V2Response<T> {
success: boolean;
data?: T;
error?: { code: string; message: string };
message?: string;
}
interface V1Response<T> {
status: number;
data?: T;
message?: string;
}
class EasySlipClient {
private apiKey: string;
private baseUrl: string;
constructor(apiKey: string, version: 'v1' | 'v2' = 'v2') {
this.apiKey = apiKey;
this.baseUrl = `https://developer.easyslip.com/api/${version}`;
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
...options.headers,
},
});
return response.json();
}
// V2 Methods
async verifyByPayload(
payload: string,
options: {
remark?: string;
matchAccount?: boolean;
matchAmount?: number;
checkDuplicate?: boolean;
} = {}
): Promise<V2Response<{ rawSlip: SlipData; isDuplicate: boolean }>> {
return this.request('/verify/bank', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payload, ...options }),
});
}
async verifyByUrl(
url: string,
options: {
remark?: string;
matchAccount?: boolean;
matchAmount?: number;
checkDuplicate?: boolean;
} = {}
): Promise<V2Response<{ rawSlip: SlipData; isDuplicate: boolean }>> {
return this.request('/verify/bank', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url, ...options }),
});
}
async verifyByBase64(
base64: string,
options: {
remark?: string;
matchAccount?: boolean;
matchAmount?: number;
checkDuplicate?: boolean;
} = {}
): Promise<V2Response<{ rawSlip: SlipData; isDuplicate: boolean }>> {
return this.request('/verify/bank', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ base64, ...options }),
});
}
async getInfo(): Promise<V2Response<{
application: { name: string; quota: { used: number; max: number } };
}>> {
return this.request('/info');
}
}
export { EasySlipClient, SlipData, V2Response };Usage
typescript
import { EasySlipClient } from './easyslip';
const client = new EasySlipClient(process.env.EASYSLIP_API_KEY!);
// Verify by payload
const result = await client.verifyByPayload('QR_PAYLOAD', {
checkDuplicate: true,
});
if (result.success && result.data) {
console.log('Amount:', result.data.rawSlip.amount.amount);
console.log('Duplicate:', result.data.isDuplicate);
} else {
console.error('Error:', result.error?.message);
}Express.js Integration
typescript
// routes/verify.ts
import express from 'express';
import multer from 'multer';
const router = express.Router();
const upload = multer({ limits: { fileSize: 4 * 1024 * 1024 } });
const EASYSLIP_API_KEY = process.env.EASYSLIP_API_KEY;
router.post('/verify', upload.single('slip'), async (req, res) => {
try {
let body: Record<string, any> = {};
let headers: Record<string, string> = {
'Authorization': `Bearer ${EASYSLIP_API_KEY}`,
};
if (req.file) {
// Image upload
const formData = new FormData();
formData.append('image', new Blob([req.file.buffer]), req.file.originalname);
formData.append('checkDuplicate', 'true');
body = formData;
} else if (req.body.payload) {
// Payload
headers['Content-Type'] = 'application/json';
body = JSON.stringify({
payload: req.body.payload,
checkDuplicate: true,
});
} else if (req.body.url) {
// URL
headers['Content-Type'] = 'application/json';
body = JSON.stringify({
url: req.body.url,
checkDuplicate: true,
});
}
const response = await fetch(
'https://api.easyslip.com/v2/verify/bank',
{
method: 'POST',
headers,
body,
}
);
const result = await response.json();
res.json(result);
} catch (error) {
res.status(500).json({ error: 'Verification failed' });
}
});
export default router;Next.js API Route
typescript
// app/api/verify/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const body = await request.json();
const response = await fetch(
'https://api.easyslip.com/v2/verify/bank',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.EASYSLIP_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
payload: body.payload,
checkDuplicate: true,
}),
}
);
const result = await response.json();
if (!result.success) {
return NextResponse.json(
{ error: result.error.message },
{ status: 400 }
);
}
return NextResponse.json({
transRef: result.data.rawSlip.transRef,
amount: result.data.rawSlip.amount.amount,
sender: result.data.rawSlip.sender.account.name.th,
receiver: result.data.rawSlip.receiver.account.name.th,
isDuplicate: result.data.isDuplicate,
});
}React Component
tsx
// components/SlipVerifier.tsx
import { useState } from 'react';
interface SlipResult {
transRef: string;
amount: number;
sender: string;
receiver: string;
isDuplicate: boolean;
}
export function SlipVerifier() {
const [file, setFile] = useState<File | null>(null);
const [result, setResult] = useState<SlipResult | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!file) return;
setLoading(true);
setError(null);
try {
const formData = new FormData();
formData.append('slip', file);
const response = await fetch('/api/verify', {
method: 'POST',
body: formData,
});
const data = await response.json();
if (data.error) {
setError(data.error);
} else {
setResult(data);
}
} catch (err) {
setError('Verification failed');
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="file"
accept="image/*"
onChange={(e) => setFile(e.target.files?.[0] || null)}
/>
<button type="submit" disabled={!file || loading}>
{loading ? 'Verifying...' : 'Verify Slip'}
</button>
{error && <p className="error">{error}</p>}
{result && (
<div className="result">
<p>Transaction: {result.transRef}</p>
<p>Amount: {result.amount} THB</p>
<p>From: {result.sender}</p>
<p>To: {result.receiver}</p>
{result.isDuplicate && (
<p className="warning">This slip has been verified before</p>
)}
</div>
)}
</form>
);
}Error Handling
typescript
async function verifyWithRetry(
payload: string,
maxRetries = 3
): Promise<SlipData> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(
'https://api.easyslip.com/v2/verify/bank',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.EASYSLIP_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ payload, checkDuplicate: true }),
}
);
const result = await response.json();
if (result.success) {
return result.data.rawSlip;
}
// Handle specific errors
switch (result.error.code) {
case 'QUOTA_EXCEEDED':
throw new Error('API quota exceeded');
case 'SLIP_NOT_FOUND':
throw new Error('Invalid slip');
case 'API_SERVER_ERROR':
if (attempt < maxRetries) {
await new Promise((r) => setTimeout(r, 1000 * attempt));
continue;
}
throw new Error('Server temporarily unavailable');
default:
throw new Error(result.error.message);
}
} catch (error) {
if (attempt === maxRetries) throw error;
}
}
throw new Error('Max retries exceeded');
}Webhook Handler
typescript
// Verify slip from webhook notification
app.post('/webhook/payment', async (req, res) => {
const { slipUrl, orderId, expectedAmount } = req.body;
try {
const response = await fetch(
'https://api.easyslip.com/v2/verify/bank',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.EASYSLIP_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: slipUrl,
remark: orderId,
matchAmount: expectedAmount,
checkDuplicate: true,
}),
}
);
const result = await response.json();
if (!result.success) {
return res.status(400).json({ error: result.error.message });
}
const { isDuplicate, isAmountMatched, rawSlip } = result.data;
if (isDuplicate) {
return res.status(400).json({ error: 'Duplicate slip' });
}
if (!isAmountMatched) {
return res.status(400).json({
error: 'Amount mismatch',
expected: expectedAmount,
actual: rawSlip.amount.amount,
});
}
// Process payment...
await updateOrderStatus(orderId, 'paid');
res.json({ success: true, transRef: rawSlip.transRef });
} catch (error) {
res.status(500).json({ error: 'Verification failed' });
}
});