Getting started
Verify your first slip in 5 minutes — set up a shop, link LINE, check your quota, call the API (Starter and up)
Everything you need to do for SlipBolt to verify your first slip
1. Create an account + shop
Go to app.slip-bolt.com/auth/signup and confirm your email, then name your shop during onboarding — a shop's first 7 days are always a trial (Trial-plan entitlements only, not a free Pro/Business)
During the trial you get:
- 50 slips · 1 seat (the owner) · 1 LINE group · 1 LINE OA
- Slip verification through LINE OA + Dashboard
- No REST API / Webhooks — API keys become available once you upgrade to Starter or higher
Your remaining quota is shown right on the Dashboard (the quota tile) — no API key needed
2. Add a receiving account
Settings → Shop → Receiving accounts — if a shop has no account for customers to pay into,
every slip is rejected (NO_PAYEE_CONFIGURED) before it is sent for verification
3. Link your LINE OA
At Settings → LINE Channels, paste the Channel ID + Secret + Access Token from LINE OA Manager, then invite the bot into a group and send one test slip
4. Create an API key (Starter plan and up)
At Settings → API Keys, create a new key — the full key is shown only once.
Keys cannot be issued during the Trial (403 PLAN_API_ACCESS_REQUIRED)
sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Copy it right away — we only keep an argon2 hash on the server (lose it and you have to create a new one)
5. Make your first call
Put the key in an environment variable first (never in code) — during development use an sk_test_ key;
it does not consume the shop's quota
export SLIPBOLT_API_KEY="sk_test_..."
Then send the slip image as raw bytes to POST /api/v1/verify
— pick your language; the choice is remembered on every page
curl -X POST https://api.slip-bolt.com/api/v1/verify \
-H "Authorization: Bearer $SLIPBOLT_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary "@slip.jpg"
Response (abridged — every field is in the API Reference):
{
"success": true,
"data": {
"status": "SUCCESS",
"verified": true,
"duplicate": false,
"amount": 50.0,
"transRef": "20260525123045123456",
"transDate": "2026-05-25T05:30:45.000Z",
"senderName": "นายสมชาย ใจดี",
"bankName": "ธนาคารกสิกรไทย",
"receiverName": "ร้านกาแฟพี่ตุ๊ก",
"environment": "test",
"quota": { "used": 1, "limit": 500, "remaining": 499 }
},
"meta": { "requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c", "timestamp": "2026-05-25T05:30:46.412Z" }
}
Names come back exactly as printed on the slip — for Thai banks that is usually Thai script.
When is it safe to release the order — 4 checks
data.verified === true— a genuine slip, paid into the shop's accountdata.duplicate === false— not a slip that has already been used (a customer resending an old slip)data.amountmatches your order total — the API does not know how much this order should cost; you have to compare it yourself (a customer can transfer 1 THB and send that slip — the slip is still "genuine")data.transRefis not yet attached to another order in your system — storetransRefin a UNIQUE column (resending the same image within 24 hours returns the original result withduplicatestillfalse⇒ checks 1–3 cannot stop one slip closing two orders)
Complete code that runs all 4 checks, with retries and an upload page, is in Recipes
Don't accept old slips? A genuine slip transferred more than 24 hours ago still gets verified: true, but carries errorCode: "STALE_SLIP" — if your business needs to reject those, check that field as well (see Stale slip)
https://api.slip-bolt.com/api/v1/openapi.json — open it in Postman / Insomnia / Bruno to try every endpoint right away, or generate a client in another language (Go · Java · C# …) with openapi-generator
· the full path has the /api/v1/ prefix — https://api.slip-bolt.com/openapi.json at the domain root redirects to the same place
Ready-made Postman collection: https://api.slip-bolt.com/api/v1/postman.json — import it, set the apiKey variable and send · POST /verify comes as 5 separate requests (raw file · multipart · base64 · url · qr)
Copy-paste POST /verify in Node.js · Python · PHP · Go · Java · C# is in Recipes
The result is always under data — every successful response is wrapped in { success, data, meta }.
Reading response.verified directly gives undefined (the most common mistake on a first integration)
API calls use the same quota as the shop's LINE slips · check the balance via quota in the response or the X-Slipbolt-Quota-Remaining header · quota used up → 402 (see API Reference) · use an sk_test_ key to test without consuming the shop's quota (separate cap of 200 calls/month)
6. Check your remaining quota (uses no slips)
| Channel | Use when | What you get |
|---|---|---|
| Dashboard → quota tile | Every plan, including Trial | used / limit / days until reset |
GET /api/v1/quota | You have an API key + read scope | The shop's quota only |
GET /api/v1/me | You have an API key + read scope | Shop · key · plan · live+test quota · receiving accounts (last 4 digits) |
curl https://api.slip-bolt.com/api/v1/me \
-H "Authorization: Bearer sk_live_..."
Field details are in API Reference — GET /me
7. Receive Webhooks (optional)
Subscribe at /settings/webhooks and the system POSTs an event every time there is a new slip result:
{
"event": "slip.verified",
"id": "evt_9f3c1a7b2d4e6f8a0b1c2d3e",
"created": 1781107927,
"data": {
"transactionId": "8f3c…",
"transRef": "20260525123045123456",
"amount": 50.0,
"status": "SUCCESS",
"sender": "นายสมชาย ใจดี",
"receiver": "ร้านกาแฟพี่ตุ๊ก",
"verifiedAt": "2026-05-25T05:30:46.412Z",
"latencyMs": 480
}
}
Verify the signature every time — the X-Slipbolt-Signature header looks like t=<unix>,v1=<hex>
where v1 = HMAC-SHA256(secret, ts + "." + raw_body) (ts = the number after t=) · the signed string has no t= prefix
and must use the raw body — ready-to-use code is at Webhooks
Next steps
Copy-paste code — a client with retries · take a slip and close the order · test webhooks locally
→Every endpoint + error code
→Bearer vs API key
→Retry policy + signature verification
→Encryption + data-subject rights
→GET /me + GET /quota — uses no slips
