← back to Ventura Claw

server/connectors/hubspot.js

41 lines

// HubSpot — REAL. Private-app token (pat-na1-...) is simplest.
const API = "https://api.hubapi.com";
function token(c) {
  const t = c?.HUBSPOT_TOKEN || process.env.HUBSPOT_TOKEN;
  if (!t) throw new Error("HUBSPOT_TOKEN not set");
  return t;
}
async function call(method, path, body, c) {
  const r = await fetch(`${API}${path}`, {
    method, headers: { "Authorization": `Bearer ${token(c)}`, "Content-Type": "application/json" },
    body: body ? JSON.stringify(body) : undefined
  });
  const d = r.status === 204 ? {} : await r.json();
  if (!r.ok) throw new Error(`hubspot ${path} ${r.status}: ${d.message || JSON.stringify(d).slice(0,200)}`);
  return d;
}
module.exports = {
  meta: { id: "hubspot", name: "HubSpot", category: "crm", docsUrl: "https://developers.hubspot.com/docs/api/overview", auth: "oauth2", realImpl: true },
  fields: [{ key: "HUBSPOT_TOKEN", label: "Private App Token", type: "password", required: true, hint: "pat-na1-... — Settings > Integrations > Private Apps" }],
  configured(c) { return !!(c?.HUBSPOT_TOKEN || process.env.HUBSPOT_TOKEN); },
  async health(c) {
    if (!this.configured(c)) return { ok: false, reason: "no_token" };
    try { const d = await call("GET", "/crm/v3/owners?limit=1", null, c); return { ok: true, owners_total: d.results?.length || 0 }; }
    catch (e) { return { ok: false, reason: e.message }; }
  },
  actions: {
    async "contacts.list"({ limit }, c) { return call("GET", `/crm/v3/objects/contacts?limit=${limit||20}`, null, c); },
    async "contact.upsert"({ email, firstname, lastname, phone, company }, c) {
      const props = { email, firstname, lastname, phone, company };
      Object.keys(props).forEach(k => props[k] === undefined && delete props[k]);
      return call("POST", "/crm/v3/objects/contacts", { properties: props }, c);
    },
    async "deals.list"({ limit }, c)    { return call("GET", `/crm/v3/objects/deals?limit=${limit||20}`, null, c); },
    async "deal.create"({ dealname, amount, dealstage, pipeline, hubspot_owner_id }, c) {
      const props = { dealname, amount, dealstage, pipeline, hubspot_owner_id };
      Object.keys(props).forEach(k => props[k] === undefined && delete props[k]);
      return call("POST", "/crm/v3/objects/deals", { properties: props }, c);
    }
  }
};