# `pages` API

Helpers for creating, reading, updating, and archiving Notion pages from inside a custom block. The SDK forwards each call to Notion on your behalf.

```ts
import { pages } from "ncblock";
```

Every helper returns a discriminated result instead of throwing:

```ts
const result = await pages.get(pageId);
if (result.status === "success") {
  // result.page is a NotionPage
} else {
  // result.error is a human-readable string
}
```

Always check `result.status` before reading `result.page`.

## Creating pages

`pages.create` mirrors Notion's [`POST /v1/pages`](https://developers.notion.com/reference/post-page). Pass a parent, a property map, and (optionally) an `icon`, `cover`, or `position`:

```ts
const result = await pages.create({
  parent: { type: "data_source_key", key: "tasks" },
  properties: {
    title: {
      type: "title",
      title: [{ type: "text", text: { content: "New task" } }],
    },
    dueDate: { type: "date", date: { start: "2026-06-01" } },
  },
  icon: { type: "emoji", emoji: "📝" },
  position: { type: "end" },
});

if (result.status === "success") {
  console.log("created", result.page.id);
}
```

### Choosing a parent

`parent` is a `CreatePageParent`:

```ts
type CreatePageParent =
  | { type: "page_id"; page_id: NotionPageId }
  | { type: "data_source_id"; data_source_id: NotionDataSourceId }
  | { type: "data_source_key"; key: string };
```

`type: "data_source_key"` is the recommended form inside a custom view. Pass the semantic key you declared in `custom_blocks.json` (e.g. `"tasks"`) and the SDK looks up the corresponding data source for you. The other two variants exist for the rarer case where you already have a raw Notion ID in hand.

### Property keys

`properties` is a `NotionPagePropertyInputMap`. Two niceties versus the raw API when the create parent resolves to a configured data source:

- **Keys** can be either raw Notion property IDs _or_ the data-source property keys you declared in the manifest. The SDK resolves keys → IDs before forwarding the request. Semantic keys work for `parent.type: "data_source_key"` and for `parent.type: "data_source_id"` when that ID matches a data source delivered by `init` / `dataSourcesChanged`; use raw property IDs for `page_id` parents or unmapped data sources.
- **Values** (`NotionPagePropertyInputValue`) may omit `id` — the SDK fills in the final raw ID for you.

So if your manifest declares `title` and `dueDate`, you can write them by name (as in the example above) instead of looking up the raw IDs.

### Where the new page lands

`position` is a `NotionCreatePagePosition` and controls placement inside the parent:

- `{ type: "start" }` / `{ type: "end" }` — prepend or append (default).
- `{ type: "before", blockId }` / `{ type: "after", blockId }` — insert as a sibling of the given block (which can be nested anywhere under the parent).

## Reading pages

`pages.get(pageId)` fetches a single page by ID:

```ts
const result = await pages.get(pageId);
if (result.status === "error") return;

const page = result.page; // NotionPage
console.log(page.properties);
```

`page` mirrors Notion's public API shape, with `id`, `parent`, `properties`, optional `icon` / `cover`, etc. — see `NotionPage` in the types list below.

## Updating pages

`pages.update` writes back to a page. The optional fields (`properties`, `icon`, `cover`, `archived`) are independent — supply only what you want to change:

```ts
const result = await pages.update({
  pageId,
  properties: {
    "%5C%3FX%3D": {
      id: "%5C%3FX%3D",
      type: "checkbox",
      checkbox: true,
    },
  },
  icon: { type: "emoji", emoji: "✅" },
});
```

The `properties` map (a `NotionPagePropertyWriteMap`) is keyed by **raw Notion property ID**, and each value must repeat that ID as its own `id` field — semantic data-source keys aren't accepted here. To update a row by configured custom-block key without writing out the raw IDs, use the `update` helper on the row returned from `useDataSource` instead; the SDK handles the key → ID resolution for you.

If you call `pages.update` with no fields to change, it short-circuits and resolves with `{ status: "error", error: { code: "invalid_page_update", message: "updatePage requires at least one of: properties, icon, cover, archived.", isRetryable: false } }` — no request is sent.

## Deleting (archiving) pages

`pages.delete(pageId)` is a thin wrapper around `pages.update({ pageId, archived: true })`. Notion treats archive and trash the same way for pages:

```ts
await pages.delete(pageId);
```

To restore a page, call `pages.update({ pageId, archived: false })`.

## Icons, covers, and file uploads

File-upload references aren't enabled for custom blocks yet. For icons, covers, and file properties, use one of:

- An emoji icon — `{ type: "emoji", emoji: "🟢" }`
- An external URL — `{ type: "external", external: { url: "https://example.com/cover.png" } }`
- An existing hosted file URL returned by Notion — `{ type: "file", file: { url: existingUrl } }`

Do **not** send `{ type: "file_upload", file_upload: { id } }`; the host will reject it.

## Types

- `NotionPage` — the page record returned by every successful call.
- `NotionPageId` — branded string ID for a page.
- `NotionPageIcon` / `NotionPageCover` — icon and cover variants Notion supports.
- `NotionParent` — a block's parent reference (`page_id` / `block_id` / `data_source_id` / `workspace`), as returned on `NotionPage.parent` and by `useParent()`.
- `NotionPagePropertyValue` — a single property value as returned on a `NotionPage`.
- `NotionPagePropertyInputValue` — a single property value as accepted by `pages.create` / `pages.update` (may omit `id` for `create`).
- `NotionPagePropertyInputMap` — input map for `pages.create` (keys can be raw property IDs, or semantic keys when creating into a mapped data source).
- `NotionPagePropertyWriteMap` — input map for `pages.update` (raw property IDs only).
- `NotionCreatePagePosition` — `start` / `end` / `before` / `after` insertion variants.
- `CreatePageInput` / `CreatePageParent` / `CreatePageResult`.
- `GetPageResult`.
- `UpdatePageInput` / `UpdatePageResult`.
