Install
$ agentstack add skill-apideck-libraries-api-skills-apideck-node ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Apideck TypeScript SDK Skill
Overview
The Apideck Unified API provides a single integration layer to connect with 200+ third-party services across accounting, CRM, HRIS, file storage, ATS, e-commerce, and more. The official TypeScript SDK (@apideck/unify) provides typed clients for all unified APIs.
Key capabilities:
- Accounting - Invoices, bills, payments, ledger accounts, journal entries, tax rates, balance sheets, P&L
- CRM - Contacts, companies, leads, opportunities, activities, pipelines, notes
- HRIS - Employees, departments, payrolls, time-off requests, schedules
- File Storage - Files, folders, drives, shared links, upload sessions
- ATS - Jobs, applicants, applications
- Vault - Connection management, OAuth flows, custom field mapping
- Vault JS - Embeddable modal UI for users to authorize connectors and manage settings
- Webhook - Event subscriptions and real-time notifications
Installation
npm add @apideck/unify
Requires Node.js 18+. The SDK is fully typed with TypeScript definitions.
IMPORTANT RULES
- ALWAYS use the
@apideck/unifySDK. DO NOT make rawfetch/axioscalls to the Apideck API. - ALWAYS pass
apiKey,appId, andconsumerIdwhen initializing the client. These are required for all API calls. - ALWAYS set the
APIDECK_API_KEYenvironment variable rather than hardcoding API keys. - USE
serviceIdto specify which downstream connector to use (e.g.,"salesforce","quickbooks","xero"). If a consumer has multiple connections for an API,serviceIdis required. - USE cursor-based pagination with
for await...offor iterating large result sets. DO NOT implement manual pagination. - USE the
filterparameter to narrow results server-side. DO NOT fetch all records and filter client-side. - USE the
fieldsparameter to request only the columns you need. This reduces response size and improves performance. - ALWAYS handle errors with try/catch. The SDK throws typed errors for different HTTP status codes.
- DO NOT store Apideck API keys, App IDs, or Consumer IDs in source code. Use environment variables or a secrets manager.
Quick Start
import { Apideck } from "@apideck/unify";
const apideck = new Apideck({
apiKey: process.env["APIDECK_API_KEY"] ?? "",
appId: "your-app-id",
consumerId: "your-consumer-id",
});
// List CRM contacts
const { data } = await apideck.crm.contacts.list({
limit: 20,
filter: { email: "john@example.com" },
});
for (const contact of data) {
console.log(contact.name, contact.emails);
}
SDK Patterns
Client Setup
import { Apideck } from "@apideck/unify";
const apideck = new Apideck({
apiKey: process.env["APIDECK_API_KEY"] ?? "",
appId: "your-app-id",
consumerId: "your-consumer-id",
});
The consumerId identifies the end-user whose connections are being used. In multi-tenant apps, set this per-request or per-user session.
CRUD Operations
All resources follow the same pattern: apideck.{api}.{resource}.{operation}().
// LIST - retrieve multiple records
const { data } = await apideck.crm.contacts.list({
serviceId: "salesforce",
limit: 20,
filter: { email: "john@example.com" },
sort: { by: "updated_at", direction: "desc" },
fields: "id,name,email,phone_numbers",
});
// CREATE - create a new record
const { data: created } = await apideck.crm.contacts.create({
serviceId: "salesforce",
contact: {
first_name: "John",
last_name: "Doe",
emails: [{ email: "john@example.com", type: "primary" }],
phone_numbers: [{ number: "+1234567890", type: "mobile" }],
},
});
console.log(created.id); // "contact_abc123"
// GET - retrieve a single record
const { data: contact } = await apideck.crm.contacts.get({
id: "contact_abc123",
serviceId: "salesforce",
});
// UPDATE - modify an existing record
const { data: updated } = await apideck.crm.contacts.update({
id: "contact_abc123",
serviceId: "salesforce",
contact: { first_name: "Jane" },
});
// DELETE - remove a record
await apideck.crm.contacts.delete({
id: "contact_abc123",
serviceId: "salesforce",
});
Pagination
Use async iteration to automatically handle cursor-based pagination:
const result = await apideck.accounting.invoices.list({
serviceId: "quickbooks",
limit: 50,
});
// Automatically fetches next pages
for await (const page of result) {
for (const invoice of page.data) {
console.log(invoice.number, invoice.total);
}
}
Or handle pagination manually:
let cursor: string | undefined;
do {
const { data, meta } = await apideck.accounting.invoices.list({
serviceId: "quickbooks",
limit: 50,
cursor,
});
for (const invoice of data) {
console.log(invoice.number);
}
cursor = meta?.cursors?.next ?? undefined;
} while (cursor);
Error Handling
import { Apideck } from "@apideck/unify";
import * as errors from "@apideck/unify/models/errors";
try {
const { data } = await apideck.crm.contacts.get({ id: "invalid" });
} catch (e) {
if (e instanceof errors.BadRequestResponse) {
console.error("Bad request:", e.message);
} else if (e instanceof errors.UnauthorizedResponse) {
console.error("Invalid API key or missing credentials");
} else if (e instanceof errors.NotFoundResponse) {
console.error("Record not found");
} else if (e instanceof errors.PaymentRequiredResponse) {
console.error("API limit reached or payment required");
} else if (e instanceof errors.UnprocessableResponse) {
console.error("Validation error:", e.message);
} else {
throw e;
}
}
Common Parameters
Most list endpoints accept these parameters:
| Parameter | Type | Description | |-----------|------|-------------| | serviceId | string | Downstream connector ID (e.g., "quickbooks", "salesforce") | | limit | number | Max results per page (1-200, default 20) | | cursor | string | Pagination cursor from previous response | | filter | object | Resource-specific filter criteria | | sort | object | { by: string, direction: "asc" \| "desc" } | | fields | string | Comma-separated field names to return | | passThrough | object | Pass-through query parameters for the downstream API |
Pass-Through Parameters
When the unified model doesn't cover a connector-specific field, use passThrough:
const { data } = await apideck.accounting.invoices.list({
serviceId: "quickbooks",
passThrough: {
search: "overdue",
},
});
For creating/updating, use pass_through in the request body to send connector-specific fields:
const { data } = await apideck.crm.contacts.create({
serviceId: "salesforce",
contact: {
first_name: "John",
last_name: "Doe",
pass_through: [
{
service_id: "salesforce",
operation_id: "contactsAdd",
extend_object: { custom_sf_field__c: "value" },
},
],
},
});
API Namespaces
The SDK organizes APIs by namespace. See the reference files for detailed endpoints:
| Namespace | Reference | Resources | |-----------|-----------|-----------| | apideck.accounting.* | [references/accounting-api.md](references/accounting-api.md) | invoices, bills, payments, customers, suppliers, ledgerAccounts, journalEntries, taxRates, creditNotes, purchaseOrders, balanceSheet, profitAndLoss, and more | | apideck.crm.* | [references/crm-api.md](references/crm-api.md) | contacts, companies, leads, opportunities, activities, notes, pipelines, users | | apideck.hris.* | [references/hris-api.md](references/hris-api.md) | employees, companies, departments, payrolls, timeOffRequests | | apideck.fileStorage.* | [references/file-storage-api.md](references/file-storage-api.md) | files, folders, drives, driveGroups, sharedLinks, uploadSessions | | apideck.ats.* | [references/ats-api.md](references/ats-api.md) | applicants, applications, jobs | | apideck.vault.* | [references/vault-api.md](references/vault-api.md) | connections, connectionSettings, consumers, customMappings, logs, sessions | | apideck.webhook.* | [references/webhook-api.md](references/webhook-api.md) | webhooks, eventLogs |
Vault JS (Embeddable UI)
Use [@apideck/vault-js](references/vault-js.md) to embed a pre-built modal that lets your users authorize connectors and manage integration settings. Session creation must happen server-side.
// 1. Server-side: create a session
const { data } = await apideck.vault.sessions.create({
session: {
consumer_metadata: { account_name: "Acme Corp", user_name: "John Doe", email: "john@acme.com" },
redirect_uri: "https://myapp.com/integrations",
settings: { unified_apis: ["accounting", "crm"] },
theme: { vault_name: "My App", primary_color: "#4F46E5" },
},
});
// 2. Client-side: open the modal
import { ApideckVault } from "@apideck/vault-js";
ApideckVault.open({
token: sessionToken,
onConnectionChange: (connection) => console.log("Changed:", connection),
onClose: () => console.log("Closed"),
});
See [references/vault-js.md](references/vault-js.md) for full configuration options, theming, React integration, and event callbacks.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: apideck-libraries
- Source: apideck-libraries/api-skills
- License: Apache-2.0
- Homepage: https://developers.apideck.com/building-with-llms
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.