# Get started

Source: https://checkslip.com/en/docs

This page takes you from sign-up to a first request that returns a result, in a few minutes of reading. Every route is described in the [API reference](https://checkslip.com/en/docs/reference)

## 1. Create an API key

1. [Sign up](https://app.checkslip.com/sign-up?utm_source=site&utm_content=docs) and confirm your mobile number. The account gets 50 trial credits
2. Open the [API keys page](https://app.checkslip.com/keys), create a key and choose the slip:lookup scope (add slip:read to read history as well; neither scope includes the other)
3. Copy the key and store it right away. It starts with csk_ and is shown only once: we do not keep the key itself, so it cannot be viewed again. If you lose it, create a new key and revoke the old one.

Keep the key on your server. Never put it in web page code or a mobile app.

## 2. Send your first request

Read the text in the QR on the slip with any QR reader and send it.

**cURL**

```bash
curl https://api.checkslip.com/api/slips/lookup \
  -H "Authorization: Bearer $CHECKSLIP_API_KEY" \
  -H "Idempotency-Key: order-1042-slip-1" \
  -H "Content-Type: application/json" \
  -d '{"qr":"00330006000001010306902126302105340875102TH9104F86F"}'
```

**Node.js**

```javascript
const res = await fetch("https://api.checkslip.com/api/slips/lookup", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CHECKSLIP_API_KEY}`,
    "Idempotency-Key": "order-1042-slip-1",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    qr: "00330006000001010306902126302105340875102TH9104F86F",
  }),
});
const data = await res.json();
```

**Python**

```python
import os

import requests

res = requests.post(
    "https://api.checkslip.com/api/slips/lookup",
    headers={
        "Authorization": f"Bearer {os.environ['CHECKSLIP_API_KEY']}",
        "Idempotency-Key": "order-1042-slip-1",
    },
    json={
        "qr": "00330006000001010306902126302105340875102TH9104F86F",
    },
)
data = res.json()
```

The qr value above only shows the format; use the text of the QR on the slip your customer sent you. Without a QR at hand, send the slip image instead as multipart/form-data, field image.

## 3. Read the answer

Decide from outcome in the body, not from the HTTP status.

```json
{
  "request_id": "0192d4e0-7c1a-7b3e-9f00-1a2b3c4d5e6f",
  "outcome": "FOUND",
  "checked_at": "2026-10-29T10:41:02+07:00",
  "slip": {
    "trans_ref": "630210534087",
    "transferred_at": "2026-10-29T10:33:30+07:00",
    "amount": {
      "satang": 5000,
      "currency": "THB"
    },
    "sender": {
      "bank": {
        "code": "KKP",
        "bot_code": "069",
        "name_th": "ธนาคารเกียรตินาคินภัทร",
        "name_en": "Kiatnakin Phatra Bank"
      },
      "name_th": "นาย สมชาย ใ",
      "name_en": "MR. SOMCHAI J",
      "account": "0439"
    },
    "receiver": {
      "kind": "BANK_ACCOUNT",
      "bank": {
        "code": "GSB",
        "bot_code": "030",
        "name_th": "ธนาคารออมสิน",
        "name_en": "Government Savings Bank"
      },
      "name_th": "นางสาว สมหญิง ร",
      "name_en": "MISS SOMYING R",
      "account": "9681"
    }
  }
}
```

| `outcome` | What it means for your shop | Credit |
| --- | --- | --- |
| `FOUND` | **Found** The bank holds this transfer. Compare the amount, receiver and time with your order, then decide yourself. | 1 credit taken |
| `NOT_FOUND` | **Not found** The bank holds no transfer for this trans_ref at the time we asked. It only says there is no transfer, not why. You decide, for example by asking the customer for more proof. | No credit taken |
| `DUPLICATE` | **Duplicate** Your account already got a found result for this slip; duplicate_of.request_id points at the first one. If that was another order, the slip was already used with your shop. If it was the same order, see step 5. | No credit taken |
| `PENDING` | **Waiting for bank** [Transfer lookup outcomes](https://checkslip.com/en/docs/outcomes) | No credit taken |
| `UNAVAILABLE` | **Unavailable** [Error codes](https://checkslip.com/en/problems/unavailable) | No credit taken |
| `INVALID_QR` | **Invalid QR** [Error codes](https://checkslip.com/en/problems/invalid-qr) | No credit taken |
| `INVALID_FILE` | **Unreadable file** [Error codes](https://checkslip.com/en/problems/invalid-file) | No credit taken |
| `QR_TAMPERED` | **QR mismatch** [Error codes](https://checkslip.com/en/problems/qr-tampered) | No credit taken |
| `TOO_OLD` | **Too old** [Error codes](https://checkslip.com/en/problems/too-old) | No credit taken |

A lookup is still named check in the API, in the error code [`CHECK_NOT_FOUND`](https://checkslip.com/en/problems/check-not-found). The name is kept for compatibility and means the same lookup.

## 4. When a credit is taken

One credit is taken only when the outcome is FOUND. Other outcomes take none, DUPLICATE and NOT_FOUND included.

PENDING (waiting for the bank) takes nothing yet: we ask the bank again for you, take one credit if the transfer turns up later, and send the result by webhook.

Your credit balance and every credit taken are in [the app](https://app.checkslip.com)

## 5. Send Idempotency-Key with every request

If the connection drops or times out before you get an answer, send the same request again with the same Idempotency-Key within 24 hours. You get the first answer back (same request_id, same result): no new lookup with the bank and no extra credit.

Sent again without the first key, it is a new request. If the first one was FOUND, the new one is DUPLICATE and takes no credit, but your code may read it as a reused slip and turn away a customer who really paid.

The same slip sent in several requests at the same moment without a key is still charged once: one request gets FOUND and the rest get DUPLICATE. While the first one runs, every request holds a credit for a moment, so with few credits left an extra request may get 402 instead of DUPLICATE (neither is charged).

Use a key tied to the order and that slip, such as order-1042-slip-1. The same key with a different body gets the error [`idempotency-key-reused`](https://checkslip.com/en/problems/idempotency-key-reused), and while the first request is still running you get [`idempotency-in-flight`](https://checkslip.com/en/problems/idempotency-in-flight): wait and send again with the same key.

## 6. When something goes wrong

Every error is application/problem+json (RFC 9457). Read type to know what happened; each type has [a page with the cause and the fix](https://checkslip.com/en/docs/errors)

Contact the team with the instance value from the response (the same number as the X-Request-Id header).

## Next

- [Supported banks](https://checkslip.com/en/docs/banks)
- [All error codes](https://checkslip.com/en/docs/errors)
- [API reference for every route](https://checkslip.com/en/docs/reference)
