agentleFS
apideck-librariesapideck-libraries/api-skills/skills/apideck-migration/SKILL.md

apideck-migration

Skill4 starsChanged 3 months agoApache-2.0View on GitHub

Guide for migrating from direct third-party API integrations to Apideck's unified API. Use when a user wants to replace their existing Salesforce, HubSpot, QuickBooks, Xero, or other direct API integrations with Apideck, or when consolidating multiple integrations into a single unified layer.

  • Sends data out

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 4 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    ALWAYS check connector coverage before migrating.

    line 19
  2. Distinctive:

    ALWAYS preserve existing data flows and business logic.

    line 20
  3. Very specific:

    USE pass_through for connector-specific fields that don't map to the unified model.

    line 21
  4. Distinctive:

    USE custom field mapping in Vault for recurring connector-specific fields.

    line 22
  5. Distinctive:

    NEVER delete the existing integration code until the Apideck migration is verified in production.

    line 23

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Apideck Migration Guide Skill

Overview

This skill helps migrate existing direct third-party API integrations (Salesforce, HubSpot, QuickBooks, Xero, etc.) to Apideck's unified API layer. The benefit is replacing N separate integrations with a single Apideck integration that supports 200+ connectors.

IMPORTANT RULES

  • ALWAYS check connector coverage before migrating. Not all operations may be supported through the unified API.
  • ALWAYS preserve existing data flows and business logic. Migration should be transparent to end-users.
  • USE pass_through for connector-specific fields that don't map to the unified model.
  • USE custom field mapping in Vault for recurring connector-specific fields.
  • NEVER delete the existing integration code until the Apideck migration is verified in production.
  • RECOMMEND a phased migration: start with read operations, then writes, then webhooks.

Migration Strategy

Phase 1: Assessment

  1. Inventory existing integrations — List all third-party APIs currently in use
  2. Map operations — For each integration, list the CRUD operations and fields used
  3. Check coverage — Verify each operation is supported via the Apideck Connector API
  4. Identify gaps — Note operations that need pass_through or Proxy API
  5. Plan consumer mapping — Decide how your users/tenants map to Apideck consumer IDs

Phase 2: Connection Setup

  1. Create Apideck account — Get API key and App ID from the dashboard
  2. Enable connectors — Enable the connectors you need in the Apideck dashboard
  3. Integrate Vault — Add Vault JS to your frontend for user-managed connections
  4. Create consumers — Map your existing users to Apideck consumer IDs
  5. Authorize connections — Have users re-authorize via Vault (OAuth is handled automatically)

Phase 3: Read Migration (Low Risk)

Replace read operations first since they're non-destructive:

// BEFORE: Direct Salesforce API
const contacts = await salesforce.sobjects.Contact.find({
  Email: "john@example.com",
});

// AFTER: Apideck Unified API
const { data } = await apideck.crm.contacts.list({
  serviceId: "salesforce",
  filter: { email: "john@example.com" },
});

Phase 4: Write Migration

Replace create/update/delete operations:

// BEFORE: Direct HubSpot API
const contact = await hubspot.crm.contacts.basicApi.create({
  properties: {
    firstname: "John",
    lastname: "Doe",
    email: "john@example.com",
    company: "Acme Corp",
  },
});

// AFTER: Apideck Unified API
const { data } = await apideck.crm.contacts.create({
  serviceId: "hubspot",
  contact: {
    first_name: "John",
    last_name: "Doe",
    emails: [{ email: "john@example.com", type: "primary" }],
    company_name: "Acme Corp",
  },
});

Phase 5: Webhook Migration

Replace direct webhook handlers with Apideck's unified webhooks:

// BEFORE: Salesforce-specific webhook handler
app.post("/webhooks/salesforce", (req, res) => {
  const event = req.body;
  if (event.type === "ContactChangeEvent") {
    handleContactChange(event);
  }
});

// AFTER: Apideck unified webhook handler
app.post("/webhooks/apideck", (req, res) => {
  const signature = req.headers["x-apideck-signature"];
  if (!verifySignature(req.body, signature, secret)) {
    return res.status(401).send("Invalid signature");
  }

  const { event_type, entity_id, service_id } = req.body.payload;
  // Works for ALL connectors, not just Salesforce
  if (event_type === "crm.contact.updated") {
    handleContactChange(entity_id, service_id);
  }
  res.status(200).send("OK");
});

Common Migration Patterns

CRM: Salesforce to Apideck

Salesforce APIApideck Unified API
sobjects.Contact.create()crm.contacts.create({ serviceId: "salesforce" })
sobjects.Account.find()crm.companies.list({ serviceId: "salesforce" })
sobjects.Opportunity.update()crm.opportunities.update({ serviceId: "salesforce" })
sobjects.Lead.create()crm.leads.create({ serviceId: "salesforce" })
sobjects.Task.create()crm.activities.create({ serviceId: "salesforce" })
Custom fields via custom_sf_field__cpass_through: [{ service_id: "salesforce", extend_object: { custom_sf_field__c: "value" } }]

CRM: HubSpot to Apideck

HubSpot APIApideck Unified API
crm.contacts.basicApi.create()crm.contacts.create({ serviceId: "hubspot" })
crm.companies.basicApi.getAll()crm.companies.list({ serviceId: "hubspot" })
crm.deals.basicApi.create()crm.opportunities.create({ serviceId: "hubspot" })
crm.contacts.searchApi.doSearch()crm.contacts.list({ serviceId: "hubspot", filter: { ... } })

Accounting: QuickBooks to Apideck

QuickBooks APIApideck Unified API
Invoice.create()accounting.invoices.create({ serviceId: "quickbooks" })
Customer.findAll()accounting.customers.list({ serviceId: "quickbooks" })
Bill.create()accounting.bills.create({ serviceId: "quickbooks" })
Payment.create()accounting.payments.create({ serviceId: "quickbooks" })
JournalEntry.create()accounting.journalEntries.create({ serviceId: "quickbooks" })
CompanyInfo.get()accounting.companyInfo.get({ serviceId: "quickbooks" })

Accounting: Xero to Apideck

Xero APIApideck Unified API
xero.accountingApi.createInvoices()accounting.invoices.create({ serviceId: "xero" })
xero.accountingApi.getContacts()accounting.customers.list({ serviceId: "xero" })
xero.accountingApi.createBankTransactions()accounting.payments.create({ serviceId: "xero" })
xero.accountingApi.getReportBalanceSheet()accounting.balanceSheet.get({ serviceId: "xero" })

HRIS: BambooHR to Apideck

BambooHR APIApideck Unified API
GET /employees/directoryhris.employees.list({ serviceId: "bamboohr" })
POST /employeeshris.employees.create({ serviceId: "bamboohr" })
GET /employees/{id}hris.employees.get({ serviceId: "bamboohr", id })
PUT /employees/{id}/time_off/requesthris.timeOffRequests.create({ serviceId: "bamboohr" })

File Storage: Google Drive to Apideck

Google Drive APIApideck Unified API
drive.files.list()fileStorage.files.list({ serviceId: "google-drive" })
drive.files.create()fileStorage.files.create({ serviceId: "google-drive" })
drive.files.get()fileStorage.files.get({ serviceId: "google-drive" })
drive.files.export()fileStorage.files.download({ serviceId: "google-drive" })
drive.permissions.create()fileStorage.sharedLinks.create({ serviceId: "google-drive" })

Handling Connector-Specific Fields

Option 1: Pass-Through (inline)

For one-off connector-specific fields in request bodies:

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: {
          RecordTypeId: "012000000000001",
          Custom_Score__c: 85,
        },
      },
    ],
  },
});

Option 2: Custom Field Mapping (reusable)

For fields that are used repeatedly, configure custom mapping in Vault so they appear as part of the unified model:

// Set up custom mapping via Vault API
await apideck.vault.customMappings.update({
  unifiedApi: "crm",
  serviceId: "salesforce",
  id: "mapping_123",
  customMapping: {
    value: "$.Custom_Score__c",
  },
});

// Now the field appears in custom_fields on every response
const { data } = await apideck.crm.contacts.get({
  id: "contact_123",
  serviceId: "salesforce",
});
// data.custom_fields includes { id: "mapping_123", value: 85 }

Option 3: Proxy API (full control)

For operations not supported by the unified API, use the Proxy to make direct downstream calls while still using Apideck's managed authentication:

const response = await fetch("https://unify.apideck.com/proxy", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "x-apideck-app-id": appId,
    "x-apideck-consumer-id": consumerId,
    "x-apideck-service-id": "salesforce",
    "x-apideck-downstream-url": "/services/data/v59.0/sobjects/CustomObject__c",
    "x-apideck-downstream-method": "GET",
    "Content-Type": "application/json",
  },
});

Testing the Migration

  1. Run both integrations in parallel — Shadow mode: make Apideck calls alongside existing calls and compare responses
  2. Use raw mode — Add raw=true to Apideck calls to compare with the original API response
  3. Contract test with Portman — Generate tests from OpenAPI specs and run against your staging environment
  4. Test with the API Explorer — Use the Apideck API Explorer to verify endpoints interactively
  5. Gradual rollout — Migrate one connector at a time, starting with the lowest-traffic integration

Post-Migration Benefits

Once migrated to Apideck:

  • Add new connectors instantly — Enable a new connector in the dashboard, no code changes needed
  • User self-service — End-users manage their own connections via Vault
  • Unified webhooks — One handler for all connectors instead of N separate handlers
  • Unified error handling — One error format instead of learning each API's error structure
  • Automatic maintenance — Apideck handles API version changes, deprecations, and auth token refresh

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.