Skip to content

Commit 98e28aa

Browse files
ryanioclaude
andauthored
Add Search API endpoint (#1918)
* Add Search API endpoint and bump version to 8.0.17 Add search endpoint for discovering collections, tokens, NFTs, and accounts with support for chain and asset type filtering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add search endpoint integration tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ac882fb commit 98e28aa

7 files changed

Lines changed: 428 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opensea-js",
3-
"version": "8.0.16",
3+
"version": "8.0.17",
44
"description": "TypeScript SDK for the OpenSea marketplace helps developers build new experiences using NFTs and our marketplace data",
55
"license": "MIT",
66
"author": "OpenSea Developers",

src/api/api.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { EventsAPI } from "./events";
66
import { ListingsAPI } from "./listings";
77
import { NFTsAPI } from "./nfts";
88
import { OffersAPI } from "./offers";
9+
import { SearchAPI } from "./search";
910
import { TokensAPI } from "./tokens";
1011
import {
1112
FulfillmentDataResponse,
@@ -50,6 +51,8 @@ import {
5051
GetSwapQuoteArgs,
5152
GetSwapQuoteResponse,
5253
GetTokenResponse,
54+
SearchArgs,
55+
SearchResponse,
5356
} from "./types";
5457
import { executeWithRateLimit } from "../utils/rateLimit";
5558

@@ -82,6 +85,7 @@ export class OpenSeaAPI {
8285
private nftsAPI: NFTsAPI;
8386
private accountsAPI: AccountsAPI;
8487
private eventsAPI: EventsAPI;
88+
private searchAPI: SearchAPI;
8589
private tokensAPI: TokensAPI;
8690

8791
/**
@@ -116,6 +120,7 @@ export class OpenSeaAPI {
116120
this.nftsAPI = new NFTsAPI(fetcher, this.chain);
117121
this.accountsAPI = new AccountsAPI(fetcher, this.chain);
118122
this.eventsAPI = new EventsAPI(fetcher);
123+
this.searchAPI = new SearchAPI(fetcher);
119124
this.tokensAPI = new TokensAPI(fetcher);
120125
}
121126

@@ -705,6 +710,16 @@ export class OpenSeaAPI {
705710
return this.tokensAPI.getToken(chain, address);
706711
}
707712

713+
/**
714+
* Search across collections, tokens, NFTs, and accounts.
715+
* Results are ranked by relevance.
716+
* @param args Query parameters including query text, optional chain/asset type filters, and limit.
717+
* @returns The {@link SearchResponse} returned by the API.
718+
*/
719+
public async search(args: SearchArgs): Promise<SearchResponse> {
720+
return this.searchAPI.search(args);
721+
}
722+
708723
/**
709724
* Gets all active offers for a specific NFT (not just the best offer).
710725
* @param assetContractAddress The NFT contract address.

src/api/apiPaths.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,7 @@ export const getSwapQuotePath = () => {
159159
export const getTokenPath = (chain: string, address: string) => {
160160
return `/api/v2/chain/${chain}/token/${address}`;
161161
};
162+
163+
export const getSearchPath = () => {
164+
return "/api/v2/search";
165+
};

src/api/search.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { getSearchPath } from "./apiPaths";
2+
import { Fetcher } from "./fetcher";
3+
import { SearchArgs, SearchResponse } from "./types";
4+
5+
/**
6+
* Search-related API operations
7+
*/
8+
export class SearchAPI {
9+
constructor(private fetcher: Fetcher) {}
10+
11+
/**
12+
* Search across collections, tokens, NFTs, and accounts.
13+
*/
14+
async search(args: SearchArgs): Promise<SearchResponse> {
15+
const response = await this.fetcher.get<SearchResponse>(
16+
getSearchPath(),
17+
args,
18+
);
19+
return response;
20+
}
21+
}

src/api/types.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,3 +756,120 @@ export type GetSwapQuoteResponse = {
756756
* @category API Response Types
757757
*/
758758
export type GetTokenResponse = Token;
759+
760+
/**
761+
* Query args for the Search endpoint.
762+
* @category API Query Args
763+
*/
764+
export interface SearchArgs {
765+
/** Search query text */
766+
query: string;
767+
/** Filter by blockchain(s) */
768+
chains?: string[];
769+
/** Filter by asset type(s): collection, nft, token, account */
770+
asset_types?: string[];
771+
/** Number of results to return (default: 20, max: 50) */
772+
limit?: number;
773+
}
774+
775+
/**
776+
* Collection search result.
777+
* @category API Models
778+
*/
779+
export type CollectionSearchResult = {
780+
/** The collection slug */
781+
collection: string;
782+
/** The collection name */
783+
name: string;
784+
/** URL of the collection image */
785+
image_url: string | null;
786+
/** Whether trading is disabled for this collection */
787+
is_disabled: boolean;
788+
/** Whether this collection is marked as NSFW */
789+
is_nsfw: boolean;
790+
/** URL to the collection on OpenSea */
791+
opensea_url: string;
792+
};
793+
794+
/**
795+
* Token (currency) search result.
796+
* @category API Models
797+
*/
798+
export type TokenSearchResult = {
799+
/** Contract address of the token */
800+
address: string;
801+
/** Blockchain the token is on */
802+
chain: string;
803+
/** Token name */
804+
name: string;
805+
/** Token symbol */
806+
symbol: string;
807+
/** URL of the token image */
808+
image_url: string | null;
809+
/** Current USD price of the token */
810+
usd_price: string;
811+
/** Number of decimal places for the token */
812+
decimals: number;
813+
/** URL to the token on OpenSea */
814+
opensea_url: string;
815+
};
816+
817+
/**
818+
* NFT search result.
819+
* @category API Models
820+
*/
821+
export type NftSearchResult = {
822+
/** Token ID of the NFT */
823+
identifier: string;
824+
/** Collection slug the NFT belongs to */
825+
collection: string;
826+
/** Contract address of the NFT */
827+
contract: string;
828+
/** Name of the NFT */
829+
name: string | null;
830+
/** URL of the NFT image */
831+
image_url: string | null;
832+
/** URL to the NFT on OpenSea */
833+
opensea_url: string;
834+
};
835+
836+
/**
837+
* Account search result.
838+
* @category API Models
839+
*/
840+
export type AccountSearchResult = {
841+
/** Primary wallet address of the account */
842+
address: string;
843+
/** Username of the account */
844+
username: string | null;
845+
/** URL of the account's profile image */
846+
profile_image_url: string | null;
847+
/** URL to the account on OpenSea */
848+
opensea_url: string;
849+
};
850+
851+
/**
852+
* A single search result with a type discriminator and the corresponding typed object.
853+
* @category API Models
854+
*/
855+
export type SearchResult = {
856+
/** The type of search result */
857+
type: string;
858+
/** Collection details, present when type is 'collection' */
859+
collection?: CollectionSearchResult;
860+
/** Token details, present when type is 'token' */
861+
token?: TokenSearchResult;
862+
/** NFT details, present when type is 'nft' */
863+
nft?: NftSearchResult;
864+
/** Account details, present when type is 'account' */
865+
account?: AccountSearchResult;
866+
};
867+
868+
/**
869+
* Response from OpenSea API for search.
870+
* @category API Response Types
871+
*/
872+
export type SearchResponse = {
873+
/** List of search results ranked by relevance */
874+
results: SearchResult[];
875+
};

0 commit comments

Comments
 (0)