Thai Company Data API (eKYB)
Returns a Thai company's or partnership's registration record from its 13-digit registration number: status, capital, industry, address, directors, financial statements and a credit risk assessment.
The database holds all 1,751,616 juristic persons in the Department of Business Development (DBD) register (27 October 2026). A lookup reads that database and answers in under a second; when a company is newer than the copy, the live endpoints fetch it from DBD at the time of the call.
Request
GET with the registration number in the path; POST with JSON for the batch. A company is identified by its 13-digit registration number (เลขทะเบียนนิติบุคคล), which is also its tax ID.
Headers
apikeystringrequiredPath
company_idstringrequired0135556015413. A number with a wrong check digit is refused before anything is billed.Query
as_ofstring/snapshot: a date, 2026-09-30, or a date and time with the offset URL-encoded, 2026-09-30T12:00:00%2B07:00. Without it, the current version.nameprovincestatustsicstring/company/search, all four required: part of the Thai name, a province (a misspelling is resolved), the status in Thai as the register writes it, ยังดำเนินกิจการอยู่, ร้าง or เลิก, and a 5-digit industry code (TSIC), 62022. Matches the name partially first, then by similarity.namestring/person/search: a person's name in Thai, with or without the title, at least 2 characters.limitoffsetstring/person/search they count people, not companies.Body
idsfieldsbody/batch: {"ids": ["0135556015413", "..."], "fields": "summary"}, up to 50 numbers and 16 KB. summary returns name, province, industry code and status for each; full returns the whole record.| Endpoint | Returns | Price |
|---|---|---|
GET /ekyb/v1/company/{company_id} | The registration record | 2 IC |
GET …/{company_id}/financial | Financial statements for up to five fiscal years, and the filing status | 1 IC |
GET …/{company_id}/risk | 10 red-flag rules and a 0 to 100 risk score | 2 IC |
GET …/{company_id}/snapshot | The record as it stood on a date | Free |
POST /ekyb/v1/company/batch | Up to 50 companies in one call | 2 IC per company found |
GET /ekyb/v1/company/search | Companies by Thai name, province, status and industry | 1 IC when anything is found, otherwise free |
GET /ekyb/v1/person/search | The companies where a person is a director or partner | 2 IC when anything is found, otherwise free |
GET /ekyb/live/v1/company/{company_id} | The record, fetched from DBD now | 4 IC |
GET /ekyb/live/v1/company/{company_id}/risk | The risk assessment on a live fetch | 6 IC |
GET or POST /ekyb/live/v1/company/search | DBD's own name search; returns numbers and names, not records | 2 IC |
Only a successful response is billed: an error, a company not found and an empty search cost nothing. A live lookup also adds or refreshes the company in the database, so later lookups find it at the database price.
Response
Every success is {"status": "success", "data": ..., "meta": ...}. The panel shows the registration record.
idnamenameEngstringtypeOfEntityoperatingStatusstringtypeOfEntityEng and operatingStatusEng.registrationDateISOstringregistrationDate gives it in Thai, 08 ส.ค. 2556.registerCapitalpaidCapitalnumbertsicCodetsicCodeLatesttsicstring, objectaddressaddressDetailstring, objectdirectorspartnersmanaging_partnersarraytitle, firstName and lastName. A company has directors; a partnership has partners.authorized_signatorystringhistoryChangeNamehistoryChangeCapitalarraysubmittedFiscalYearsarraymeta.sourcestringredis or db, read from the database; dbd, fetched live.meta.dataAsOfstringmeta.last_seen_dataAsOf is when it was last read from DBD, and meta.updated_dataAsOf when its content last changed.Financial statements, risk, searches and batch
/financial. Read financialStatus before the numbers: ok, statements filed; never_submitted, the company has never filed, which is a definite answer; expected_but_missing, statements should exist but could not be retrieved yet, which must not be read as "no statements"; fetch_error, retrieval failed. summary gives the latest year's revenue, profit or loss and total assets; financial holds the balance sheet, income statement and ratios by year.
/risk. risk_score runs from 0 to 100 and higher means riskier; it is not a credit bureau score. risk_level is low below 20, medium from 20 and high from 50. Each raised rule is in risk_flags with its code, severity, weight and the evidence. A rule that could not be evaluated, for lack of statements for instance, is listed in risk_coverage.unavailable: no flag is not the same as checked and clean.
| Rule | Raised when | Weight |
|---|---|---|
INACTIVE_STATUS | The status is ร้าง, เลิก, เสร็จการชำระบัญชี, ล้มละลาย or พิทักษ์ทรัพย์ | 40 |
NO_FILING_2Y | No statements for 2 consecutive years (15 if the company has never filed) | 25 |
NEGATIVE_EQUITY | Shareholders' equity is negative | 25 |
LOSS_3Y | A loss in 3 consecutive years | 20 |
DIRECTOR_LINKED_STRUCK_OFF | A director or partner sits on 3 or more struck-off companies | 15 |
PEER_LEVERAGE_TSIC | Debt to equity far above companies with the same industry code | 10 |
REVENUE_DROP_YOY | Revenue down 30% or more on the year before | 10 |
FREQUENT_CHANGES | 2 name changes or 3 capital changes within 3 years | 10 |
CAPITAL_VS_REVENUE_LOW | Registered capital under 1% of revenue, for revenue of 10 million baht or more | 5 |
YOUNG_HIGH_CAPITAL | Under 2 years old with registered capital of 5 million baht or more | 5 |
DIRECTOR_LINKED_STRUCK_OFF is common in large groups, whose directors sit on many boards; on its own it leaves a company at low. The live risk endpoint cannot evaluate it and lists it as unavailable.
/company/search and /person/search. data is an array; meta carries totalItems, returned and hasMore (totalPersons and returnedPersons on /person/search). Nothing found is HTTP 200 with an empty array. Each person comes with their companies, at most 50, each with the role: director, partner or managing_partner. A name is not an identity: the register publishes no ID card numbers, so two people with the same name are one entry, and meta.confidence is always name_only.
/batch. data lists the numbers in the order sent, each with found and, when not found, a reason; meta counts requested, found, notInDb, invalid and duplicates. Only found companies are billed.
/snapshot. The record has the same shape as a lookup. History is kept from 28 August 2026, one version each time the record changes: meta.versions counts them, meta.historyFrom is the earliest date this company can be asked for, and meta.validFrom and meta.validTo give the period the returned version was current.
Details
Errors
An error is {"status": "error", "error": {"code", "message", "details", "requestId"}}. Act on code; the wording of message may change.
| HTTP | code | Meaning |
|---|---|---|
| 400 | INVALID_JURISTIC_ID | Not 13 digits, or the check digit is wrong; details.reason says which |
| 400 | INVALID_REQUEST, BATCH_TOO_LARGE | A parameter is missing or invalid (details names it), or more than 50 numbers |
| 404 | COMPANY_NOT_IN_DB | Not in the database. Check the number; a company registered in the last few days can be fetched with the live lookup |
| 404 | COMPANY_NOT_FOUND | Live lookup: DBD has no company with this number |
| 404 | SNAPSHOT_NOT_FOUND | The date is before the record's history begins; details.historyFrom gives the first date |
| 413 | PAYLOAD_TOO_LARGE | A batch body over 16 KB |
| 503 | REQUEST_TIMEOUT, UPSTREAM_RATE_LIMITED | Live endpoints: DBD did not answer in 25 seconds or is limiting requests. Retry after details.retryAfterSeconds |
The gateway answers 401 for a missing or wrong key and 429 over the rate limit, as {"message": ...}.
Limits
- Database endpoints: 100 requests a second per key; they answered in 0.16 to 0.74 seconds end to end in our tests on 27 October 2026.
- Live endpoints: 30 requests a minute per key, the lookup and the risk endpoint counting together and the search separately. A live lookup took 1.0 second in the same test; when DBD is slow a call waits up to 25 seconds, then returns
503with a retry time. - Shareholder lists (บอจ.5) and beneficial owners are not included:
shareholdersanduboare empty andubo_availableisfalse.
Data handling
The data is DBD's public register. Directors' and partners' names in it are personal data: use them only for a lawful purpose, such as a KYB, credit or supplier check, under your own basis under PDPA. Requests are logged with the calling key for billing and support.