# Find an Indigenous corporation by name, then read it by ICN

What you build: a server-side flow for a grants or procurement system. A clerk types part of a corporation's name; your server lists the matches from the ORIC register with their ICNs; the clerk picks one; your server reads that corporation's record by its ICN. An empty search is a real answer; an outage is not.

## Before you start: a development app, then a production app

1. `npx comms-id init` makes a development key in `.env.local` and prints its public key. In the Companion App, register it as a development app, enable **ORIC** for it, and put the app id in `.env.local` as `COMMS_ID_CLIENT_ID`. This key reaches only the TEST service (`https://api-test.comms.id`): the same API, errors and authentication as LIVE, with synthetic replies.
2. When it works in TEST, `npx comms-id key --worker <your worker>` makes the production key straight into your server's `COMMS_ID_PRIVATE_JWK` secret and prints the public key; register it as a production app with ORIC enabled. Going live changes only the environment and the key: nothing in the code below.

A `.env.local` never holds a production key, and a browser never holds any key.

## The code

`pnpm add @comms-id/oric`

`find-corporation.ts`:

```ts
// Find an Indigenous corporation by name, then read one record by its ICN, on your server.
import { type OricClient, outcomeOf } from "@comms-id/oric";

export interface Corporation {
  readonly icn: string;
  readonly name: string;
  readonly status: string;
}

/** The corporations whose names contain `term`; an empty list is a real answer, an outage is not. */
export const findByName = async (term: string, oric: OricClient): Promise<readonly Corporation[]> => {
  const found = await oric.search({ term });
  if (found.status === "unavailable") {
    throw new Error("The ORIC register did not answer; try again later.");
  }
  if (found.status !== "found" || !("data" in found)) {
    return [];
  }
  return found.data.map((row) => ({ icn: row.icn, name: row.name, status: row.statusReason ?? "unknown" }));
};

/** One corporation's register record, or undefined when the ICN is not on the register. */
export const readByIcn = async (icn: string, oric: OricClient) => {
  try {
    const reply = await oric.lookup({ kind: "icn", value: icn });
    if (reply.status === "unavailable") {
      throw new Error("The ORIC register did not answer; try again later.");
    }
    const snapshot = reply.snapshot;
    return snapshot !== undefined && snapshot.status === "found" ? snapshot.data : undefined;
  } catch (error) {
    if (outcomeOf(error) === "source-unavailable") {
      throw new Error("The ORIC register did not answer; try again later.");
    }
    throw error;
  }
};
```

`search` answers from the published ORIC dataset; `lookup` by ICN answers `status: "complete"` with the register record (and, when the portal answered too, its details). `unavailable` is a status of its own, so the function throws rather than return an empty record.

## TEST first

```ts
import { createOricClient } from "@comms-id/oric/server";
import { findByName, readByIcn } from "./find-corporation";

const oric = createOricClient({
  clientId: process.env.COMMS_ID_CLIENT_ID!,
  privateJwk: JSON.parse(process.env.COMMS_ID_PRIVATE_JWK!),
  environment: "test",
});

const matches = await findByName("Urapuntja", oric); // the published example term: one fictional match
const record = await readByIcn(matches[0]!.icn, oric); // its ICN (4172 in TEST)
await findByName("nomatch anything", oric); // []
await readByIcn("503", oric); // throws: the register did not answer
```

## LIVE

Remove `environment: "test"` and use the production key. Reference: [ORIC API](/docs/reference/oric). The attribution in each reply (`Source: ... ORIC, via data.gov.au`) must be shown wherever the data is.
