Skip to content

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-data

API 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' });
  }
});

Bank Slip Verification API for Thai Banking