Entities
Read portal data with getEntity, searchEntities, and the underlying portal client.
Once you've connected, you can read epilot entities through
the portal's authentication. The SDK wraps @epilot/customer-portal-client and
configures auth from the current session for you, so you never handle tokens
directly.
All of these require a resolved session; they throw
SparkNotInitializedError otherwise.
getEntity(params)
Fetch a single entity for the portal user. Resolves to an EntityItem or
undefined if not found.
import { getEntity } from '@epilot/spark-sdk'
const contract = await getEntity({
slug: 'contract',
entity_id: '5da0a718-c822-403d-9f5d-20d4584e0528',
hydrate: true,
fields: ['_id', '_title', 'customer', 'products'],
})
console.log(contract?._title)Pass fields to fetch only what you render; it keeps payloads small and reads
fast. From a HEMS's use-asset-query.ts, wrapped in TanStack Query:
import { getEntity, type EntityItem } from '@epilot/spark-sdk'
import { useQuery } from '@tanstack/react-query'
const ASSET_FIELDS = ['_id', '_title', 'title', 'asset_number']
export function useAssetQuery(assetId: string | undefined) {
const { isMockedMode } = useBlockContext()
return useQuery<EntityItem | null>({
queryKey: assetKeys.detail(assetId ?? ''),
queryFn: async () => {
if (!assetId) return null
const entity = await getEntity({
slug: 'asset',
entity_id: assetId,
fields: ASSET_FIELDS,
})
return entity ?? null
},
enabled: Boolean(assetId) && !isMockedMode,
staleTime: 60_000,
})
}searchEntities(params)
Search entities for the portal user. Resolves to an EntityResponseWithHits
(results, hits, pagination).
import { searchEntities } from '@epilot/spark-sdk'
const { results, hits } = await searchEntities({
slug: 'contract',
q: 'active',
size: 10,
sort: '_created_at:desc',
})
console.log(`Found ${hits} contracts`)
results?.forEach((c) => console.log(c._title))You can pass structured filters instead of (or with) a q string. This is how
a HEMS batch-loads assets by id in use-assets-by-ids-query.ts, then
back-fills the per-entity cache so detail views are instant:
import { searchEntities, type EntityItem } from '@epilot/spark-sdk'
const response = await searchEntities({
slug: 'asset',
size: ids.length,
fields: ASSET_FIELDS,
filters: [{ terms: { _id: ids } }],
})
const byId = new Map<string, EntityItem>()
for (const asset of response.results ?? []) {
if (asset._id) {
byId.set(asset._id, asset)
queryClient.setQueryData(assetKeys.detail(asset._id), asset) // warm the cache
}
}getPortalClient()
Both helpers above are thin wrappers over the customer portal client. When you need an operation the SDK doesn't wrap, reach for the configured client directly; auth and base URL are set from the current session on every call.
import { initialize, getPortalClient } from '@epilot/spark-sdk'
await initialize()
const client = await getPortalClient()
const files = await client.getAllFiles({ origin: 'END_CUSTOMER_PORTAL' })See the @epilot/customer-portal-client
docs for the full operation surface.
Types
These come from @epilot/customer-portal-client and are re-exported by the SDK so
you can import them from one place:
| Type | Used for |
|---|---|
EntityItem | A single entity (_id, _title, your attributes…). |
EntityGetParams | Params for getEntity. |
EntitySearchParams | Params for searchEntities. |
EntityResponse | Raw entity response. |
EntityResponseWithHits | Search response: results, hits, pagination. |
EntitySlug | Known entity slugs. |
import type { EntityItem, EntitySearchParams } from '@epilot/spark-sdk'Entities vs. use cases. Use the entity API to read epilot's own data model. To call an external system wired up through Integration Hub (devices, energy data, vendor APIs…), use
executeUseCaseinstead.