providers/claude/plugin/skills/apideck-best-practices/SKILL.md
Best practices for building Apideck integrations. Covers authentication patterns, pagination, error handling, connection management with Vault, webhook setup, and common pitfalls. Use when designing or reviewing any Apideck integration regardless of language.
npx skillsauth add apideck-libraries/api-skills apideck-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The Apideck Unified API base URL is https://unify.apideck.com. All API calls must be made server-side to prevent token leakage.
Every API call requires three headers: Authorization: Bearer {API_KEY}, x-apideck-app-id, and x-apideck-consumer-id. The x-apideck-service-id header specifies which downstream connector to use (e.g., salesforce, quickbooks, xero). When a consumer has multiple connections for the same unified API, x-apideck-service-id is required.
Never hardcode API keys in source code. Always use environment variables or a secrets manager. Never expose API keys to the client/browser.
Always use the official Apideck SDK for the user's language. Do not make raw HTTP calls when an SDK is available:
| Language | Package |
|----------|---------|
| TypeScript/Node.js | @apideck/unify |
| Python | apideck-unify |
| C# / .NET | ApideckUnifySdk |
| Java | com.apideck:unify |
| Go | github.com/apideck-libraries/sdk-go |
| PHP | apideck-libraries/sdk-php |
All SDKs follow the same CRUD pattern: client.{api}.{resource}.{operation}(). All SDKs support retry configuration with exponential backoff.
The consumerId represents your end-user — the person whose third-party connections you're accessing. In multi-tenant SaaS applications:
consumerId per request — never use a shared consumer for all usersAlways use Apideck Vault for managing end-user connections. Never build custom OAuth flows when Vault handles them.
Use @apideck/vault-js to embed the connection management modal in your frontend. Session creation must always happen server-side:
vault.sessions.create() with the consumer's metadataApideckVault.open({ token })onConnectionChange callbacks to update your UI when users authorize/modify connectionsCustomize the Vault modal appearance via session theme properties (logo, colors, vault name) to match your brand.
Apideck uses cursor-based pagination across all list endpoints. Always paginate — never assume a single page returns all records.
limit (1-200, default 20) to control page sizefor await...of (Node.js), .next() (Python/Go/.NET), callAsStream() (Java), foreach generator (PHP)nullFor incremental sync, use filter[updated_since] with an ISO 8601 timestamp to fetch only records modified since your last sync.
Always filter server-side using the filter parameter. Never fetch all records and filter client-side — this wastes API units and increases response time.
Always use the fields parameter to request only the columns you need. This reduces response size and improves performance. Example: fields=id,name,email,updated_at.
Always handle errors. All SDKs provide typed error classes:
| HTTP Code | Meaning | Action |
|-----------|---------|--------|
| 400 | Bad Request | Fix request parameters |
| 401 | Unauthorized | Check API key and consumer credentials |
| 402 | Payment Required | API limit reached — upgrade plan or wait |
| 404 | Not Found | Resource does not exist or wrong service ID |
| 422 | Unprocessable | Validation error — check required fields |
| 429 | Rate Limited | Back off and retry (check x-downstream-ratelimit-reset header) |
| 5xx | Server Error | Retry with exponential backoff |
For downstream connector errors, inspect the detail and downstream_errors fields to get the original error from the third-party service.
When the unified model doesn't cover a connector-specific field, use pass_through in the request body:
{
"first_name": "John",
"pass_through": [
{
"service_id": "salesforce",
"operation_id": "contactsAdd",
"extend_object": { "custom_sf_field__c": "value" }
}
]
}
Use custom field mapping in Vault to let end-users map their connector-specific fields without code changes.
Use Apideck webhooks for real-time notifications instead of polling. Apideck supports both native webhooks (from connectors that support them) and virtual webhooks (polling-based for connectors that don't).
Always verify webhook signatures using the x-apideck-signature header with HMAC-SHA256. Never process unverified webhook payloads.
Webhook events follow the pattern {api}.{resource}.{action} (e.g., crm.contact.created, accounting.invoice.updated).
Apideck provides detailed API call logs for every request made through the platform. Logs are available both in the Apideck dashboard and via the API. Use logs to debug failed requests, inspect downstream responses, and monitor integration health.
Access logs programmatically via the Vault API: vault.logs.list(). Each log entry includes the HTTP method, URL, status code, request/response bodies, downstream service, and timestamps.
Use logs when:
Append raw=true to any request to include the unmodified downstream response alongside the normalized data. Use this for debugging or when you need connector-specific fields not in the unified model.
Use Portman to generate API contract tests from Apideck's OpenAPI specs. Apideck publishes specs at https://specs.apideck.com/{api-name}.yml. See the apideck-portman skill for full configuration.
The Apideck API Explorer lets you test any unified API endpoint directly in the browser without writing code. It accepts a JWT token for authentication and returns live responses.
The Explorer URL format supports pre-filled headers for quick access:
https://developers.apideck.com/api-explorer?id={api}&headers={encoded_json}
Where headers is a URL-encoded JSON object with:
Authorization: Bearer {JWT_TOKEN}x-apideck-auth-type: JWTx-apideck-app-id: your app IDx-apideck-consumer-id: the consumer ID to test withRecommend the API Explorer when users want to:
Apideck publishes OpenAPI 3.x specs for all unified APIs at https://specs.apideck.com/{api-name}.yml. Use these for:
serviceId values within a single workflow — stick to one connector per operation chain.row_version field on updates — use it for optimistic concurrency when supported.development
Jira Teams via Apideck's Proxy API + managed Vault auth — Apideck handles auth and proxies HTTP calls to Jira Teams's native API. Use when the user wants to call Jira Teams (no unified API resource mapping). Routes through Apideck with serviceId "jira-teams".
development
Jira Service Desk via Apideck's Proxy API + managed Vault auth — Apideck handles auth and proxies HTTP calls to Jira Service Desk's native API. Use when the user wants to call Jira Service Desk (no unified API resource mapping). Routes through Apideck with serviceId "jira-service-desk".
development
Jira Data Center via Apideck's Proxy API + managed Vault auth — Apideck handles auth and proxies HTTP calls to Jira Data Center's native API. Use when the user wants to call Jira Data Center (no unified API resource mapping). Routes through Apideck with serviceId "jira-data-center".
development
JetBrains YouTrack via Apideck's Proxy API + managed Vault auth — Apideck handles auth and proxies HTTP calls to JetBrains YouTrack's native API. Use when the user wants to call JetBrains YouTrack (no unified API resource mapping). Routes through Apideck with serviceId "jetbrains-youtrack".