STICBOX OCR API

STICBOX OCR API ให้บริการแปลงเอกสารและรูปภาพเป็นข้อความ (Optical Character Recognition) ผ่าน REST API โดยรองรับหลายรูปแบบไฟล์และส่งคืนตำแหน่ง bounding box ของข้อความทุก paragraph

Base URL:  https://api.sticbox.com  —  ทุก endpoint ใช้ HTTPS เท่านั้น

รูปแบบ Response

ทุก response เป็น JSON และมี field success: true/false เสมอ เมื่อเกิดข้อผิดพลาด จะมี field error.code และ error.message

Sync vs Async

  • รูปภาพ (PNG, JPG, TIFF, WebP): ประมวลผล synchronous — ได้ผลลัพธ์ทันทีใน HTTP 200
  • PDF: ประมวลผล asynchronous — ได้ task_id ใน HTTP 202 แล้ว poll สถานะด้วย GET /v1/ocr/status/{task_id}

รูปแบบไฟล์ที่รองรับ

รูปแบบModeขนาดสูงสุดหมายเหตุ
PDFAsync20 MBแปลงทุกหน้าเป็นรูปภาพแล้ว OCR
PNGSync20 MB
JPG / JPEGSync20 MB
TIFF / TIFSync20 MB
WebPSync20 MB
GIFSync20 MBเฉพาะ frame แรก

Authentication

ทุก request ต้องส่ง API Key ใน HTTP header X-API-Key

HTTP Header
X-API-Key: sb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
สร้าง API Key ได้ที่ Dashboard → API Keys — รูปแบบ sb_live_ ตามด้วย 40 ตัวอักษร
อย่าเก็บ API Key ใน source code หรือ version control — ใช้ environment variable แทน

Quick Start

ตัวอย่างการส่งไฟล์ภาพเข้า OCR ด้วย cURL:

bash
# OCR รูปภาพ (sync)
curl -X POST https://api.sticbox.com/v1/ocr \
  -H "X-API-Key: sb_live_xxxx" \
  -F "file=@invoice.jpg"

# OCR PDF (async) — ขั้นตอนที่ 1: ส่งไฟล์
curl -X POST https://api.sticbox.com/v1/ocr \
  -H "X-API-Key: sb_live_xxxx" \
  -F "file=@document.pdf"

# ขั้นตอนที่ 2: ตรวจสอบสถานะ
curl https://api.sticbox.com/v1/ocr/status/{task_id} \
  -H "X-API-Key: sb_live_xxxx"

POST /v1/ocr

อัปโหลดไฟล์และทำ OCR — คืนข้อความที่แยกได้พร้อม bounding box ของแต่ละ paragraph และข้อมูลการเรียกเก็บเงิน

Request Headers

Headerประเภทคำอธิบาย
X-API-Keyrequired string API Key ที่ได้จาก Dashboard
Content-Typerequired string multipart/form-data

Request Body (multipart/form-data)

Fieldประเภทคำอธิบาย
filerequired file ไฟล์ที่ต้องการ OCR — PDF, PNG, JPG, JPEG, TIFF, WebP ขนาดสูงสุด 20 MB

Response — 200 OK (รูปภาพ, sync)

200 OKapplication/json
{
  "success": true,
  "request_id": "OCR-20240608-A3F9C1B2",
  "pages": 1,
  "cost": 0.2000,
  "processing_time": 1.23,
  "text": "ใบเสร็จรับเงิน\nเลขที่ 1234/2024\n...",
  "blocks": [
    {
      "page": 1,
      "text": "ใบเสร็จรับเงิน",
      "confidence": 0.9981,
      "bounding_box": { "x": 48, "y": 32, "width": 220, "height": 28 }
    }
  ]
}

Response — 202 Accepted (PDF, async)

202 Acceptedapplication/json
{
  "success": true,
  "message": "File accepted for processing",
  "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status_url": "/v1/ocr/status/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
สำหรับ PDF ให้ poll status_url ทุก 2-5 วินาที จนกว่าสถานะจะเป็น SUCCESS หรือ FAILURE

GET /v1/ocr/status/{task_id}

ตรวจสอบสถานะของ OCR task ที่ส่งมาจาก PDF upload (async mode)

Path Parameters

Parameterประเภทคำอธิบาย
task_idrequired string task_id ที่ได้รับจาก POST /v1/ocr (202 response)

Response States

PENDING task ยังรอการประมวลผล — poll ใหม่อีกครั้ง
SUCCESS ประมวลผลสำเร็จ — field result มีข้อมูล OCR เหมือนกับ 200 response
FAILURE ประมวลผลไม่สำเร็จ — field error ระบุสาเหตุ
200 OK — PENDING
{ "success": true, "status": "PENDING" }
200 OK — SUCCESS
{
  "success": true,
  "status": "SUCCESS",
  "result": { /* เหมือนกับ 200 response ของ POST /v1/ocr */
    "text": "...", "pages": 5, "cost": 0.7500, "blocks": [...]
  }
}

GET /v1/balance

ดูยอด credit คงเหลือในบัญชี ต้องการ JWT authentication (login ผ่าน Dashboard หรือใช้ Bearer token)

200 OK
{ "success": true, "balance": 48.3250 }

GET /v1/transactions

ดูประวัติธุรกรรมของบัญชี

Query Parameters

ParameterประเภทDefaultคำอธิบาย
pageoptionalinteger1หน้าที่ต้องการ
per_pageoptionalinteger20จำนวนรายการต่อหน้า (สูงสุด 100)
200 OK
{
  "success": true,
  "transactions": [
    { "type": "DEBIT", "amount": "0.2000", "balance_after": "48.3250",
      "description": "OCR - 1 page(s) - PNG", "reference_id": "OCR-20240608-A3F9C1B2",
      "created_at": "2024-06-08T13:45:00" }
  ],
  "pagination": { "page": 1, "per_page": 20, "total": 42 }
}

GET /v1/usage/monthly

ดูสถิติการใช้งานรายเดือน

Query Parameters

Parameterประเภทคำอธิบาย
yearrequiredintegerปี เช่น 2024
monthrequiredintegerเดือน 1–12
200 OK
{
  "success": true,
  "usage": {
    "total_requests": 128, "total_pages": 312,
    "total_cost": 62.4000, "avg_response_time_ms": 1420,
    "daily": [
      { "date": "2024-06-08", "requests": 12, "pages": 28, "cost": 5.6000 }
    ]
  }
}

รูปแบบ OCR Response

เมื่อ OCR สำเร็จ (200 สำหรับรูปภาพ หรือ result ใน 200 ของ status endpoint) fields มีดังนี้:

success boolean true เสมอเมื่อสำเร็จ
request_id string รหัสอ้างอิงของ request เช่น OCR-20240608-A3F9C1B2
text string ข้อความทั้งหมดที่แยกได้ — หน้าคั่นด้วย newline สองบรรทัด
pages integer จำนวนหน้าที่ประมวลผล
cost float ค่าใช้จ่ายจริง (THB) ที่หักจาก wallet
processing_time float เวลาประมวลผล (วินาที)
blocks array ข้อมูล bounding box ระดับ paragraph — ดู Bounding Boxes

Bounding Boxes

field blocks ประกอบด้วย array ของ paragraph แต่ละอันมีตำแหน่งพิกเซลบนรูปภาพ ช่วยให้ระบุตำแหน่งของข้อความในเอกสารได้แม่นยำ

page integer หมายเลขหน้าที่ข้อความนี้อยู่ (เริ่มจาก 1)
text string ข้อความของ paragraph นี้
confidence float ความมั่นใจของ OCR (0.0–1.0) เช่น 0.9981
bounding_box.x integer พิกัด x ของมุมบนซ้าย (พิกเซล)
bounding_box.y integer พิกัด y ของมุมบนซ้าย (พิกเซล)
bounding_box.width integer ความกว้างของกล่องข้อความ (พิกเซล)
bounding_box.height integer ความสูงของกล่องข้อความ (พิกเซล)
พิกัด bounding box อ้างอิงจากรูปภาพที่ render ด้วย scale 2× (200 DPI) สำหรับ PDF สามารถ map กลับได้ด้วยการหาร x, y, width, height ด้วย 2

ตัวอย่าง block

json
{
  "page": 1,
  "text": "ใบเสร็จรับเงิน",
  "confidence": 0.9981,
  "bounding_box": {
    "x": 48,
    "y": 32,
    "width": 220,
    "height": 28
  }
}

Error Codes

เมื่อเกิดข้อผิดพลาด response จะมีรูปแบบ:

json
{ "success": false, "error": { "code": 401, "message": "Invalid or inactive API key" } }
HTTP Statusสาเหตุวิธีแก้ไข
400 Bad Request ไม่มีไฟล์, ชื่อไฟล์ว่าง, หรือรูปแบบไฟล์ไม่ถูกต้อง ตรวจสอบ field file และนามสกุลไฟล์
401 Unauthorized ไม่มี API Key หรือ Key ไม่ถูกต้อง/ถูกยกเลิก ตรวจสอบ header X-API-Key
402 Payment Required ยอด credit ไม่พอสำหรับการประมวลผล เติม credit ที่ Dashboard → Wallet
413 Request Too Large ไฟล์ใหญ่เกิน 20 MB ลดขนาดไฟล์ก่อนส่ง
415 Unsupported Media Type รูปแบบไฟล์ไม่รองรับ หรือ magic bytes ไม่ตรงกับนามสกุล ใช้ไฟล์ที่รองรับและไม่ถูกแก้ไข header
429 Too Many Requests เกิน rate limit (60 req/min หรือ 1000 req/day) ลด request rate หรือรอ 60 วินาที
503 Service Unavailable ระบบอยู่ในโหมด Maintenance ตรวจสอบสถานะที่ api.sticbox.com/status
500 Internal Server Error ข้อผิดพลาดภายในระบบ ลองอีกครั้ง — หากปัญหายังคงอยู่ แจ้ง support

Rate Limits & Quota

ประเภทขีดจำกัดหมายเหตุ
Rate limit60 requests / นาทีต่อ API Key
Daily quota1,000 requests / วันรีเซ็ตเที่ยงคืน UTC
Monthly quota10,000 requests / เดือน
Max file size20 MBต่อไฟล์

เมื่อเกิน rate limit จะได้รับ 429 Too Many Requests พร้อม header Retry-After


ราคา

0.20 THB
รูปภาพ 1 ใบ
PNG, JPG, TIFF, WebP
0.15 THB
PDF 1 หน้า
คำนวณตามหน้าจริง
5.00 THB
เครดิตฟรีตอนสมัคร
≈ 25 รูปภาพ หรือ 33 หน้า PDF
ไม่มีค่าสมัคร — จ่ายเฉพาะที่ใช้จริง เติม credit ได้ทุกเมื่อที่ Dashboard → Wallet

ตัวอย่างโค้ด

ตัวอย่างการส่ง OCR request พร้อม poll สถานะสำหรับ PDF:

python
import requests, time

API_KEY  = "sb_live_xxxx"
BASE_URL = "https://api.sticbox.com"

def ocr_file(file_path):
    headers = {"X-API-Key": API_KEY}

    with open(file_path, "rb") as f:
        res = requests.post(
            f"{BASE_URL}/v1/ocr",
            headers=headers,
            files={"file": f},
        )

    data = res.json()

    # รูปภาพ — ได้ผลทันที
    if res.status_code == 200:
        return data

    # PDF — poll สถานะ
    if res.status_code == 202:
        status_url = BASE_URL + data["status_url"]
        while True:
            r = requests.get(status_url, headers=headers)
            d = r.json()
            if d["status"] == "SUCCESS":
                return d["result"]
            if d["status"] == "FAILURE":
                raise RuntimeError(d.get("error"))
            time.sleep(2)

    raise RuntimeError(data.get("error", {}).get("message"))

# ใช้งาน
result = ocr_file("invoice.pdf")
print(result["text"])
# แสดง bounding boxes
for block in result["blocks"]:
    print(f"p{block['page']} {block['bounding_box']}: {block['text'][:30]}")
javascript (Node.js)
import fs from 'fs';
import FormData from 'form-data';
import fetch from 'node-fetch';

const API_KEY  = 'sb_live_xxxx';
const BASE_URL = 'https://api.sticbox.com';

async function ocrFile(filePath) {
  const form = new FormData();
  form.append('file', fs.createReadStream(filePath));

  const headers = { ...form.getHeaders(), 'X-API-Key': API_KEY };
  const res = await fetch(`${BASE_URL}/v1/ocr`, { method: 'POST', headers, body: form });
  const data = await res.json();

  // รูปภาพ — sync
  if (res.status === 200) return data;

  // PDF — async poll
  if (res.status === 202) {
    const statusUrl = BASE_URL + data.status_url;
    while (true) {
      const r = await fetch(statusUrl, { headers: { 'X-API-Key': API_KEY } });
      const d = await r.json();
      if (d.status === 'SUCCESS') return d.result;
      if (d.status === 'FAILURE') throw new Error(d.error);
      await new Promise(r => setTimeout(r, 2000));
    }
  }
  throw new Error(data.error?.message);
}

// ใช้งาน
const result = await ocrFile('invoice.pdf');
console.log(result.text);
php
<?php
$apiKey  = 'sb_live_xxxx';
$baseUrl = 'https://api.sticbox.com';

function ocrFile($filePath, $apiKey, $baseUrl) {
    $ch = curl_init($baseUrl . '/v1/ocr');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => ["X-API-Key: $apiKey"],
        CURLOPT_POSTFIELDS     => ['file' => new CURLFile($filePath)],
    ]);
    $body = json_decode(curl_exec($ch), true);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // รูปภาพ
    if ($code === 200) return $body;

    // PDF — poll
    if ($code === 202) {
        $statusUrl = $baseUrl . $body['status_url'];
        while (true) {
            sleep(2);
            $r = json_decode(file_get_contents(
                $statusUrl, false,
                stream_context_create(['http' => ['header' => "X-API-Key: $apiKey"]])
            ), true);
            if ($r['status'] === 'SUCCESS') return $r['result'];
            if ($r['status'] === 'FAILURE') throw new Exception($r['error']);
        }
    }
    throw new Exception($body['error']['message'] ?? 'Unknown error');
}

$result = ocrFile('invoice.pdf', $apiKey, $baseUrl);
echo $result['text'];
bash (cURL)
# OCR รูปภาพ (sync)
curl -X POST https://api.sticbox.com/v1/ocr \
  -H "X-API-Key: sb_live_xxxx" \
  -F "file=@invoice.jpg" | python3 -m json.tool

# OCR PDF (ขั้นตอนที่ 1: ส่งไฟล์)
curl -X POST https://api.sticbox.com/v1/ocr \
  -H "X-API-Key: sb_live_xxxx" \
  -F "file=@document.pdf"
# ได้รับ: {"task_id": "...", "status_url": "/v1/ocr/status/..."}

# OCR PDF (ขั้นตอนที่ 2: ตรวจสอบสถานะ)
curl https://api.sticbox.com/v1/ocr/status/TASK_ID \
  -H "X-API-Key: sb_live_xxxx"

# ดู credit คงเหลือ (ต้องใช้ JWT Bearer token)
curl https://api.sticbox.com/v1/balance \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"