Skip to content

SDKs ​

The EasySlip SDKs let your server verify Thai bank transfer slips and TrueMoney Wallet receipts with the bank, and confirm in the same request that a slip paid your account the right amount and was not used before. They are available for JavaScript and TypeScript, Python, Go and PHP, and each one covers all of API v2 and API v1: slip verification, background jobs, receiving bank accounts, payment QR codes and webhook signature checks.

Each SDK adds your API key to every request, checks image files before it uploads them, returns a typed error for each kind of failure and retries failed requests without charging you twice for the same verification.

Choose your language ​

LanguageRequires
JavaScript and TypeScriptNode.js 22+
PythonPython 3.11 to 3.15
GoGo 1.26+
PHPPHP 8.2+

Bun 1.4, Deno 2.9 and Cloudflare Workers also run the JavaScript SDK. The PHP SDK needs Guzzle 7.16 or later, or Guzzle 8.3 or later. The source code of each SDK is listed in Source code and license.

Each guide walks through every feature with programs you can run. The README in each repository is a shorter summary of the same SDK.

Installation ​

sh
npm install @easyslip/sdk
sh
python -m pip install easyslip-sdk
sh
go get github.com/EASYSLIP-CO-LTD/sdk-go
sh
composer require easyslip/sdk

Set up your API key ​

Sign in to the EasySlip developer portal and copy the API key of your application. Authentication explains keys and branches. Then give the key to the SDK in one of these ways:

  1. Pass it when you create the client.
  2. Set the EASYSLIP_API_KEY environment variable.
  3. Save it in a file and set EASYSLIP_API_KEY_FILE to the path of that file, for example a Docker or Kubernetes secret.

The SDK uses the first of these that is set.

sh
export EASYSLIP_API_KEY="your-api-key"

# or keep the key in a file that only your app's user can read
export EASYSLIP_API_KEY_FILE="/run/secrets/easyslip-api-key"

Keep your API key on your server

Anyone who has your key can use your quota. Use the SDK only in code that runs on your server. Never put the key in a web page or a mobile app, and never commit a key or a key file to a repository.

The SDK sends the key only in the Authorization header. If a response ever contains the key, the SDK removes it from error messages and from the headers it gives you, so you can log the SDK's errors.

The SDK also reads these variables:

VariableDefaultWhat it changes
EASYSLIP_V2_BASE_URLhttps://api.easyslip.com/v2The address of API v2.
EASYSLIP_V1_BASE_URLhttps://api.easyslip.com/v1The address of API v1.
EASYSLIP_WEBHOOK_SECRETNoneYour branch's webhook secret. Only the JavaScript SDK reads it for you. In the other languages, pass the secret to the webhook function.

Verify your first slip ​

This program checks the slip a customer sent for an order of 1,500 baht. It asks the API whether the slip paid one of your registered bank accounts, whether the amount is right and whether the slip was used before, and accepts the payment only when all three checks pass:

ts
import { EasySlip } from '@easyslip/sdk'

const easyslip = new EasySlip() // reads your key from EASYSLIP_API_KEY

const result = await easyslip.verify.bankByImage('./slip.jpg', {
    matchAccount: true, // did the slip pay one of your bank accounts?
    matchAmount: 1500, // is the amount right?
    checkDuplicate: true, // was this slip used before?
})
const paid = result.isDuplicate === false && result.isAmountMatched === true && result.matchedAccount != null
console.log(paid ? `Paid: ${result.rawSlip.transRef}` : 'Do not accept this slip.')
python
from easyslip import Client
from easyslip.models import MatchedAccount, VerifyOptions

with Client() as client:  # reads your key from EASYSLIP_API_KEY
    result = client.verify.bank_by_image(
        "slip.jpg",
        VerifyOptions(
            match_account=True,  # did the slip pay one of your bank accounts?
            match_amount=1500.0,  # is the amount right?
            check_duplicate=True,  # was this slip used before?
        ),
    )
    paid = (
        result.is_duplicate is False
        and result.is_amount_matched is True
        and isinstance(result.matched_account, MatchedAccount)
    )
    print(f"Paid: {result.raw_slip.trans_ref}" if paid else "Do not accept this slip.")
go
package main

import (
	"context"
	"fmt"
	"log"

	easyslip "github.com/EASYSLIP-CO-LTD/sdk-go"
)

func main() {
	client, err := easyslip.NewClient("") // reads your key from EASYSLIP_API_KEY
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	result, err := client.Verify.BankByImage(context.Background(), "slip.jpg", &easyslip.VerifyOptions{
		MatchAccount:   easyslip.Some(true),   // did the slip pay one of your bank accounts?
		MatchAmount:    easyslip.Some(1500.0), // is the amount right?
		CheckDuplicate: easyslip.Some(true),   // was this slip used before?
	})
	if err != nil {
		log.Fatal(err)
	}
	duplicate, checked := result.IsDuplicate.Value()
	amountMatched, _ := result.IsAmountMatched.Value()
	account, _ := result.MatchedAccount.Value()
	if checked && !duplicate && amountMatched && account != nil {
		fmt.Println("Paid:", result.RawSlip.TransRef)
	} else {
		fmt.Println("Do not accept this slip.")
	}
}
php
<?php

require __DIR__ . '/vendor/autoload.php';

use EasySlip\EasySlip;
use EasySlip\Input\FileInput;
use EasySlip\Input\VerifyOptions;

$easyslip = new EasySlip(); // reads your key from EASYSLIP_API_KEY

$result = $easyslip->verify->bankByImage(FileInput::fromPath(__DIR__ . '/slip.jpg'), new VerifyOptions(
    matchAccount: true, // did the slip pay one of your bank accounts?
    matchAmount: 1500, // is the amount right?
    checkDuplicate: true, // was this slip used before?
));
$paid = $result->isDuplicate === false && $result->isAmountMatched === true && $result->matchedAccount !== null;
echo $paid ? "Paid: {$result->rawSlip->transRef}\n" : "Do not accept this slip.\n";

matchAccount compares the receiver with the bank accounts you registered, so add your receiving accounts first, in the developer portal or with the SDK. Each verification uses one unit of your quota. The guide for your language shows the full version of this program, with a message for each failed check and the error for a slip the bank does not know. POST /verify/bank describes the request and the response.

Take the order total from your own database, never from the customer, and store transRef with a unique constraint when you mark the order paid, so that the same slip cannot pay two orders.

What each SDK covers ​

TaskAPIJavaScriptPythonGoPHP
Account info and quotaGET /infogetInfoget_infoGetInfogetInfo
Verify a bank slipPOST /verify/bankverify.bankBy*verify.bank_by_*Verify.BankBy*verify->bankBy*
Verify a TrueMoney Wallet receiptPOST /verify/truewalletverify.truewalletBy*verify.truewallet_by_*Verify.TruewalletBy*verify->truewalletBy*
Background and batch verificationAsync Verifyjobs.*jobs.*Jobs.*jobs->*
Bank codesGET /banksbanks.listbanks.listBanks.Listbanks->list
Receiving bank accountsBank AccountsbankAccounts.*bank_accounts.*BankAccounts.*bankAccounts->*
Payment QR codesPOST /qr/generatev1.generateQrv1.generate_qrV1.GenerateQRv1->generateQr
Legacy API v1API v1v1.*v1.*V1.*v1->*
Check a webhookWebhook CallbackconstructWebhookEventwebhooks.construct_eventConstructWebhookEventWebhook::constructEvent

By* names how you send the slip: Payload (the text in the slip's QR code), Image (a file or an upload), Base64 or URL. TrueMoney Wallet receipts have no payload method.

What every SDK does the same way ​

  • Timeouts and retries. Each attempt may take 30 seconds, and a failed request is retried at most 2 times. You can change both when you create the client. The SDK waits about half a second before the first retry and doubles the wait each time, up to 8 seconds.
  • No double charges. Verifications and background job submissions use quota, so the SDK retries them only when the API answers 429 or the connection failed before the request was sent. The same rule applies to creating, updating and unlinking a bank account. Reading data, linking an account and creating a QR code are safe to repeat, so they are also retried after a timeout, a network failure or a 500, 502, 503 or 504 answer. A 400, 401, 403, 404 or 409 answer is never retried.
  • Retry-After. When the API sends Retry-After, the SDK waits that long before it retries. If the wait would be longer than 60 seconds, the SDK returns the error at once.
  • File checks before upload. Images must be JPEG, PNG, GIF or WebP files of at most 4 MB. The SDK returns an InputError for an empty file, a file over 4 MB or a file that is not an image, without sending anything.
  • Request values. In a request, the receiving account type is NATURAL or JURISTIC, and the QR type is one of five values. TypeScript and Python type checkers reject other values through the AccountType and QrType types, PHP takes the AccountType and QrType enums, and Go has constants such as AccountTypeJuristic and QRTypePromptPay. Fields in responses accept any string, so a value the API adds later does not break your code.
  • Typed errors. Every SDK uses the same error names, such as SlipNotFoundError, QuotaExceededError and RateLimitError, and they all share the type EasySlipError. In JavaScript, Python and PHP it is the base class of every error. In Go it is an interface, and you find the exact type with errors.As. Error Codes explains each code the API returns.
  • Webhook checks. Each SDK checks the X-EasySlip-Signature header, which holds sha256= followed by the HMAC-SHA256 of the raw body, with a constant time comparison. The webhook examples in each guide answer status 400 when the signature is missing or wrong and when a signed body is not a webhook event.

Source code and license ​

The source code of each SDK is on GitHub: sdk-js, sdk-python, sdk-go and sdk-php. Each repository has a README, a changelog and an examples folder with one runnable program for every method. Report bugs on the repository's Issues page, and never post your API key or a real slip there.

All four SDKs are released under the MIT License, Copyright (c) 2026 EasySlip Co., Ltd.

For questions about your account, quota or billing, contact EasySlip on LINE @ai-easy, by phone at 02-114-8806 or through the contact page.

Bank Slip Verification API for Thai Banking