Skip to main content
When adding new leads to your CRM, you’ll need to search and find their company’s profile: name, description, industry classification, slogan, social profiles, and more. This guide shows how to automate that with Context.dev’s Brand API.

Prerequisites

  • A Context.dev API key. Sign up at context.dev, copy it from the dashboard, and save it to .env (make sure .env is in .gitignore).
    export CONTEXT_DEV_API_KEY="ctxt_secret_..."
    
  • Admin access to your CRM to create a webhook on new leads and write fields back.
  • The Context.dev SDK for your backend, or call the API directly with curl (no install required):
    npm install context.dev
    

Architecture

The pipeline has two jobs:
  1. Enrich a lead’s company profile by saving the Brand API response in your CRM’s fields.
  2. Listen for new-lead events and run that enrichment on each one.

Step 1. Enrich with the Brand API

Here’s what the Brand API gives you:
FieldWhat it is
brand.titleCompany name.
brand.descriptionOne-paragraph company description.
brand.sloganMarketing tagline, when available.
brand.domainCanonical company domain.
brand.logos[]Image source URLs for all variants of the logo and icon.
brand.colors[]Hex codes for every color in the brand palette.
brand.backdrops[]Hero and background imagery.
brand.socials[]Links to their social profiles.
brand.addressHQ address: street, city, state/province, country, and postal code.
brand.phonePublic contact phone, when available.
brand.emailPublic contact email, when available.
brand.industries.eic[]Industry and subindustry classification. (Read more about EIC)
brand.stockStock ticker and the name of the exchange for public companies, otherwise null.
brand.primary_languageDetected language of the brand’s site.
Exactly which field each value maps to depends on what CRM you’re using. Read their documentation to find this. Here’s the code for the server that works for HubSpot, Salesforce, Zoho, Pipedrive, and monday.com.
import express from "express";
import ContextDev from "context.dev";

const app = express();
app.use(express.json());
const client = new ContextDev({ apiKey: process.env.CONTEXT_DEV_API_KEY });

// One endpoint for every CRM. Point each CRM's webhook at /webhooks/<crm>.
app.post("/webhooks/:crm", async (req, res) => {
  res.sendStatus(200); // ack fast; CRMs retry slow endpoints

  const { email, recordId } = extractLead(req.params.crm, req.body);
  if (!email) return;

  const fields = await enrichLead(email);
  if (fields) await writeBack(req.params.crm, recordId, fields);
});

// Call the Brand API and map the response to the fields you store.
async function enrichLead(email: string) {
  try {
    const { brand } = await client.brand.retrieveByEmail({ email, timeoutMS: 8000 });
    return {
      companyName: brand.title,
      description: brand.description,
      phone: brand.phone,
      website: brand.domain,
      logo: brand.logos?.find((l) => l.mode === "light")?.url ?? brand.logos?.[0]?.url ?? null,
      industry: brand.industries?.eic?.[0]?.industry ?? null,
      linkedin: brand.socials?.find((s) => s.type === "linkedin")?.url ?? null,
    };
  } catch {
    return null; // 422 free email, 400 no brand, 408 timeout: keep the rep's input
  }
}

// CRM-specific: read the email + record id from each payload shape.
function extractLead(crm: string, body: any): { email?: string; recordId?: string } {
  switch (crm) {
    case "hubspot":    return { email: body[0]?.propertyValue, recordId: body[0]?.objectId };
    case "salesforce": return { email: body.Lead?.Email, recordId: body.Lead?.Id };
    case "zoho":       return { email: body.email, recordId: body.id };
    case "pipedrive":  return { email: body.data?.email?.[0]?.value, recordId: body.data?.id };
    case "monday":     return { email: body.event?.columnValues?.email?.email, recordId: body.event?.pulseId };
    default:           return {};
  }
}

// CRM-specific: write the mapped fields back, filling blanks only.
async function writeBack(crm: string, recordId: string | undefined, fields: object) {
  // HubSpot CRM API, Salesforce sObject update, Zoho Records API,
  // Pipedrive Persons, monday change_multiple_column_values.
}

app.listen(3000);
10 credits per successful call Host this on something like Vercel, and use the URL it’s hosted on as the webhook URL in Step 2. This server follows these best practices:
  • Free and personal email filtering is built in. Brand API rejects Gmail, Yahoo, and 10,000+ free or disposable providers with a 422 error code. Keep placeholders for when data can’t be found.
  • Set a timeout. Pass timeoutMS so a cold lookup can’t hang your handler. A first-time domain can take a few seconds; warm lookups return in about 250ms.
  • Cache by domain. Enrich once per company and store the result in your own database keyed by domain. Since brand details don’t change often, this will save your API credits.

Step 2. Listen for new leads

Every major CRM platform lets you set up webhooks. When set up, every time you add a new lead, the CRM app will send a POST request to the configured endpoint. You’ll need to create a backend server which serves this route by using the work email field to pull data from Context.dev’s Brand API and then write the brand profile data back to the CRM.
CRMHow to set up a webhook on new leadsDocs
HubSpotSubscribe a private app to the contact.creation event (Settings → Integrations → Private Apps → Webhooks).Private app webhooks
SalesforceA record-triggered Flow on Lead → created, with an HTTP Callout (or Outbound Message) action to your endpoint.Configure an HTTP Callout
Zoho CRMA workflow rule on the Leads module with a Webhook action, or the Webhook API.Webhooks in workflows
PipedriveA Webhooks v2 subscription for create.person (or create.lead).Guide for Webhooks v2
monday.comA create_item webhook on your leads board, via the API or the board integration.Webhooks reference
When you set up the webhook, point its URL at wherever your backend server is hosted (for example https://api.example.com/webhooks/hubspot). Step 1 describes how to actually build this server.

(Optional) Get specific information about leads

When you need a specific data point your sales team cares about but isn’t included in the Brand API’s response, use the Extract API. It crawls the company’s website, runs an LLM over the pages, and returns values matching a JSON Schema you provide: describe each field you need (e.g., “Do they have referral rewards?”) and get typed answers in response. Add this to your server, right after the Brand API enrichment:
// After enrichLead() returns: pull a custom datapoint and attach it to the write-back.
const { data } = await client.web.extract({
  url: `https://${fields.website}`,
  schema: {
    type: "object",
    properties: {
      pricing_model: {
        type: "string",
        description: "How the product is priced: per-seat, usage-based, or flat-rate.",
      },
    },
    required: ["pricing_model"],
    additionalProperties: false,
  },
});

fields.pricingModel = data.pricing_model ?? null;
10 credits per successful call

Best practices

Enrich on create, not on read

Trigger enrichment when a lead is created or explicitly re-enriched, never on every record view. A view should read your cached columns, not fire an API call.

Prefetch for faster response

Context.dev provides a prefetch endpoint that starts the scraping for building the brand profiles when a new brand comes in that isn’t already in Context.dev’s database.
// Fire and forget at the top of the handler, before other work.
client.utility.prefetchByEmail({ email }).catch(() => {});
// ... later, when you need the data:
const data = await enrichLead(email);
See Prefetch for Faster Response for the full pattern.

Handle the misses

Common failure situations:
  1. Free or disposable email (HTTP 422). Expected. Don’t retry; you have no company domain to look up. Fall back to the rep’s typed company name.
  2. No brand found (HTTP 400, error_code: "NOT_FOUND"). The domain isn’t in Context.dev’s index. Log it and show a “could not enrich” badge; reps like to know.
  3. Cold-hit timeout (HTTP 408). Rare. Retry once with backoff, or let it fall through; the next call against that domain hits the now-warm cache.

Next steps

Retrieve by Email

Endpoint reference for the call this guide uses.

Prefetch for Faster Response

Hide cold-hit latency from your create-record handler.

Onboarding Flows

The same enrichment pattern, applied to in-product signup forms.

Classify Brands by Industry

Choosing between EIC, NAICS, and SIC for lead segmentation.