// Vayne API integration // Docs: https://www.vayne.io (OpenAPI spec available at /api endpoint) // Auth: Authorization: Bearer // Base URL: https://www.vayne.io // // Flow: // 1. POST /api/orders with { url, limit, name, email_enrichment: false, export_format: "simple" } // 2. Poll GET /api/orders/{id} until scraping_status === "finished" | "failed" // 3. POST /api/orders/{id}/export with { export_format: "simple" } // 4. Poll GET /api/orders/{id} until exports[0].status === "completed" // 5. Download CSV from exports[0].file_url (S3 presigned URL) import axios from "axios"; import Papa from "papaparse"; const BASE_URL = "https://www.vayne.io"; export interface VayneOrder { id: number; name: string; order_type: string; scraping_status: "initialization" | "pending" | "segmenting" | "scraping" | "finished" | "failed"; limit: number; scraped: number; created_at: string; exports?: Array<{ status: "completed" | "pending" | "not_started"; file_url?: string }>; } export interface LeadProfile { firstName: string; lastName: string; fullName: string; title: string; company: string; companyDomain: string; linkedinUrl: string; location: string; } export async function createOrder( salesNavUrl: string, maxResults: number, apiToken: string, orderName?: string ): Promise { const response = await axios.post( `${BASE_URL}/api/orders`, { url: salesNavUrl, limit: maxResults, name: orderName || `OnyvaLeads-${Date.now()}`, email_enrichment: false, export_format: "simple", }, { headers: { Authorization: `Bearer ${apiToken}`, "Content-Type": "application/json", }, timeout: 30000, } ); return response.data.order; } export async function getOrderStatus( orderId: number, apiToken: string ): Promise { const response = await axios.get(`${BASE_URL}/api/orders/${orderId}`, { headers: { Authorization: `Bearer ${apiToken}` }, timeout: 15000, }); return response.data.order; } export async function triggerExport( orderId: number, apiToken: string ): Promise { const response = await axios.post( `${BASE_URL}/api/orders/${orderId}/export`, { export_format: "simple" }, { headers: { Authorization: `Bearer ${apiToken}`, "Content-Type": "application/json", }, timeout: 15000, } ); return response.data.order; } export async function downloadOrderCSV( fileUrl: string ): Promise { const response = await axios.get(fileUrl, { timeout: 60000, responseType: "text", }); return parseVayneCSV(response.data); } function parseVayneCSV(csvContent: string): LeadProfile[] { const { data } = Papa.parse>(csvContent, { header: true, skipEmptyLines: true, }); return data.map((row) => { // Vayne simple format columns (may vary; handle common variants) const fullName = row["Name"] || row["Full Name"] || row["full_name"] || ""; const nameParts = fullName.trim().split(/\s+/); const firstName = nameParts[0] || ""; const lastName = nameParts.slice(1).join(" ") || ""; // Extract domain from company URL or website column const companyUrl = row["Company URL"] || row["company_url"] || row["Website"] || ""; let companyDomain = ""; if (companyUrl) { try { const u = new URL(companyUrl.startsWith("http") ? companyUrl : `https://${companyUrl}`); companyDomain = u.hostname.replace(/^www\./i, ""); } catch { companyDomain = companyUrl.replace(/^www\./i, "").split("/")[0]; } } return { firstName, lastName, fullName, title: row["Job Title"] || row["Title"] || row["title"] || "", company: row["Company"] || row["Company Name"] || row["company"] || "", companyDomain, linkedinUrl: row["LinkedIn URL"] || row["linkedin_url"] || row["Profile URL"] || "", location: row["Location"] || row["location"] || "", }; }); } export async function checkLinkedInAuth(apiToken: string): Promise { try { const response = await axios.get(`${BASE_URL}/api/linkedin/status`, { headers: { Authorization: `Bearer ${apiToken}` }, timeout: 10000, }); return response.data?.connected === true; } catch { return false; } }