TypeScript SDK
The official TypeScript/JavaScript client — typed resources, cursor pagination helpers, conservative retries, and typed errors. Zero runtime dependencies.
Requires Node 18+ (or any runtime with a global fetch). The package has no runtime dependencies — nothing extra to audit or keep patched.
Quick start
Keep your key out of source control
Key scopes
There are two kinds of key and they are not interchangeable. A sub-account key reaches agents, contacts, calendars, appointments and calls. An agency key reaches dextel.agency.*. The tenant is derived from the key itself, so you never pass an agency_id or sub_account_id. Calling an agency method with a sub-account key throws PermissionError.
Resources
Read-only resources genuinely have no create, update or del method — calling one is a compile error rather than a 404 you discover in production.
Create, update, delete
Pagination
The API uses cursor pagination, not page numbers. The SDK gives you three ways to consume it.
iterate() over listAll() for large collections — it holds one page in memory rather than the entire set.Errors
Every failure throws a typed error, so you branch with instanceof rather than comparing status numbers at each call site.
The classes are ValidationError (400, 422), AuthenticationError (401), PermissionError (403), NotFoundError (404), RateLimitError (429, carrying retryAfterSeconds), ServerError (5xx), and ConnectionError when no response arrived at all. All carry .status, .requestId and .rateLimit. Your API key never appears in an error message or stack trace.
Retries
Retries are deliberately conservative. GET and HEAD retry on 408, 429 and 5xx. Writes — POST, PATCH and DELETE — retry only on 429, because a 429 means the request never ran. Any other failed write is not retried: the API has no idempotency keys, so repeating a POST could create a second contact.
Backoff honours Retry-Afterwhen the server sends one, and otherwise uses exponential backoff with full jitter — so that many clients rate-limited at the same moment don't retry in lockstep and collide again.
Rate limits
The current window is available after any call via dextel.rateLimit, parsed from the response headers into limit, remaining and resetAt.
Configuration
Escape hatch
If an endpoint isn't wrapped yet, call it directly through the underlying client — you keep authentication, retries and error mapping.
