openapi: 3.0.3 info: title: Surfe API version: '2.0' description: >- The Surfe API (formerly Leadjet) provides B2B people and company search plus enrichment. It returns verified professional emails and mobile phone numbers, company firmographics, and lookalike account recommendations. Bulk enrichment is asynchronous: start a job with POST and either poll the GET job endpoint or receive a webhook callback. All requests are authenticated with a Bearer API key managed from the Surfe dashboard. contact: name: Surfe API Support url: https://developers.surfe.com/ x-former-name: Leadjet servers: - url: https://api.surfe.com/v2 description: Surfe API v2 production base URL security: - bearerAuth: [] tags: - name: People description: Search and enrich individual contacts. - name: Companies description: Search and enrich organizations. - name: Recommendations description: ICP definition and lookalike account recommendations. - name: Account description: Credit balance and account utilities. paths: /people/search: post: tags: - People summary: Search people description: >- Search for people by persona filters (job titles, seniorities, departments) and company filters (industry, headcount, location). Job titles are expanded automatically with acronym and semantic matching. Results are paged with nextPageToken. operationId: searchPeople requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PeopleSearchRequest' responses: '200': description: Matching people. content: application/json: schema: $ref: '#/components/schemas/PeopleSearchResponse' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' '429': $ref: '#/components/responses/RateLimited' /people/enrich: post: tags: - People summary: Enrich people (start) description: >- Start an asynchronous bulk enrichment job for up to 10,000 people. Each person is identified by a LinkedIn URL, or by first name + last name + company name or domain. Returns an enrichment ID for polling or a webhook callback. operationId: startPeopleEnrichment requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PeopleEnrichmentRequest' responses: '202': description: Enrichment job accepted. content: application/json: schema: $ref: '#/components/schemas/EnrichmentJobAccepted' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' '429': $ref: '#/components/responses/RateLimited' /people/enrich/{id}: get: tags: - People summary: Enrich people (get) description: >- Retrieve the status and results of a people enrichment job by ID. Poll until status is COMPLETED, or use a webhook to be notified. operationId: getPeopleEnrichment parameters: - name: id in: path required: true description: The enrichment job ID returned by the start operation. schema: type: string format: uuid responses: '200': description: Enrichment job status and enriched people. content: application/json: schema: $ref: '#/components/schemas/PeopleEnrichmentResult' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' /people/find-by-email: post: tags: - People summary: Find people by email description: >- Enrich people directly from a list of email addresses, returning the matched person profile and firmographics where available. operationId: findPeopleByEmail requestBody: required: true content: application/json: schema: type: object required: - emails properties: emails: type: array items: type: string format: email description: Email addresses to enrich. responses: '200': description: Matched people. content: application/json: schema: type: object properties: people: type: array items: $ref: '#/components/schemas/EnrichedPerson' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /companies/search: post: tags: - Companies summary: Search companies description: >- Search for companies against Ideal Customer Profile filters (industry, employee count, revenue, location, keywords). When credit charging is enabled the call deducts ICP search credits and returns 402 when the balance is insufficient. operationId: searchCompanies requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompanySearchRequest' responses: '200': description: Matching companies. content: application/json: schema: $ref: '#/components/schemas/CompanySearchResponse' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' '429': $ref: '#/components/responses/RateLimited' /companies/enrich: post: tags: - Companies summary: Enrich companies (start) description: >- Start an asynchronous bulk enrichment job for companies identified by domain. Returns an enrichment ID for polling or a webhook callback. operationId: startCompanyEnrichment requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompanyEnrichmentRequest' responses: '202': description: Enrichment job accepted. content: application/json: schema: $ref: '#/components/schemas/EnrichmentJobAccepted' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' '429': $ref: '#/components/responses/RateLimited' /companies/enrich/{id}: get: tags: - Companies summary: Enrich companies (get) description: >- Retrieve the status and results of a company enrichment job by ID. Poll until status is COMPLETED, or use a webhook to be notified. operationId: getCompanyEnrichment parameters: - name: id in: path required: true description: The enrichment job ID returned by the start operation. schema: type: string format: uuid responses: '200': description: Enrichment job status and enriched companies. content: application/json: schema: $ref: '#/components/schemas/CompanyEnrichmentResult' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' /recommendations/icp: post: tags: - Recommendations summary: Create or update ICP description: >- Create or update the Ideal Customer Profile used to generate lookalike account recommendations. operationId: upsertICP requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ICPDefinition' responses: '200': description: ICP saved. content: application/json: schema: $ref: '#/components/schemas/ICPDefinition' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /recommendations/fetch: post: tags: - Recommendations summary: Fetch lookalike recommendations description: >- Fetch lookalike account recommendations resembling the best-fit companies defined by the ICP. operationId: fetchRecommendations requestBody: required: true content: application/json: schema: type: object properties: limit: type: integer minimum: 1 maximum: 200 description: Maximum number of recommendations to return. pageToken: type: string description: Pagination token from a previous response. responses: '200': description: Lookalike company recommendations. content: application/json: schema: type: object properties: companies: type: array items: $ref: '#/components/schemas/Company' nextPageToken: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /credits: get: tags: - Account summary: Get credit balance description: >- Return the remaining credit balance across the email, mobile, and search/ICP credit pools. operationId: getCredits responses: '200': description: Current credit balances. content: application/json: schema: $ref: '#/components/schemas/CreditBalance' '401': $ref: '#/components/responses/Unauthorized' components: securitySchemes: bearerAuth: type: http scheme: bearer description: >- Surfe API key issued from the Surfe dashboard, sent as `Authorization: Bearer {api-key}`. responses: Unauthorized: description: Missing or invalid API key. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: Resource or job not found. content: application/json: schema: $ref: '#/components/schemas/Error' InsufficientCredits: description: Not enough credits to complete the request. content: application/json: schema: $ref: '#/components/schemas/Error' RateLimited: description: >- Too many requests. The API allows up to 10 requests per second with short bursts to 20, plus a daily request quota. content: application/json: schema: $ref: '#/components/schemas/Error' schemas: Error: type: object properties: message: type: string code: type: string PeopleFilters: type: object description: Person-based filters. properties: jobTitles: type: array items: type: string description: >- Job titles to match. Titles are expanded automatically with bidirectional acronym and semantic matching. seniorities: type: array items: type: string departments: type: array items: type: string countries: type: array items: type: string CompanyFilters: type: object description: Company-based filters. properties: industries: type: array items: type: string employeeCount: $ref: '#/components/schemas/Range' revenue: $ref: '#/components/schemas/Range' countries: type: array items: type: string domains: type: array items: type: string keywords: type: array items: type: string Range: type: object properties: from: type: integer to: type: integer PeopleSearchRequest: type: object required: - limit properties: limit: type: integer minimum: 1 maximum: 200 description: Maximum results per page. people: $ref: '#/components/schemas/PeopleFilters' companies: $ref: '#/components/schemas/CompanyFilters' peoplePerCompany: type: integer minimum: 1 maximum: 5 description: Maximum results returned per company. pageToken: type: string description: Pagination token from a previous response. PeopleSearchResponse: type: object properties: people: type: array items: $ref: '#/components/schemas/Person' total: type: integer nextPageToken: type: string Person: type: object properties: firstName: type: string lastName: type: string jobTitle: type: string seniorities: type: array items: type: string departments: type: array items: type: string companyName: type: string companyDomain: type: string country: type: string linkedInUrl: type: string externalID: type: string PeopleEnrichmentRequest: type: object required: - people - include properties: people: type: array minItems: 1 maxItems: 10000 description: >- People to enrich. Each entry needs at least a linkedinUrl, or firstName + lastName + companyName or companyDomain. items: $ref: '#/components/schemas/PersonInput' include: type: object description: Which fields to retrieve. properties: email: type: boolean mobile: type: boolean linkedInUrl: type: boolean jobHistory: type: boolean enrichmentOptions: type: object properties: acceptedEmailType: type: string enum: - professional - personal skipMobileEnrichmentIfNoEmailFound: type: boolean notificationOptions: type: object properties: webhookUrl: type: string format: uri PersonInput: type: object properties: linkedinUrl: type: string firstName: type: string lastName: type: string companyName: type: string companyDomain: type: string externalID: type: string EnrichmentJobAccepted: type: object properties: enrichmentID: type: string format: uuid enrichmentCallbackURL: type: string format: uri message: type: string description: Estimated completion time. PeopleEnrichmentResult: type: object properties: enrichmentID: type: string format: uuid status: $ref: '#/components/schemas/JobStatus' percentCompleted: type: integer people: type: array items: $ref: '#/components/schemas/EnrichedPerson' EnrichedPerson: allOf: - $ref: '#/components/schemas/Person' - type: object properties: emails: type: array items: $ref: '#/components/schemas/EmailRecord' mobilePhones: type: array items: $ref: '#/components/schemas/PhoneRecord' jobHistory: type: array items: $ref: '#/components/schemas/JobHistoryEntry' status: type: string EmailRecord: type: object properties: email: type: string format: email type: type: string enum: - professional - personal validationStatus: type: string PhoneRecord: type: object properties: mobilePhone: type: string confidenceScore: type: number JobHistoryEntry: type: object properties: companyName: type: string companyDomain: type: string jobTitle: type: string startDate: type: string endDate: type: string CompanySearchRequest: type: object required: - filters - limit properties: limit: type: integer minimum: 1 maximum: 200 filters: $ref: '#/components/schemas/CompanyFilters' pageToken: type: string CompanySearchResponse: type: object properties: companies: type: array items: $ref: '#/components/schemas/Company' total: type: integer nextPageToken: type: string CompanyEnrichmentRequest: type: object required: - companies properties: companies: type: array minItems: 1 description: Companies to enrich, identified by domain and/or externalID. items: type: object properties: domain: type: string externalID: type: string include: type: object properties: firmographics: type: boolean phoneNumbers: type: boolean notificationOptions: type: object properties: webhookUrl: type: string format: uri CompanyEnrichmentResult: type: object properties: enrichmentID: type: string format: uuid status: $ref: '#/components/schemas/JobStatus' percentCompleted: type: integer companies: type: array items: $ref: '#/components/schemas/Company' Company: type: object properties: name: type: string domain: type: string websites: type: array items: type: string description: type: string industry: type: string keywords: type: array items: type: string employeeCount: type: integer revenue: type: string founded: type: integer hqCountry: type: string hqAddress: type: string linkedInUrl: type: string linkedInFollowersCount: type: integer phones: type: array items: type: string isPublic: type: boolean stockExchange: type: string stockSymbol: type: string fundingRounds: type: array items: type: object properties: type: type: string amount: type: number date: type: string parentOrganization: type: string externalID: type: string status: type: string ICPDefinition: type: object properties: name: type: string filters: $ref: '#/components/schemas/CompanyFilters' CreditBalance: type: object properties: emailCredits: type: integer mobileCredits: type: integer searchCredits: type: integer JobStatus: type: string enum: - PENDING - IN_PROGRESS - COMPLETED - FAILED