> For the complete documentation index, see [llms.txt](https://emeditweb.gitbook.io/pulsar-stellar-sdk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://emeditweb.gitbook.io/pulsar-stellar-sdk/sdk-reference/schemas-and-types.md).

# Schemas and types

The SDK's Zod schemas are the source of truth; the TypeScript types are inferred from them, so the two cannot drift. Nothing here trusts its input: data from the indexer, from RPC, or from a caller is parsed before use.

Two postures are used on purpose. Caller input is strict, so a misspelled query key is a reported mistake, not a silently ignored field. Server responses are lenient, so an indexer that adds a field does not break an SDK built before it existed.

## Contract and event identifiers

### `ContractIdSchema`

```ts
const ContractIdSchema: z.ZodString // /^C[A-Z2-7]{55}$/
```

A Soroban contract ID: `C` followed by 55 base32 characters, 56 in total. This checks the shape, not existence or checksum. It rejects the common mistakes, a truncated paste or an account ID starting with `G`, before a network call.

### `EventIdSchema`

```ts
const EventIdSchema: z.ZodString // /^\d+$/
```

An event id as the SDK accepts it: a string of digits. The indexer's `events` table uses `BIGSERIAL`, whose range exceeds what a JSON number holds exactly, so the id is a string and is never parsed into a number. Validated as digits so an obviously wrong value, a tx hash or an empty string, is caught before a request.

### `PulsarNetworkSchema` and `PulsarNetwork`

```ts
const PulsarNetworkSchema = z.enum(['testnet', 'futurenet', 'mainnet', 'local']);
type PulsarNetwork = 'testnet' | 'futurenet' | 'mainnet' | 'local';
```

The networks the toolkit can address.

## Contracts

### `ContractStatusSchema` and `ContractStatus`

```ts
const ContractStatusSchema = z.enum(['active', 'paused', 'error']);
type ContractStatus = 'active' | 'paused' | 'error';
```

Whether the indexer is currently following a contract.

### `ContractInfoSchema` and `ContractInfo`

```ts
interface ContractInfo {
  contractId: string;
  addedAt: string;                       // ISO 8601
  firstIndexedLedger: number | null;     // null until the first poll completes
  lastIndexedLedger: number;
  status: ContractStatus;
}
```

What the indexer knows about a contract it tracks. `firstIndexedLedger` is `null` until the first poll completes, so a contract registered a moment ago reports `null` rather than a misleading zero. Returned by [`registerContract`](/pulsar-stellar-sdk/sdk-reference/client.md#clientregistercontractcontractid), [`getContract`](/pulsar-stellar-sdk/sdk-reference/client.md#clientgetcontractcontractid), and [`listContracts`](/pulsar-stellar-sdk/sdk-reference/client.md#clientlistcontracts).

## Events

### `DecodedEventSchema` and `DecodedEvent`

```ts
interface DecodedEvent {
  id: string;                        // opaque; indexer key, or "rpc:<id>" on the RPC path
  contractId: string;
  ledger: number;
  txHash: string;
  eventIndex: number;                // ordinal within the ledger, not the transaction
  name: string;                      // '' when the first topic is not a Symbol
  topics: DecodedValue[];
  data: DecodedValue;
  rawTopics: string[];               // base64 XDR, one per topic
  rawData: string;                   // base64 XDR
  emittedAt: string;                 // ISO 8601 ledger close time
  inSuccessfulContractCall: boolean; // false is possible; reverted calls still emit
}
```

One contract event, carrying both the decoded form a caller reads and the raw XDR it came from, so anyone can check the decoding. This is the single type both read paths produce. Two fields have their own concept pages: [`eventIndex`](/pulsar-stellar-sdk/concepts/two-paths.md#eventindex-is-a-ledger-ordinal) and [`inSuccessfulContractCall`](/pulsar-stellar-sdk/concepts/successful-contract-call.md).

### `EventQuerySchema`, `EventQuery`, and `ResolvedEventQuery`

```ts
type EventQuery = {
  name?: string;          // exact event name, such as 'transfer'
  fromLedger?: number;
  toLedger?: number;
  topicContains?: string; // substring match against decoded topic values
  limit?: number;         // 1..500, defaults to 50
  cursor?: string;        // opaque, from a previous response
  order?: 'asc' | 'desc'; // defaults to 'desc'
};
```

Filters for [`client.events`](/pulsar-stellar-sdk/sdk-reference/client.md#clienteventscontractid-query). **Strict**: an unrecognized key is a `PulsarValidationError`, because a typo in a filter would otherwise return a confidently wrong result set. `EventQuery` is the input type, with `limit` and `order` optional; `ResolvedEventQuery` is the same after parsing, with both defaults filled in.

### `EventsPage`

```ts
interface EventsPage {
  readonly items: DecodedEvent[];
  readonly nextCursor: string | null;
}
```

One page from [`client.events`](/pulsar-stellar-sdk/sdk-reference/client.md#clienteventscontractid-query). `nextCursor` is `null` on the last page; a `null` and an absent wire field both arrive as `null`, so you page until you see `null` and never check two falsy values. Contrast [`LiveEventsPage`](/pulsar-stellar-sdk/sdk-reference/rpc.md#liveeventspage), whose cursor is never `null`.

## Configuration

### `PulsarConfigSchema`, `PulsarConfig`, and `ResolvedPulsarConfig`

```ts
type PulsarConfig = {
  indexerUrl: string;              // required, http or https
  rpcUrl?: string;                 // http or https; only the RPC path uses it
  network?: PulsarNetwork;
  fetchImpl?: typeof fetch;        // for runtimes without a global fetch, or tests
  timeoutMs?: number;              // defaults to DEFAULT_TIMEOUT_MS (15000)
};
```

The constructor input for [`PulsarClient`](/pulsar-stellar-sdk/sdk-reference/client.md#new-pulsarclientconfig). **Strict**, and validated as parsing rather than mere type-checking, so a JavaScript caller and a caller passing environment values get the same guarantees. `indexerUrl` is required even when only the RPC path is used. `ResolvedPulsarConfig` is the parsed form with defaults filled in, and is what [`client.config`](/pulsar-stellar-sdk/sdk-reference/client.md#clientconfig), [`fetchLiveEvents`](/pulsar-stellar-sdk/sdk-reference/rpc.md#fetchliveeventsconfig-query), and [`liveEventStream`](/pulsar-stellar-sdk/sdk-reference/rpc.md#liveeventstreamconfig-query-options) work with.

The schemes are constrained to `http` and `https`. Bare `z.url()` accepts more than it looks: `localhost:8080` parses as a URL whose protocol is `localhost:`, and `ftp://` and `javascript:` parse cleanly too.

## Health

### `PingResult`

```ts
interface PingResult {
  readonly ok: boolean;                  // the indexer's self-report
  readonly version: string;
  readonly latestLedger: number | null;  // null if it has processed none yet
  readonly trackedContracts: number | null;
  readonly latencyMs: number;             // round trip, measured by the SDK
  readonly serverTookMs: number | null;   // the indexer's own timing, if reported
}
```

What [`client.ping`](/pulsar-stellar-sdk/sdk-reference/client.md#clientping) returns. `ok: false` is a successful call with bad news, not a throw. `latencyMs` is the SDK's round-trip measurement, reported separately from the indexer's own `serverTookMs`, because the difference between the two is the network.

## Decoded values

### `DecodedValue` and `DecodedMapEntry`

```ts
type DecodedValue =
  | { type: 'address' | 'symbol' | 'string'; value: string }
  | { type: 'bool'; value: boolean }
  | { type: 'bytes'; value: string }                 // lowercase hex
  | { type: 'u32' | 'i32'; value: number }
  | { type: 'u64' | 'i64' | 'u128' | 'i128'
        | 'u256' | 'i256' | 'timepoint' | 'duration'; value: string }
  | { type: 'vec' | 'tuple'; value: DecodedValue[] }
  | { type: 'map'; value: DecodedMapEntry[] }
  | { type: 'void' }
  | { type: 'unknown'; xdr: string };                // base64

interface DecodedMapEntry { readonly key: DecodedValue; readonly value: DecodedValue; }
```

The discriminated union every decoded contract value takes, per ADR-023. The [Decoded values](/pulsar-stellar-sdk/concepts/decoded-values.md) concept page explains each choice; the [`DecodedValueSchema`](/pulsar-stellar-sdk/sdk-reference/decoding.md#decodedvalueschema) and [`DecodedMapEntrySchema`](/pulsar-stellar-sdk/sdk-reference/decoding.md#decodedmapentryschema) validators are on the Decoding page. `tuple` is reachable only on the indexer path; the RPC path emits `vec`.

## Constants

```ts
const DEFAULT_TIMEOUT_MS = 15000;        // default request timeout
const EVENT_QUERY_MAX_LIMIT = 500;       // largest page the indexer returns
const EVENT_QUERY_DEFAULT_LIMIT = 50;    // page size when a query omits limit
```

Two more constants live with the modules they belong to: [`DEFAULT_CALL_TIMEOUT_SECONDS`](/pulsar-stellar-sdk/sdk-reference/contracts.md#default_call_timeout_seconds) (`30`) and [`DEFAULT_POLL_INTERVAL_MS`](/pulsar-stellar-sdk/sdk-reference/rpc.md#default_poll_interval_ms) (`2000`).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://emeditweb.gitbook.io/pulsar-stellar-sdk/sdk-reference/schemas-and-types.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
