Skip to content

epilot-dev/sdk-js

Repository files navigation

epilot
epilot SDK

CI npm version License

JavaScript/TypeScript SDK for epilot APIs. Full types, tree-shakeable imports, and lazy-loaded OpenAPI specs.

Install

npm i @epilot/sdk axios openapi-client-axios

Quick Start

import { epilot } from '@epilot/sdk'

epilot.authorize(() => '<my-bearer-token>')

const { data: entity } = await epilot.entity.createEntity(
  { slug: 'contact' },
  { first_name: 'John', last_name: 'Doe' },
)

const { data: file } = await epilot.file.getFile({ id: 'file-123' })

const { data: executions } = await epilot.workflow.getExecutions()

API clients are built on openapi-client-axios, which generates fully typed operation methods on top of regular axios instances. All standard axios features (interceptors, defaults, config) work as expected. Each operation is forwarded to a lazy singleton — the spec is loaded and the client initialized on first use, then cached.

Full API documentation: https://docs.epilot.io/api

Packages

Package Description
@epilot/sdk JavaScript/TypeScript SDK for epilot APIs
@epilot/app-sdk SDK to build Apps for epilot XRM
@epilot/app-bridge App bridge for communication between epilot apps and the host

API Reference

API Import Docs
epilot.accessToken @epilot/sdk/access-token docs
epilot.address @epilot/sdk/address docs
epilot.addressSuggestions @epilot/sdk/address-suggestions docs
epilot.aiAgents @epilot/sdk/ai-agents docs
epilot.app @epilot/sdk/app docs
epilot.auditLogs @epilot/sdk/audit-logs docs
epilot.automation @epilot/sdk/automation docs
epilot.billing @epilot/sdk/billing docs
epilot.blueprintManifest @epilot/sdk/blueprint-manifest docs
epilot.consent @epilot/sdk/consent docs
epilot.customerPortal @epilot/sdk/customer-portal docs
epilot.dashboard @epilot/sdk/dashboard docs
epilot.dataManagement @epilot/sdk/data-management docs
epilot.deduplication @epilot/sdk/deduplication docs
epilot.design @epilot/sdk/design docs
epilot.document @epilot/sdk/document docs
epilot.emailSettings @epilot/sdk/email-settings docs
epilot.emailTemplate @epilot/sdk/email-template docs
epilot.entity @epilot/sdk/entity docs
epilot.entityMapping @epilot/sdk/entity-mapping docs
epilot.environments @epilot/sdk/environments docs
epilot.erpIntegration @epilot/sdk/erp-integration docs
epilot.eventCatalog @epilot/sdk/event-catalog docs
epilot.file @epilot/sdk/file docs
epilot.iban @epilot/sdk/iban docs
epilot.journey @epilot/sdk/journey docs
epilot.kanban @epilot/sdk/kanban docs
epilot.message @epilot/sdk/message docs
epilot.metering @epilot/sdk/metering docs
epilot.notes @epilot/sdk/notes docs
epilot.notification @epilot/sdk/notification docs
epilot.organization @epilot/sdk/organization docs
epilot.partnerDirectory @epilot/sdk/partner-directory docs
epilot.permissions @epilot/sdk/permissions docs
epilot.pricing @epilot/sdk/pricing docs
epilot.pricingTier @epilot/sdk/pricing-tier docs
epilot.purpose @epilot/sdk/purpose docs
epilot.sandbox @epilot/sdk/sandbox docs
epilot.submission @epilot/sdk/submission docs
epilot.targeting @epilot/sdk/targeting docs
epilot.templateVariables @epilot/sdk/template-variables docs
epilot.user @epilot/sdk/user docs
epilot.validationRules @epilot/sdk/validation-rules docs
epilot.webhooks @epilot/sdk/webhooks docs
epilot.workflow @epilot/sdk/workflow docs
epilot.workflowDefinition @epilot/sdk/workflow-definition docs

Codebase Structure

sdk-js/
├── clients/                    # 46 API client packages (source specs + types)
├── packages/
│   ├── epilot-sdk-v2/          # @epilot/sdk
│   ├── app-sdk/                # @epilot/app-sdk
│   └── app-bridge/             # @epilot/app-bridge
└── scripts/                    # code generation scripts

Explicit Client Access

import { epilot } from '@epilot/sdk'

epilot.authorize(() => '<my-token>')

// Get the cached singleton client
const entityClient = epilot.entity.getClient()
const { data } = await entityClient.getEntity({ slug: 'contact', id: '123' })

// Create a fresh (non-singleton) client instance
const freshClient = epilot.entity.createClient()
authorize(freshClient, () => '<my-token>')

Tree-Shakeable Imports

Import only what you need. Other APIs never touch your bundle.

import { getClient, authorize } from '@epilot/sdk/entity'

const entityClient = getClient()
authorize(entityClient, () => '<my-token>')

const { data } = await entityClient.getEntity({ slug: 'contact', id: '123' })

// Or use the handle for direct operation forwarding
import { entity } from '@epilot/sdk/entity'
const { data } = await entity.getEntity({ slug: 'contact', id: '123' })

Types

Each API subpath re-exports all schema types generated from the OpenAPI spec. Import them directly:

import type { Entity, EntitySchema, RelationAttribute } from '@epilot/sdk/entity'
import type { FileItem } from '@epilot/sdk/file'
import type { AutomationFlow } from '@epilot/sdk/automation'

The Client, OperationMethods, and PathsDictionary types are also available for typing client instances:

import type { Client } from '@epilot/sdk/entity'

const entityClient: Client = epilot.entity.getClient()

Headers

Global Headers

Set default headers applied to all clients. Useful for x-epilot-org-id, x-epilot-user-id, etc.

import { epilot } from '@epilot/sdk'

epilot.authorize(() => '<my-token>')
epilot.headers({
  'x-epilot-org-id': 'org-123',
  'x-epilot-user-id': 'user-456',
})

const { data } = await epilot.entity.searchEntities(...)

Standard Axios Headers

Use standard axios defaults.headers.common on individual clients:

const entityClient = epilot.entity.getClient()
entityClient.defaults.headers.common['x-epilot-org-id'] = 'org-123'

Auth Patterns

authorize() accepts a string or a function. The function form is preferred — it is called on every request, so tokens stay fresh.

import { authorize } from '@epilot/sdk'
import { getClient } from '@epilot/sdk/entity'

// Per-client — function predicate (recommended)
const entityClient = getClient()
authorize(entityClient, () => '<my-token>')

// Per-client — async function (e.g. OAuth / session)
authorize(entityClient, async () => {
  return await getTokenFromSession()
})

// Per-client — static string (sets default header once)
authorize(entityClient, 'my-static-api-token')
// Global — applies to all clients resolved from the SDK
import { epilot } from '@epilot/sdk'

epilot.authorize(() => '<my-token>')
epilot.authorize(async () => await getTokenFromSession())
epilot.authorize('my-static-api-token')

Fresh Client Instance

import { createClient, authorize } from '@epilot/sdk/entity'

const entityClient = createClient()
authorize(entityClient, () => '<my-token>')
entityClient.defaults.headers.common['x-epilot-org-id'] = 'org-123'

Multiple SDK Instances

import { createSDK } from '@epilot/sdk'

const sdk1 = createSDK()
sdk1.authorize(() => '<token-for-org-1>')
sdk1.headers({ 'x-epilot-org-id': 'org-1' })

const sdk2 = createSDK()
sdk2.authorize(() => '<token-for-org-2>')
sdk2.headers({ 'x-epilot-org-id': 'org-2' })

Interceptors

Use axios interceptors for custom request/response processing. Since clients are axios instances, you can use client.interceptors directly:

entityClient.interceptors.response.use((response) => {
  console.debug(`${response.config.method?.toUpperCase()} ${response.config.url}`, {
    status: response.status,
    data: response.data,
  })
  return response
})

Or register global interceptors applied to all clients:

epilot.interceptors.request((config) => {
  config.headers['x-correlation-id'] = generateTraceId()
  return config
})

Auto-Retry (429 Too Many Requests)

The SDK automatically retries requests that receive a 429 Too Many Requests response. It respects the Retry-After header (in seconds) to determine how long to wait before retrying.

Enabled by default with up to 3 retries.

import { epilot } from '@epilot/sdk'

// Customize retry behavior
epilot.retry({ maxRetries: 5, defaultDelayMs: 2000 })

// Disable retries
epilot.retry({ maxRetries: 0 })
Option Default Description
maxRetries 3 Maximum number of retries. Set to 0 to disable.
defaultDelayMs 1000 Fallback delay in ms when Retry-After header is missing.

For individually imported clients (tree-shakeable imports), apply the interceptor manually:

import { getClient, authorize } from '@epilot/sdk/entity'
import { applyRetryInterceptor } from '@epilot/sdk'

const entityClient = getClient()
authorize(entityClient, () => '<my-token>')
applyRetryInterceptor({ client: entityClient, config: { maxRetries: 3 } })

Large Response Handling (413 Payload Too Large)

epilot APIs use a large response middleware to work around the AWS Lambda 6MB response limit. When a response exceeds ~5.1MB, the API uploads the payload to S3 and returns a presigned URL instead.

The SDK handles this transparently — it sends the opt-in Accept header and automatically fetches the full payload from S3 when a large response URL is returned. Enabled by default.

import { epilot } from '@epilot/sdk'

// Disable large response handling
epilot.largeResponse({ enabled: false })

For individually imported clients (tree-shakeable imports), apply the interceptor manually:

import { getClient, authorize } from '@epilot/sdk/entity'
import { applyLargeResponseInterceptor } from '@epilot/sdk'

const entityClient = getClient()
authorize(entityClient, () => '<my-token>')
applyLargeResponseInterceptor({ client: entityClient, config: { enabled: true } })

Overrides & Custom APIs

Override built-in API specs or register custom APIs via .epilot/sdk-overrides.json. This is useful for testing new versions of an API spec or getting the latest types without waiting for an SDK release.

{
  "entity": "./specs/entity-openapi.json",
  "myNewApi": "./specs/my-new-api-openapi.json"
}
// Built-in API with overridden spec
const { data } = await epilot.entity.getEntity({ slug: 'contact', id: '123' })

Override Commands

# Apply all overrides from .epilot/sdk-overrides.json
npx epilot-sdk override

# Override a single API
npx epilot-sdk override entity ./my-local-entity-spec.yaml

# Regenerate types after spec changes
npx epilot-sdk typegen
Migration from @epilot/*-client

Drop-in replacement — just change the import path:

// Before
import { getClient, createClient, authorize } from '@epilot/entity-client'
import type { Client, Entity } from '@epilot/entity-client'

// After
import { getClient, createClient, authorize } from '@epilot/sdk/entity'
import type { Client, Entity } from '@epilot/sdk/entity'
Client Lifecycle

When you call authorize(), headers(), retry(), largeResponse(), or interceptors, the SDK invalidates all cached client instances. The next operation call creates a fresh client with the updated configuration.

Operation methods are always up to date — calls like epilot.entity.getEntity(...) re-resolve the client on every invocation, so they always use the latest config.

Direct getClient() references can go stale — if you hold a reference and then change config, your reference still points to the old client:

const entityClient = epilot.entity.getClient()

epilot.authorize('new-token') // invalidates all cached clients

// entityClient still has the old token
// epilot.entity.getEntity(...) will use a new client with the new token

If you need a long-lived reference that survives config changes, call getClient() again after changing config, or use operation methods directly.

Contributing

See CONTRIBUTING.md for internal development and publishing instructions.

About

javascript epilot-sdk

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors