# Taiwan Company KYB Lookup (`zinin/taiwan-company-kyb-lookup`) Actor

Resolve Taiwan companies (統一編號 or legal name) to an evidence-backed KYB card from the official MOEA GCIS open-data registry. Free structural checks, free not-found/ambiguous/error outcomes; billed only for a complete, unambiguous company card.

- **URL**: https://apify.com/zinin/taiwan-company-kyb-lookup.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 66.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $17.00 / 1,000 resolved kyb company cards

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Taiwan Company KYB Lookup: Evidence-Backed Registry Cards from MOEA GCIS

![What this Actor does: input, evidence, outcome](https://raw.githubusercontent.com/TimmyZinin/apify-actor-assets/e200ae9e85a70951ef266530fe47539e033b73e2/signalops10/taiwan-company-kyb-lookup--readme-hero.webp)

This Actor is **Taiwan only**. It reads Taiwan's official company registry — 經濟部商業發展署商工行政
資料開放平臺 (MOEA Department of Commerce Development's open-data platform), host
`data.gcis.nat.gov.tw` — and nothing else. It does not read mainland China's registry, is not built on
QCC, Tianyancha or any mainland source, and an earlier internal version of this Actor that did target
the mainland was withdrawn and redesigned specifically because that source cannot be legally
redistributed without a signed commercial agreement no candidate provider would grant. If you need a
mainland Chinese company record, this is not that product.

The billable outcome is a **resolved KYB company card**: one company you submit, by its 統一編號
(Unified Business Number, 8 digits) or its exact traditional-Chinese legal name, matches exactly one
record in the official registry, with every field this card promises populated or explicitly named as
a gap. Everything else — a number that fails Taiwan's own checksum, no match, more than one candidate
for a name search, an incomplete or unmapped board response, a registry error or rate limit, or the
same real company already billed once this run under a different input identity — is free.

### What you get

- **One evidence-backed card per company**, sourced from a single official government registry, never
  a third-party aggregator or a cached mirror.
- **Both identity and board data**, when you request it: legal name, status, incorporation date,
  legal representative, registered and paid-in capital, address, registering authority, and — when
  `includeBoard` is on — the directors, supervisors and their shareholding, exactly as the registry
  publishes them.
- **No key, no login, no captcha.** The source is keyless open data, read on a licence that explicitly
  permits commercial reuse and sublicensing — checked directly against the licence text, not assumed.
- **Never a guessed field.** A value the registry did not publish is `null`, named in `gaps`, never
  invented or left silently absent.
- **A named reason for every free outcome.** A checksum failure, a no-match, an ambiguous name search,
  an incomplete board, or a repeat of an already-billed company all return a full row with a stable
  machine error code — never a bare empty result.
- **A card for human KYB review, not an automated decision.** `safeToAutomate` is fixed `false` on
  every row; this Actor hands you a registry excerpt, never a counterparty verdict.

### Who uses it

- **KYB and onboarding compliance teams** who need a defensible, source-linked Taiwan company record
  before approving a counterparty, vendor or customer.
- **Supply-chain and vendor-risk teams** confirming a Taiwan supplier's registration status, capital
  and legal representative before a contract is signed.
- **Investors and M\&A diligence teams** pulling a registered board composition — including when a
  board seat is held on behalf of a juristic-person shareholder, not a natural person acting alone.
- **Developers and workflow builders** who want a strict, flat, machine-checkable contract an agent or
  n8n node can branch on without parsing a registry page or a scraped table.

![Where the Actor sits in your pipeline: trigger, run, action](https://raw.githubusercontent.com/TimmyZinin/apify-actor-assets/e200ae9e85a70951ef266530fe47539e033b73e2/signalops10/taiwan-company-kyb-lookup--readme-workflow.webp)

### How to run

1. Supply one to one hundred companies: each either `unifiedBusinessNumber` (8 digits) or
   `legalNameZhTw` (exact traditional-Chinese registered name), never both on the same entry.
   `inputRef` is an optional opaque correlation string.
2. Leave `includeBoard` at its default `true` to also request board/shareholding data, or set it
   `false` to request only the company card — board data names living people, so this flag exists
   specifically so you can choose not to request it.
3. Optionally cap `maxConcurrency` (1–5, default 2) — local batching only; the registry is paced
   conservatively either way.
4. Start the run from the Console, the Apify API, a scheduled Task, or an MCP client.
5. Read the Dataset for one row per submitted company — present even for a duplicate, a checksum
   failure or a registry error, so row count against input count is itself a completeness check.
6. Read `OUTPUT` for the run-level summary: submitted, unique companies processed, duplicates skipped,
   billed, free counts by category, and whether the run stopped early.
7. Route every `resolved` card to a human KYB reviewer. `safeToAutomate` is fixed `false` specifically
   to keep this card out of an automated approve/reject decision.

A default-input smoke run reads a real, currently live registry record (TSMC, 統一編號 22099131) and
does not require any buyer secret — the source is keyless.

### Pricing

**$0.02 per resolved company card, plus $0.005 Actor start.** This Actor's own external cost is
zero: the registry is keyless and requires no paid account, so the price covers the verification
work, not a resold data bill.

What this page can state is the billing mechanism. The primary pricing noun is the **resolved KYB
company card** — one identity-matched, complete registry excerpt per company. Every other outcome is
free: a checksum failure, no match, an ambiguous name search, an incomplete board or company record, a
registry error or rate limit, and a repeat of an already-billed company within the same run. A run of
one hundred companies where only forty resolve to a complete card bills for forty, not one hundred.

### Input contract

`companies` is required: one to one hundred objects, each giving either `unifiedBusinessNumber` (8
digits, structurally validated against Taiwan's official checksum before any network request — a
number that fails it is rejected for free, with no registry call made at all) or `legalNameZhTw` (the
exact registered name in traditional Chinese; a search returning more than one candidate is a free
`ambiguous_match`, never a guess at which one you meant). `inputRef` is an optional opaque string up to
200 characters, copied back exactly, including whitespace.

`includeBoard` is a boolean, default `true`. `maxConcurrency` is an integer, 1–5, default 2, local
batching only. Companies are deduplicated on exact submitted identity before any network call —
submitting the identical `unifiedBusinessNumber` or normalized `legalNameZhTw` twice in one run charges
once; see Evidence and boundaries for the separate, narrower protection against the same real company
submitted once by number and once by name.

```json
{
  "companies": [
    { "unifiedBusinessNumber": "22099131", "inputRef": "kyb-check-4471" },
    { "legalNameZhTw": "大安精密科技股份有限公司", "inputRef": "kyb-check-4472" }
  ],
  "includeBoard": true,
  "maxConcurrency": 2
}
```

*(Contract illustration built from `.actor/input_schema.json`. `22099131` is TSMC's real, public
統一編號, used because the company-identity fields it resolves to are real, directly observed registry
data — see the happy-path example below. `大安精密科技股份有限公司` is an invented name used only to
illustrate a partial outcome and is not a real company.)*

### Real happy, partial and failure output

Every row shares one flat, 32-field schema regardless of outcome — checked directly against
`.actor/dataset_schema.json`'s own `required` array. The company-identity fields in the first example
below are real: they were read directly from the live registry (TSMC's actual record, 2026-08-12) and
are not invented. The second and third examples use an invented company and an invalid number
respectively, to illustrate the free outcomes.

#### Real registry data, illustrative row shape — TSMC, a complete resolved card

```json
{
  "recordType": "kyb_company_card",
  "schemaVersion": "1.0",
  "entityId": "22099131",
  "inputRef": "kyb-check-4471",
  "legalNameZhTw": "台灣積體電路製造股份有限公司",
  "legalNameEn": null,
  "status": "active",
  "caseStatus": "核准設立",
  "incorporationDate": "1987-02-21",
  "legalRepresentative": "魏哲家",
  "registeredCapital": 280500000000,
  "paidInCapital": 259323700670,
  "shareValue": 10,
  "registeredAddress": "新竹科學園區新竹市力行六路8號",
  "registeringAuthority": "國家科學及技術委員會新竹科學園區管理局",
  "board": [
    { "position": "董事長", "name": "魏哲家", "representingEntity": null, "shareholding": 7452349 },
    { "position": "董事", "name": "曾繁城", "representingEntity": null, "shareholding": 29472675 },
    { "position": "董事", "name": "葉俊顯", "representingEntity": "行政院國家發展基金管理會", "shareholding": 1653709980 },
    { "position": "獨立董事", "name": "彼得‧邦菲爵士", "representingEntity": null, "shareholding": 0 },
    { "position": "獨立董事", "name": "麥克‧史賓林特", "representingEntity": null, "shareholding": 0 },
    { "position": "獨立董事", "name": "摩西‧蓋弗瑞洛夫", "representingEntity": null, "shareholding": 0 },
    { "position": "獨立董事", "name": "拉斐爾‧萊夫", "representingEntity": null, "shareholding": 0 },
    { "position": "獨立董事", "name": "烏蘇拉‧伯恩斯", "representingEntity": null, "shareholding": 0 },
    { "position": "獨立董事", "name": "琳恩‧埃爾森漢斯", "representingEntity": null, "shareholding": 0 },
    { "position": "獨立董事", "name": "林全", "representingEntity": null, "shareholding": 126826 }
  ],
  "source": "經濟部商業發展署商工行政資料開放平臺 (data.gcis.nat.gov.tw)",
  "sourceUrl": "https://data.gcis.nat.gov.tw/od/data/api/5F64D864-61CB-4D0D-8AD9-492047CC1EA6?$format=json&$filter=Business_Accounting_NO+eq+22099131&$skip=0&$top=5",
  "sourceTimestamp": "2026-08-12T18:55:00.000Z",
  "fieldProvenance": {
    "legalNameZhTw": "registry", "legalNameEn": "unavailable", "status": "derived",
    "caseStatus": "registry", "incorporationDate": "derived", "legalRepresentative": "registry",
    "registeredCapital": "registry", "paidInCapital": "registry", "shareValue": "registry",
    "registeredAddress": "registry", "registeringAuthority": "registry"
  },
  "confidenceScore": 100,
  "gaps": ["legalNameEn"],
  "recommendedAction": "human_review_before_kyb_decision",
  "safeToAutomate": false,
  "partial": false,
  "partialReason": null,
  "verificationStatus": "resolved",
  "errorCode": null,
  "error": null,
  "retryable": false,
  "observedAt": "2026-08-12T18:55:00.000Z",
  "found": true
}
```

Every field on the left of the colon and the identity/financial values are real, read directly from
the registry (10 of 10 real board seats present, not the 1-of-10 ghost an earlier, unreviewed version
of this Actor's field mapping would have shipped — see Evidence and boundaries). `legalNameEn` is
`null` and named in `gaps` because no English-name field exists in either GCIS resource this Actor
reads, for any company, not only this one. `incorporationDate` is converted from the registry's own ROC
calendar value `0760221` (Republic-of-China year 76 = 1987).

#### Invented company, illustrative partial path — board data partially unmapped

```json
{
  "recordType": "kyb_company_card",
  "schemaVersion": "1.0",
  "entityId": "90000001",
  "inputRef": "kyb-check-4472",
  "legalNameZhTw": "大安精密科技股份有限公司",
  "legalNameEn": null,
  "status": "active",
  "caseStatus": "核准設立",
  "incorporationDate": "2011-06-14",
  "legalRepresentative": "陳建宏",
  "registeredCapital": 50000000,
  "paidInCapital": 50000000,
  "shareValue": 10,
  "registeredAddress": "新北市板橋區示範路12號",
  "registeringAuthority": "新北市政府",
  "board": [
    { "position": "董事長", "name": "陳建宏", "representingEntity": null, "shareholding": 2000000 },
    { "position": "監察人", "name": "林淑芬", "representingEntity": null, "shareholding": 500000 }
  ],
  "source": "經濟部商業發展署商工行政資料開放平臺 (data.gcis.nat.gov.tw)",
  "sourceUrl": "https://data.gcis.nat.gov.tw/od/data/api/4E5F7653-1B91-4DDC-99D5-468530FAE396?$format=json&$filter=Business_Accounting_NO+eq+90000001&$skip=0&$top=200",
  "sourceTimestamp": "2026-08-12T19:03:00.000Z",
  "fieldProvenance": {
    "legalNameZhTw": "registry", "legalNameEn": "unavailable", "status": "derived",
    "caseStatus": "registry", "incorporationDate": "derived", "legalRepresentative": "registry",
    "registeredCapital": "registry", "paidInCapital": "registry", "shareValue": "registry",
    "registeredAddress": "registry", "registeringAuthority": "registry"
  },
  "confidenceScore": 100,
  "gaps": ["legalNameEn", "board"],
  "recommendedAction": null,
  "safeToAutomate": false,
  "partial": true,
  "partialReason": "board_partially_unmapped",
  "verificationStatus": "partial_source_coverage",
  "errorCode": "partial_source_coverage",
  "error": "The company was identified, but some board rows could not be mapped and the board returned here is incomplete.",
  "retryable": false,
  "observedAt": "2026-08-12T19:03:00.000Z",
  "found": false
}
```

Entirely invented — `90000001` passes the official checksum but names no real company. This illustrates
a real, code-verified mechanism with two independent triggers, not one: this exact `partialReason`
fires both when the registry returns more raw board rows than this Actor can map to an identifiable
seat (a position and/or a name), and — a class an earlier review round found the first check alone
could not catch — when every mapped seat that does survive comes back with the same one field empty,
the fingerprint of a single source field renamed underneath this Actor rather than genuinely absent
data. Either shape ships free, never billed as if the board were complete. `recommendedAction` is
`null` here on purpose — see the note under Field dictionary about which free codes this build gives a
recommendation for and which it does not.

#### Free path — a UBN that fails Taiwan's own checksum, no request made

```json
{
  "recordType": "kyb_company_card",
  "schemaVersion": "1.0",
  "entityId": null,
  "inputRef": "kyb-check-4473",
  "legalNameZhTw": null,
  "legalNameEn": null,
  "status": null,
  "caseStatus": null,
  "incorporationDate": null,
  "legalRepresentative": null,
  "registeredCapital": null,
  "paidInCapital": null,
  "shareValue": null,
  "registeredAddress": null,
  "registeringAuthority": null,
  "board": [],
  "source": "經濟部商業發展署商工行政資料開放平臺 (data.gcis.nat.gov.tw)",
  "sourceUrl": null,
  "sourceTimestamp": null,
  "fieldProvenance": {},
  "confidenceScore": null,
  "gaps": [],
  "recommendedAction": "Verify the 統一編號 and resubmit; no request was sent to the registry.",
  "safeToAutomate": false,
  "partial": false,
  "partialReason": null,
  "verificationStatus": "checksum_invalid",
  "errorCode": "checksum_invalid",
  "error": "10000000 fails Taiwan's official Unified Business Number checksum.",
  "retryable": false,
  "observedAt": "2026-08-12T19:04:00.000Z",
  "found": false
}
```

`10000000` fails the official weighted-digit checksum. `sourceUrl` and `sourceTimestamp` are `null`
because this is the one outcome that never reaches the network at all — the check runs locally, before
any request, saving both this Actor's own request budget and your time.

### Field dictionary

| Field | Meaning | Important boundary |
|---|---|---|
| `recordType` | Always `"kyb_company_card"` | Constant discriminator |
| `schemaVersion` | Always `"1.0"` | Bumped on any breaking change, never silently |
| `entityId` | The company's real 統一編號 | Populated once a company is identified — on `resolved`, on a `partial_source_coverage` row that got that far, and on `duplicate_entity` (naming which already-billed company was repeated); `null` on every other free row |
| `inputRef` | Your caller reference, copied exactly | Never normalized; `null` when you did not supply one |
| `legalNameZhTw` | Registered name, traditional Chinese | `null` when no company was identified |
| `legalNameEn` | Always `null` | No English-name field exists at the source for any company; always named in `gaps` when a company is identified |
| `status` | Normalized status: `active`, `dissolved`, `revoked`, `suspended`, `liquidating`, `unknown` | Only `active` is confirmed against a live response; the rest are inferred by the registry's well-known terminology, not individually source-proof-verified — see Evidence and boundaries |
| `caseStatus` | Raw registry status text, verbatim | `null` when no company was identified |
| `incorporationDate` | ISO date, converted from the registry's ROC-calendar value | `null` if the source value is missing, malformed, or does not name a real calendar date — never a plausible-looking wrong date |
| `legalRepresentative` | Registered responsible person | `null` when no company was identified |
| `registeredCapital` | Capital\_Stock\_Amount, TWD | `null` when the source omits a parseable number |
| `paidInCapital` | Paid\_In\_Capital\_Amount, TWD | Best-effort field; `null` and named in `gaps` when absent, never gates billing alone |
| `shareValue` | Par value per share, TWD | Best-effort field; same rule as `paidInCapital` |
| `registeredAddress` | Registered address | `null` when no company was identified |
| `registeringAuthority` | Government body holding the registration | `null` when no company was identified |
| `board` | Directors/supervisors and shareholding | `[]` when `includeBoard` was `false`, when the company has no separately-listed board, or when no company was identified; personal data of living people, carried through unenriched |
| `source` | Always the same fixed identity | This Actor reads exactly one registry, by design |
| `sourceUrl` | The exact registry request this row came from | `null` only on `checksum_invalid` — the one outcome with no network request |
| `sourceTimestamp` | When the registry response was received | Same null rule as `sourceUrl` |
| `fieldProvenance` | Per-field origin (`registry`, `derived`, `unavailable`) | `{}` when no company was identified |
| `confidenceScore` | 100 for a UBN match, 90 for a name match | Set whenever a specific company was identified — including on `partial_source_coverage` and `duplicate_entity` rows — `null` on every outcome that never identified one |
| `gaps` | Names of promised fields this row could not populate | Always includes `legalNameEn` once a company is identified; includes `board` only for `board_fields_unmapped`/`board_partially_unmapped`, not for `board_unavailable`/`board_possibly_truncated` — a documented asymmetry, not a promise every incomplete-board reason is flagged here identically |
| `recommendedAction` | Human-readable next step | Populated for `resolved`, `checksum_invalid`, `ambiguous_match`, `rate_limited` and `duplicate_entity` only; `null` on `not_found`, `source_error` and every `partial_source_coverage` row in this build |
| `safeToAutomate` | Always `false` | This card is for human KYB review, never an automated counterparty decision |
| `partial` | Whether the row could not be completed in full | Covers an incomplete registry answer and a run that failed before/during the request; does not imply the registry was necessarily reached |
| `partialReason` | Which specific limit or gap caused `partial:true` | `null` unless `partial:true`; eight distinct values share `errorCode:"partial_source_coverage"` — see Decision routing |
| `verificationStatus` | The row's outcome | Only `resolved` is billable |
| `errorCode` | Bounded machine error code, one of seven values | `null` only on the billable row |
| `error` | Human-readable message | `null` only on the billable row |
| `retryable` | Whether retrying unchanged could differ | `true` only for `rate_limited`; depends on the failure for `source_error`; `false` otherwise |
| `observedAt` | When this row's outcome was produced | Shared by every row in one run |
| `found` | Whether this row is the billable class | `true` if and only if `verificationStatus` is `resolved` |

### Evidence and boundaries

**Why Taiwan, and not mainland China or Hong Kong.** Mainland China is closed by law, not engineering:
QCC, Tianyancha and OpenCorporates all forbid redistributing company data to a third party without a
separately signed commercial agreement, and the free alternative (GSXT) has no API and sits behind a
facial-recognition captcha. Hong Kong was checked as an alternative and found weaker on live
inspection: `data.gov.hk`'s free datasets carry no director or legal-representative fields at all —
only name, number, address and date, which is proof a company exists, not a KYB card — and the fields
that do include directors sit only behind the paid ICRIS registry, whose own commercial-redistribution
terms were not confirmed by a primary document read. Taiwan's MOEA GCIS platform publishes the same
class of fields — identity, capital, legal representative and board — for free, with no key and no
registration, under a licence whose own text was read directly and contains a clause permitting
sublicensing to third parties (`再轉授權他人為前項之利用`).

**Why this Actor treats an absent robots.txt as permission here, and only here.** This program's usual
rule — an unreadable or missing robots policy means no permission — exists for a different situation:
crawling a buyer-named site whose owner's intent is otherwise unknown. `data.gcis.nat.gov.tw`'s own
`robots.txt` answers HTTP 404, checked directly and stably three times. A 404 under the Robots
Exclusion Protocol means no policy was published, not that none is permitted, and this Actor treats
that absence as permission specifically and only because it is paired with the government's own
published open-data licence text granting commercial reuse and sublicensing — a stronger, more
specific statement of intent than a robots file would be. A `401`, `403`, `5xx` or unreadable response
is still treated as no permission, exactly like every other source in this program: this Actor's own
run refuses to start at all if that check ever fails, rather than degrading to per-company free rows.

**Why the board field names were the single biggest risk in this build, and what happened.** An
earlier, unreviewed version of this Actor's field mapping named the board's position, director-name
and shareholding fields by guessing a naming convention rather than reading them off a live response.
An independent review ran a real request against this exact TSMC record and found three of those four
guessed names wrong. The measured effect: nine of TSMC's ten real board seats silently disappeared
during mapping, and the one seat that survived did so only because its fourth, unrelated field
happened to be a correct guess — the paid card would have shipped with one board member instead of ten,
and nothing about the row's own shape would have signaled the loss. The field names are now the ones
confirmed against that live response (recorded in this Actor's source-proof file), and the mapping
logic no longer trusts field names to stay correct on their own: any board response where fewer rows
survive mapping than the registry actually returned makes the whole card free
(`partial_source_coverage`), whether that loss is total or partial, and a response that fills the
resource's own 200-row page size is flagged as possibly truncated rather than trusted as complete.

**That row-count defense turned out to have its own gap, found and closed in a later round.** A drift
in exactly one of the board's four source field names never drops a row — the row survives, only the
one field inside it goes empty, row counts still match, and the earlier defense above cannot see it.
Measured against 15 possible single-and-multi-field drift combinations on TSMC's real 10-row board, 11
of 15 billed a card with a silently empty field before this was closed. The fix reads two different
facts depending which field: for `position`/`name`/`shareholding`, a value that comes back empty on
every surviving seat at once is the signature of a renamed key, since a genuine per-seat gap never
hits every seat identically; for `representingEntity` specifically, that same signal is unusable — 9 of
TSMC's 10 real seats legitimately carry no juristic-person entity, so uniform emptiness there is the
healthy, common shape, not evidence of drift — and the question is instead put to the raw registry
response before any mapping happens, where a renamed key is simply absent from every record while a
genuinely empty field is present with an empty value. Together the two close all 15 measured drift
combinations, and a live-shaped clean board still bills. Both this defense and the row-count one before
it are structural guards against this exact class recurring, not only against the specific instances
that were found.

**Why duplicate protection has a real, disclosed boundary.** Two protections exist, at different
scopes. Within one run, submitting the identical `unifiedBusinessNumber` or normalized `legalNameZhTw`
twice is caught before any network call. Also within one run, the same real company submitted once by
number and once by name — which this Actor cannot know is the same company until the registry answers
both — is caught after resolution: the second identity to resolve to an already-billed 統一編號 is a
free `duplicate_entity`, not a second charge. Neither protection extends across separate runs: this
in-run identity map lives in process memory and is not written to the cross-run delivery journal, which
is keyed on the text you submitted, not the resolved company. The same real company submitted by
number in one run and by name in a different run is billed once in each. This is a named limitation of
this build, not a silent gap.

**Personal data is a separate legal question the open-data licence does not answer.** Board records
name living people and their shareholding. The government's open-data licence clears copyright and
database rights on the dataset; it says nothing about Taiwan's Personal Data Protection Act and its
application to a commercial, cross-border transmission of these specific fields. This Actor enriches
nothing beyond what the registry itself already publishes for public viewing, prints the source and
observation time on every row so a buyer can see it is a registry excerpt rather than a dossier, and
gives `includeBoard:false` as a way to never request these fields at all — but the legal question
itself is open, is not resolved by this page, and is recorded as a condition of publication rather than
assumed answered in either direction.

### Decision routing

| `verificationStatus` | Billable? | What it means | `retryable` |
|---|---|---|---|
| `resolved` | Yes | Exactly one company matched, with all obligatory fields populated | `false` |
| `checksum_invalid` | No | The submitted UBN fails Taiwan's official checksum; no registry request was made | `false` |
| `not_found` | No | The registry returned no matching company | `false` |
| `ambiguous_match` | No | A name search returned more than one candidate; this Actor never guesses which one you meant | `false` |
| `rate_limited` | No | The registry's own request limit was reached | `true` |
| `source_error` | No | An upstream timeout, malformed response or unexpected failure | depends on the specific failure |
| `partial_source_coverage` | No | A company was identified, but the card could not be completed — eight distinct `partialReason` values share this one code: `core_fields_incomplete`, `board_unavailable`, `board_fields_unmapped`, `board_partially_unmapped`, `board_possibly_truncated`, `budget_stopped_before_source_read`, `budget_stopped_after_source_read`, `company_processing_error` | `false` |
| `duplicate_entity` | No | This real company was already billed earlier in this same run, under a different submitted identity | `false` |

A workflow only needs a few rules: only continue on `found === true` **and** `partial === false`; never
assume `recommendedAction` is populated on a free row (`not_found`, `source_error` and every
`partial_source_coverage` row carry `null` there in this build); and read `confidenceScore` as "a
company was identified" rather than "billable" — it is set on `resolved`, on an identified
`partial_source_coverage` row, and on `duplicate_entity` alike.

### Commercial playbooks

#### Vendor and counterparty onboarding

A KYB or procurement team runs a new Taiwan counterparty's UBN through this Actor before onboarding,
routing a `resolved` card to a human reviewer and treating `not_found`/`ambiguous_match` as a reason to
ask the counterparty for their exact registered identity rather than guessing.

#### Board and ownership diligence

An investor or diligence team pulls the registered board composition for a target company, including
any seat held on behalf of a juristic-person shareholder — visible in `representingEntity` — before
relying on a self-reported cap table.

#### CRM/vendor-master data-hygiene sweep

A batch of existing Taiwan vendor or customer records, keyed by `inputRef` to your own system's ID, is
re-checked against the live registry; a `not_found` or a status change to `dissolved`/`revoked` for a
record currently marked active is a worklist for review, not an automatic deactivation.

### Integration recipes

#### Scheduled counterparty re-check pattern

A buyer-owned Apify Task re-submits a list of active Taiwan counterparties on a schedule, reading
`OUTPUT` for `billed` and `freeOutcomes` counts before routing individual `resolved` cards to a
compliance queue keyed by `inputRef`.

#### Agent/MCP pattern

An agent supplies only `unifiedBusinessNumber` or `legalNameZhTw`, reads `found`, `partial` and
`verificationStatus` before any next step, never treats a `partial_source_coverage` card as complete,
and always routes a `resolved` card to a human, honoring `safeToAutomate:false` as a hard stop.

#### Data-warehouse pattern

Append Dataset rows keyed by `entityId` when present, `inputRef` otherwise (a `checksum_invalid` row
has no `entityId`); preserve `null` as null rather than coercing to empty strings.

### Operating guide

**Choosing `unifiedBusinessNumber` versus `legalNameZhTw`.** A UBN match is exact and scores
`confidenceScore:100`; a name match can return more than one candidate (`ambiguous_match`) and scores
90 when it resolves to exactly one. Prefer the UBN whenever you have it.

**Reading `status` versus `caseStatus`.** `status` is a coarse, buyer-filterable bucket; `caseStatus`
is the registry's own raw Chinese text. Only the mapping for `核准設立 → active` is confirmed against a
live response — the other mappings (`dissolved`, `revoked`, `suspended`, `liquidating`) are standard
registry terminology mapped by well-known meaning, not each individually source-proof-verified. Any
unrecognized text maps to `unknown` rather than a guessed direction; read `caseStatus` directly when a
filtering decision matters.

**Understanding board truncation.** The board resource is requested at a 200-row page size. A response
that exactly fills that page cannot be told apart from one silently truncated at the same size, so it
is flagged `board_possibly_truncated` and the card is not billed as complete — this has not yet been
observed live for any company this build has checked (TSMC's real board is 10 rows), but the flag
exists precisely because a company this large could exist.

**Understanding cross-run duplicate exposure.** The in-run duplicate-entity protection does not persist
across runs. If your own workflow might submit the same company by number in one run and by name in a
later run, deduplicate on your own side first, or accept that the second run's card is billed again.

### FAQ

#### Does this Actor cover mainland China or Hong Kong companies?

No. It reads exactly one source: Taiwan's MOEA GCIS registry. See Evidence and boundaries for why
mainland China and Hong Kong were both evaluated and rejected as sources for this specific Actor.

#### Is the English company name available?

No. Neither GCIS resource this Actor reads publishes an English name for any company. `legalNameEn` is
always `null` and always named in `gaps` when a company is identified — never a transliteration
presented as a registry field.

#### Can I trust every `status` value the same way?

Only `active` (mapped from `核准設立`) is confirmed against a live registry response. The other status
mappings are standard terminology, not individually verified — see Operating guide for how to read
`caseStatus` directly when it matters.

#### What happens if the board response looks suspiciously complete?

A response that exactly fills the 200-row page size is flagged `board_possibly_truncated` and the card
is free rather than billed as if the board were confirmed complete.

#### Does submitting the same company by number in two different runs save me money?

No. The protection against paying twice for the same real company only holds within a single run; see
Evidence and boundaries for the exact boundary and why it is not extended further in this build.

#### Is board data safe to use for automated screening?

`safeToAutomate` is fixed `false` on every row. This card is a registry excerpt for a human KYB
reviewer, never an automated approve/reject signal, and the personal-data question in Evidence and
boundaries is explicitly unresolved.

#### How reviewed is this build?

Three independent review rounds ran against this code before release. The first two rejected it and
named real findings — the most serious a silent board-data loss that would have shipped a paid card
with nine of ten real directors missing — and every finding was closed by fixing the underlying rule,
not only the cited example. The third round accepted the build; its own three residual findings were
closed and verified with the full test suite passing twice before this listing went live.

### 繁體中文

本工具讀取台灣官方公司登記資料 —— 經濟部商業發展署商工行政資料開放平臺
(`data.gcis.nat.gov.tw`) —— 不涉及中國大陸或香港的公司登記資料。輸入統一編號(8碼)或公司中文全名,
取得該公司在官方登記資料中的完整卡片:狀態、設立日期、負責人、資本額、實收資本額、地址、登記機關,
以及(可選)董監事名單與持股。

**唯一收費結果:單一、明確比對成功的公司卡片,所有必要欄位皆已填寫。** 統一編號未通過檢查碼驗證、
查無公司、名稱查詢比對到多筆候選、董監事資料不完整或可能被截斷、來源錯誤或達到查詢限制、同一公司
在同一次執行中已收費 —— 以上皆為免費結果,不收取任何費用。

**個人資料提醒:** 董監事資料包含真實姓名與持股數,是政府登記機關公開資料的原文轉載,本工具不做任何
額外比對或補充。是否符合《個人資料保護法》對跨境商業傳輸的要求,是尚待法律意見確認的問題,**本頁面
不代表已有定論**。如僅需公司卡片、不需董監事資料,可將 `includeBoard` 設為 `false`。

本頁描述的是尚未經過獨立驗收、尚未實際執行過真實 Apify 平台試跑的合約草案,所有範例中的公司卡片
形狀均為草稿說明,唯 TSMC(統一編號 22099131)的欄位數值為 2026年8月12日直接讀取官方 API 所得的真實
資料。

### Sources and rights

**The only source.** 經濟部商業發展署商工行政資料開放平臺, host `data.gcis.nat.gov.tw`, two OData
resources: company records (`5F64D864-61CB-4D0D-8AD9-492047CC1EA6`) and board/shareholding records
(`4E5F7653-1B91-4DDC-99D5-468530FAE396`). Both were read directly on 2026-08-12 for TSMC's real record
(統一編號 22099131): HTTP 200, real fields, real board composition. No authentication, no account, no
key at any point.

**The licence.** 政府資料開放授權條款-第1版 (Government Open Data License, version 1), read directly
at `data.gov.tw/license` (HTTP 200, 484,109 bytes): permits commercial use and contains an explicit
sublicensing clause (`再轉授權他人為前項之利用`). This was checked against the primary document, not
assumed by analogy to another jurisdiction's open-data terms.

**robots.txt.** `data.gcis.nat.gov.tw/robots.txt` returns HTTP 404, checked three times with stable
results. See Evidence and boundaries for why this Actor treats that absence, paired with the licence
above, as permission — a deliberate, named departure from this program's default posture, not a silent
exception.

**Personal data.** Board records name living people. The licence above clears copyright and database
rights; it does not resolve Taiwan's Personal Data Protection Act as applied to commercial, cross-border
transmission of these fields. This is recorded as an open legal question, not answered by this page in
either direction — see Evidence and boundaries.

### Limits

- One to one hundred companies per run; `maxConcurrency` 1–5, source work sequential on a monetized run.
- Exactly one source: Taiwan's MOEA GCIS registry. No mainland China or Hong Kong coverage of any kind.
- No English company name — the field does not exist at the source and is never approximated.
- Only `核准設立 → active` is individually confirmed against a live response; other status mappings are
  well-known terminology, not each source-proof-verified.
- Board data may be flagged possibly-truncated at exactly 200 raw rows; a card in that state is free,
  never billed as complete.
- Cross-run duplicate protection for the same real company submitted under two different input
  identities does not exist; only within-run protection does.
- `safeToAutomate` is fixed `false` for every row this schema allows; this is a human-review artifact.
- The personal-data legal question for board data is open and unresolved by this page.

### Support boundary

Actor support covers deterministic input validation, the source-access and mapping behavior described
on this page, the Dataset/Output/key-value-store schemas, and delivery/replay evidence for an accepted
release. It cannot decide whether a specific counterparty decision is appropriate for your business or
jurisdiction, cannot restore access if the registry changes its own API or licence terms, cannot
guarantee a company's registry record stays unchanged after observation time, and cannot provide legal
advice on KYB obligations, Taiwan's Personal Data Protection Act, or any other data-protection law.
When reporting a problem, include the Actor build/run ID, the redacted `entityId`, `verificationStatus`,
`errorCode` and approximate `observedAt` time.

# Actor input Schema

## `companies` (type: `array`):

One to 100 companies. Give either unifiedBusinessNumber or legalNameZhTw for each entry, never both.

## `includeBoard` (type: `boolean`):

Whether to also fetch the company's board of directors/supervisors and shareholding from the registry. This is personal-data-bearing: names and shareholding of living people. Turn off to request only the company card. Default: true.

## `maxConcurrency` (type: `integer`):

Companies processed concurrently only in local non-monetized runs. On-platform source work and paid delivery are sequential regardless of this value, and every request to the registry is paced conservatively either way.

## Actor input object example

```json
{
  "companies": [
    {
      "unifiedBusinessNumber": "22099131"
    }
  ],
  "includeBoard": true,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `results` (type: `string`):

API URL for uniform kyb\_company\_card rows in the default dataset.

## `summary` (type: `string`):

Validated OUTPUT record with submitted, resolved, billed, free-by-category, partial and early-stop counts.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        {
            "unifiedBusinessNumber": "22099131"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/taiwan-company-kyb-lookup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "companies": [{ "unifiedBusinessNumber": "22099131" }] }

# Run the Actor and wait for it to finish
run = client.actor("zinin/taiwan-company-kyb-lookup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    {
      "unifiedBusinessNumber": "22099131"
    }
  ]
}' |
apify call zinin/taiwan-company-kyb-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zinin/taiwan-company-kyb-lookup"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/38t4tjPQ1H9UdInvK/builds/MaqgdaxM3DQziy93s/openapi.json
