Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.15.5] - 2026-07-07

### Added

- Add Leboncoin Scraper API client (France) — 10 endpoints.

## [0.15.4] - 2026-07-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "scrapebadger",
"version": "0.15.4",
"version": "0.15.5",
"description": "Official Node.js SDK for ScrapeBadger - Async web scraping APIs for Twitter, Google, Vinted, Reddit, and more",
"type": "module",
"main": "./dist/index.js",
Expand Down
5 changes: 5 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { TikTokClient } from "./tiktok/client.js";
import { EbayClient } from "./ebay/client.js";
import { YoutubeClient } from "./youtube/client.js";
import { RealtorClient } from "./realtor/client.js";
import { LeboncoinClient } from "./leboncoin/client.js";

/**
* ScrapeBadger API client.
Expand Down Expand Up @@ -86,6 +87,9 @@ export class ScrapeBadger {
/** Realtor scraper API client — 4 endpoints across 2 markets (us, ca) */
readonly realtor: RealtorClient;

/** Leboncoin scraper API client — 10 endpoints (France) */
readonly leboncoin: LeboncoinClient;

/**
* Create a new ScrapeBadger client.
*
Expand Down Expand Up @@ -136,5 +140,6 @@ export class ScrapeBadger {
this.ebay = new EbayClient(this.baseClient);
this.youtube = new YoutubeClient(this.baseClient);
this.realtor = new RealtorClient(this.baseClient);
this.leboncoin = new LeboncoinClient(this.baseClient);
}
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export * from "./ebay/index.js";
export * from "./youtube/index.js";
export * from "./realtor/index.js";

// Re-export Leboncoin module — LeboncoinClient + Leboncoin*-prefixed sub-clients and types
export * from "./leboncoin/index.js";

// Re-export Google module — GoogleClient is exposed directly; sub-clients
// are aliased with a Google* prefix to avoid collisions with other modules
// (e.g. Twitter also has a TrendsClient).
Expand Down
63 changes: 63 additions & 0 deletions src/leboncoin/ads.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Leboncoin Ads API client.
*
* Provides methods for fetching a single ad's detail and the ads Leboncoin
* surfaces as similar to it.
*/

import type { BaseClient } from "../internal/client.js";
import type {
LeboncoinSimilarParams,
AdResponse,
SimilarResponse,
} from "./types.js";

/**
* Client for Leboncoin ad endpoints (detail, similar).
*
* @example
* ```typescript
* const client = new ScrapeBadger({ apiKey: "key" });
*
* const detail = await client.leboncoin.ads.get(2934857123);
* console.log(detail.ad.subject);
*
* const similar = await client.leboncoin.ads.similar(2934857123);
* console.log(`${similar.ads.length} similar ads`);
* ```
*/
export class AdsClient {
private readonly client: BaseClient;

constructor(client: BaseClient) {
this.client = client;
}

/**
* Get a single Leboncoin ad's full detail.
*
* @param listId - The Leboncoin ad list id.
* @returns Ad detail response.
* @throws NotFoundError - If the ad doesn't exist.
*/
async get(listId: number | string): Promise<AdResponse> {
return this.client.request<AdResponse>(`/v1/leboncoin/ads/${listId}`);
}

/**
* Get the ads Leboncoin surfaces as similar to a given ad.
*
* @param listId - The Leboncoin ad list id.
* @param options - Optional parameters (limit).
* @returns Similar-ads response.
*/
async similar(
listId: number | string,
options: LeboncoinSimilarParams = {}
): Promise<SimilarResponse> {
return this.client.request<SimilarResponse>(
`/v1/leboncoin/ads/${listId}/similar`,
{ params: { limit: options.limit } }
);
}
}
69 changes: 69 additions & 0 deletions src/leboncoin/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Leboncoin API client.
*
* Provides access to all Leboncoin API endpoints through specialized
* sub-clients.
*/

import type { BaseClient } from "../internal/client.js";
import { SearchClient } from "./search.js";
import { AdsClient } from "./ads.js";
import { SellersClient } from "./sellers.js";
import { ReferenceClient } from "./reference.js";

/**
* Leboncoin API client with access to all Leboncoin endpoints.
*
* Provides sub-clients for different resource types:
* - `search` - Ad search across the single France marketplace
* - `ads` - Ad detail and similar ads
* - `sellers` - Seller profile and their active listings
* - `reference` - Reference data (categories, regions, departments,
* location autocomplete, markets)
*
* @example
* ```typescript
* const client = new ScrapeBadger({ apiKey: "key" });
*
* // Search ads
* const results = await client.leboncoin.search.search({ text: "velo" });
*
* // Get an ad
* const ad = await client.leboncoin.ads.get(2934857123);
*
* // Similar ads
* const similar = await client.leboncoin.ads.similar(2934857123);
*
* // Seller profile + listings
* const seller = await client.leboncoin.sellers.get("a1b2c3d4-...");
* const listings = await client.leboncoin.sellers.listings("a1b2c3d4-...");
*
* // Reference data
* const { categories } = await client.leboncoin.reference.categories();
* ```
*/
export class LeboncoinClient {
/** Client for ad search */
readonly search: SearchClient;

/** Client for ad detail and similar ads */
readonly ads: AdsClient;

/** Client for seller profile and listings */
readonly sellers: SellersClient;

/** Client for reference data (categories, regions, departments, locations, markets) */
readonly reference: ReferenceClient;

/**
* Create a new Leboncoin client.
*
* @param client - The base HTTP client for making requests.
*/
constructor(client: BaseClient) {
this.search = new SearchClient(client);
this.ads = new AdsClient(client);
this.sellers = new SellersClient(client);
this.reference = new ReferenceClient(client);
}
}
50 changes: 50 additions & 0 deletions src/leboncoin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Leboncoin API module.
*
* @module leboncoin
*/

export { LeboncoinClient } from "./client.js";
export { SearchClient as LeboncoinSearchClient } from "./search.js";
export { AdsClient as LeboncoinAdsClient } from "./ads.js";
export { SellersClient as LeboncoinSellersClient } from "./sellers.js";
export { ReferenceClient as LeboncoinReferenceClient } from "./reference.js";

// Export all types
export type {
// Ad building blocks
Attribute as LeboncoinAttribute,
Location as LeboncoinLocation,
Owner as LeboncoinOwner,
Images as LeboncoinImages,
Ad as LeboncoinAd,
// Seller / store
FeedbackScores as LeboncoinFeedbackScores,
StoreRatingReview as LeboncoinStoreRatingReview,
Seller as LeboncoinSeller,
// Reference
Category as LeboncoinCategory,
Region as LeboncoinRegion,
Department as LeboncoinDepartment,
LocationSuggestion as LeboncoinLocationSuggestion,
// Response envelopes
SearchResponse as LeboncoinSearchResponse,
AdResponse as LeboncoinAdResponse,
SimilarResponse as LeboncoinSimilarResponse,
SellerResponse as LeboncoinSellerResponse,
SellerListingsResponse as LeboncoinSellerListingsResponse,
CategoriesResponse as LeboncoinCategoriesResponse,
RegionsResponse as LeboncoinRegionsResponse,
DepartmentsResponse as LeboncoinDepartmentsResponse,
LocationSearchResponse as LeboncoinLocationSearchResponse,
MarketsResponse as LeboncoinMarketsResponse,
// Param enums
LeboncoinOwnerType,
LeboncoinAdType,
LeboncoinSortBy,
// Request params
LeboncoinSearchParams,
LeboncoinSimilarParams,
LeboncoinSellerListingsParams,
LeboncoinDepartmentsParams,
} from "./types.js";
94 changes: 94 additions & 0 deletions src/leboncoin/reference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Leboncoin Reference Data API client.
*
* Provides the static category / region / department lists, the market list,
* and location autocomplete for building search filters.
*/

import type { BaseClient } from "../internal/client.js";
import type {
LeboncoinDepartmentsParams,
CategoriesResponse,
RegionsResponse,
DepartmentsResponse,
LocationSearchResponse,
MarketsResponse,
} from "./types.js";

/**
* Client for Leboncoin reference endpoints (categories, regions, departments,
* location autocomplete, markets).
*
* @example
* ```typescript
* const client = new ScrapeBadger({ apiKey: "key" });
*
* const { categories } = await client.leboncoin.reference.categories();
* const { regions } = await client.leboncoin.reference.regions();
* const { departments } = await client.leboncoin.reference.departments({ region_id: "12" });
* const { suggestions } = await client.leboncoin.reference.locations("Paris");
* const { markets } = await client.leboncoin.reference.markets();
* ```
*/
export class ReferenceClient {
private readonly client: BaseClient;

constructor(client: BaseClient) {
this.client = client;
}

/**
* List all Leboncoin categories.
*
* @returns Categories response.
*/
async categories(): Promise<CategoriesResponse> {
return this.client.request<CategoriesResponse>("/v1/leboncoin/categories");
}

/**
* List all Leboncoin regions.
*
* @returns Regions response.
*/
async regions(): Promise<RegionsResponse> {
return this.client.request<RegionsResponse>("/v1/leboncoin/regions");
}

/**
* List Leboncoin departments, optionally filtered by region.
*
* @param options - Optional parameters (region_id).
* @returns Departments response.
*/
async departments(
options: LeboncoinDepartmentsParams = {}
): Promise<DepartmentsResponse> {
return this.client.request<DepartmentsResponse>(
"/v1/leboncoin/departments",
{ params: { region_id: options.region_id } }
);
}

/**
* Resolve a place name to Leboncoin location ids (for building filters).
*
* @param query - Place name to resolve.
* @returns Location search response with suggestions.
*/
async locations(query: string): Promise<LocationSearchResponse> {
return this.client.request<LocationSearchResponse>(
"/v1/leboncoin/locations/search",
{ params: { q: query } }
);
}

/**
* List the supported Leboncoin markets (France is the single market).
*
* @returns Markets response.
*/
async markets(): Promise<MarketsResponse> {
return this.client.request<MarketsResponse>("/v1/leboncoin/markets");
}
}
61 changes: 61 additions & 0 deletions src/leboncoin/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Leboncoin Search API client.
*
* Provides ad search across the single France marketplace, scoped by
* category, geography, price, seller type, and ad type.
*/

import type { BaseClient } from "../internal/client.js";
import type { LeboncoinSearchParams, SearchResponse } from "./types.js";

/**
* Client for the Leboncoin search endpoint.
*
* @example
* ```typescript
* const client = new ScrapeBadger({ apiKey: "key" });
*
* const results = await client.leboncoin.search.search({ text: "velo" });
* for (const ad of results.ads) {
* console.log(`${ad.subject} — ${ad.price_eur} EUR`);
* }
* ```
*/
export class SearchClient {
private readonly client: BaseClient;

constructor(client: BaseClient) {
this.client = client;
}

/**
* Search Leboncoin classified ads.
*
* France is a single market; scope results with `region_id` /
* `department_id` / `city` (DOM-TOM are region values).
*
* @param params - Search parameters including text, filters, and pagination.
* @returns Search results with ads, totals, and pagination metadata.
* @throws AuthenticationError - If the API key is invalid.
* @throws ValidationError - If the parameters are invalid.
*/
async search(params: LeboncoinSearchParams = {}): Promise<SearchResponse> {
return this.client.request<SearchResponse>("/v1/leboncoin/search", {
params: {
text: params.text,
category: params.category,
region_id: params.region_id,
department_id: params.department_id,
city: params.city,
zipcode: params.zipcode,
price_min: params.price_min,
price_max: params.price_max,
owner_type: params.owner_type,
ad_type: params.ad_type,
sort: params.sort,
page: params.page,
limit: params.limit,
},
});
}
}
Loading
Loading