v1.0

Submitting Deals from a CRM

How to push deals from your CRM into SmartMCA via the API

This guide walks through integrating your CRM (Salesforce, HubSpot, or custom) with SmartMCA to automatically submit new deals when they close.

Overview

The typical flow:

  1. CRM deal closes → trigger fires (webhook, automation, Zapier)
  2. Your middleware creates a merchant in SmartMCA (or finds existing)
  3. Your middleware creates a contact for the merchant
  4. Your middleware submits an application with deal details
  5. SmartMCA processes the application through your configured workflow

Prerequisites

  • API key with scopes: merchants:write, contacts:write, applications:write
  • CRM webhook or automation configured to fire on deal close

Step 1: Create or Find the Merchant

Check if the merchant already exists by searching, then create if needed.

// Search for existing merchant by EIN
const searchRes = await fetch(
  'https://api.smartmca.com/api/public/v1/merchants?search=12-3456789',
  { headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const { data: merchants } = await searchRes.json();

let merchantId;
if (merchants.length > 0) {
  merchantId = merchants[0].id;
} else {
  // Create new merchant
  const createRes = await fetch('https://api.smartmca.com/api/public/v1/merchants', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      legalName: crmDeal.companyName,
      dba: crmDeal.dbaName,
      ein: crmDeal.ein,
      industry: crmDeal.industry,
      address: crmDeal.address,
      city: crmDeal.city,
      state: crmDeal.state,
      zip: crmDeal.zip,
    }),
  });
  const merchant = await createRes.json();
  merchantId = merchant.data.id;
}

Step 2: Create the Contact

const contactRes = await fetch(
  `https://api.smartmca.com/api/public/v1/merchants/${merchantId}/contacts`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      firstName: crmDeal.contactFirstName,
      lastName: crmDeal.contactLastName,
      email: crmDeal.contactEmail,
      phone: crmDeal.contactPhone,
      title: crmDeal.contactTitle,
      isPrimary: true,
    }),
  }
);

Step 3: Submit the Application

const appRes = await fetch('https://api.smartmca.com/api/public/v1/applications', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': `crm-deal-${crmDeal.id}`, // Prevent duplicates
  },
  body: JSON.stringify({
    merchantId,
    requestedAmount: crmDeal.amount,
    useOfFunds: crmDeal.purpose,
    sourceType: 'direct',
    brokerName: crmDeal.referralPartner || undefined,
  }),
});

const application = await appRes.json();
console.log(`Application created: ${application.data.id}`);

Step 4: Upload Documents (Optional)

If your CRM has attached documents (bank statements, tax returns), upload them:

const form = new FormData();
form.append('file', fs.createReadStream(documentPath));
form.append('documentType', 'bankStatement');

await fetch(
  `https://api.smartmca.com/api/public/v1/applications/${application.data.id}/documents`,
  {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${API_KEY}` },
    body: form,
  }
);

Handling Duplicates

Use the Idempotency-Key header with a deterministic key (e.g., crm-deal-{crmDealId}) to prevent duplicate submissions if your webhook fires more than once. See the Idempotency guide for details.

Monitoring

Set up a webhook subscription for application.status_changed to receive updates as the application moves through your workflow:

await fetch('https://api.smartmca.com/api/public/v1/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://your-crm-middleware.com/webhooks/smartmca',
    events: ['application.status_changed', 'deal.funded'],
    description: 'CRM sync webhook',
  }),
});

Error Handling

HTTP StatusMeaningAction
409Duplicate (idempotency)Safe to ignore — original response returned
422Validation errorCheck field values, fix and retry
429Rate limitedBack off and retry after Retry-After header
500Server errorRetry with exponential backoff