Skip to content

Search Client

This page describes the Search API for indexing and searching provenance claims and accounts through Royal’s infrastructure. For authentication details, please refer to the Authentication page, and for overall API best practices, see API Guidelines.

Overview

The Search API enables you to:

  • Search for provenance claims by content hash, name, or other metadata
  • Search for accounts by username or ID
  • Perform combined searches across multiple entity types
  • Paginate through search results

Prerequisites

Before you can use the Search API, you need to:

Quick Start

  1. Install the required dependency:
Terminal window
npm install typesense --save-dev
  1. Copy the SearchClient to your project.

  2. Create a client instance and perform a basic search:

const API_KEY = "ryl_sk_YOUR_SECRET_KEY";
const client = new SearchClient({ apiKey: API_KEY });
// Search across all entity types
const searchResult = await client.searchAll("Alice");
// Search just for accounts
const accountResults = await client.searchAccounts("Alice");
// Search just for provenance claims
const claimResults = await client.searchClaims("Artwork");

Client Configuration

Class: SearchClient

The SearchClient provides an interface for searching provenance claims and accounts. For the complete implementation, see the search client source code.

Constructor

constructor(host: string, apiKey?: string, rawResponses = false)
ParameterTypeRequiredDescription
hoststringYesThe base URL for the Royal API (e.g., “https://api.royal.io 🔗”)
apiKeystringYesYour Royal API key for authentication
rawResponsesbooleanNoWhether to return raw API responses (default: false)

API Methods

Search All Entities

searchAll(q = '', page = 1, perPage = 10)

Searches across all entity types (accounts and provenance claims).

Parameters

ParameterTypeRequiredDescription
qstringNoThe search query term
pagenumberNoPage number for pagination (default: 1)
perPagenumberNoResults per page (default: 10)

Response

Returns a PerformSearchResponse containing matching accounts and provenance claims.

Search Accounts

searchAccounts(q = '', page = 1, perPage = 10)

Searches only for accounts.

Parameters

ParameterTypeRequiredDescription
qstringNoThe search query term
pagenumberNoPage number for pagination (default: 1)
perPagenumberNoResults per page (default: 10)

Response

Returns a PerformSearchResponse containing matching account records.

Search Provenance Claims

searchClaims(q = '', page = 1, perPage = 10)

Searches only for provenance claims.

Parameters

ParameterTypeRequiredDescription
qstringNoThe search query term
pagenumberNoPage number for pagination (default: 1)
perPagenumberNoResults per page (default: 10)

Response

Returns a PerformSearchResponse containing matching provenance claim records.

Advanced Use Cases

performSearch<T>(searchParameters, options = {})

Performs a customized search with full control over search parameters.

Parameters

ParameterTypeRequiredDescription
searchParametersSearchParams or SearchParamsWithPresetYesTypesense search parameters
optionsSearchOptionsNoAdditional search options

Response

Returns a PerformSearchResponse<T> containing the search results.

Best Practices

While you can use the performSearch method directly with search parameters from the Typesense documentation 🔗, we strongly recommend creating specific search functions within your application by extending the class or following the pattern of the built-in methods.

This approach improves code readability, maintainability, and reusability. Here are examples of custom search functions you might implement:

Example: Search for User Claims on a Specific Registrar
public async searchUserClaimsOnRegistrar(ORIGINATOR_ID: number | string | bigint, page = 1) {
const params = {
q: "*",
query_by: "originatorId,registrarId",
filter_by: `type:provenanceClaim && originatorId:${ORIGINATOR_ID} && registrarId:${YOUR_APP_REGISTRAR_ID}`,
sort_by: "psqlId:desc",
};
return this.performSearch<ProvenanceClaimDocumentType>(params);
}
Example: Search by Content Hash
public async searchByContentHash(contentHash: string) {
const params = {
q: contentHash.toLowerCase(),
query_by: "contentHash",
filter_by: `type:provenanceClaim`,
};
return this.performSearch<ProvenanceClaimDocumentType>(params);
}

Proxying Client-Side Calls

When building client-side applications, it’s best practice to avoid exposing your API keys directly in browser code. You can create a server-side proxy endpoint to handle search requests securely.

Server Implementation

Create a server endpoint to proxy search requests:

app/api/search/route.ts
import { SearchClient } from '@royal/protocol-client';
import { NextRequest } from 'next/server';
/**
* Since this code would be running on the server, you can
* use your Secret Key without any issues
*/
const API_KEY = "ryl_sk_YOUR_SECRET_KEY";
const client = new SearchClient({ apiKey: API_KEY });
export async function POST(request: NextRequest) {
const data = (await request.json()) as {
searchParameters: SearchParams | SearchParamsWithPreset;
options: SearchOptions;
};
const result = await client.performSearch(
data.searchParameters,
data.options,
);
return Response.json(result, { status: 200 });
}
Client Implementation

Configure the client to use your internal API endpoint:

app/client-side/page.tsx
import { SearchClient } from '@royal/protocol-client';
import { useState } from 'react';
/**
* This code would run on the client side, and we don't
* want to expose the API key, so we create the client
* and set the host to our internal endpoint to proxy the
* calls.
*
* We also set the `rawResponses` attribute to true because
* the server-side client is already parsing the responses
*/
const client = new SearchClient({
host: "https://mysiteurl/api/search",
rawResponses: true
});
export const MyClientSidePage = () => {
const [results, setResults] = useState([]);
const search = async (query: string) => {
const { data } = await client.searchAll(query);
setResults(data);
}
return (
<>
<input onChange={(evt) => search(evt.target.value)} />
<ul>
{results.map((item) => (
<li key={item.id}>Claim {item.psqlId}</li>
))}
</ul>
</>
);
}

This pattern ensures your API key remains secure on your server while still allowing client-side applications to perform searches through your proxy endpoint.

Response Types

PerformSearchResponse

type PerformSearchResponse<T> = {
data: T[]; // Array of matching documents
total: number; // Total number of matching results
numPages: number; // Total number of pages
};

AccountDocumentType

type AccountDocumentType = {
type: "account";
id: string;
psqlId: string;
username: string;
custody: string;
provenanceClaimCount: number;
originatedProvenanceClaimCount: number;
registeredProvenanceClaimCount: number;
dayBucket: number;
hourBucket: number;
recovery: string;
createdAt: string;
updatedAt: string;
};

ProvenanceClaimDocumentType

type ProvenanceClaimDocumentType = {
type: 'provenanceClaim';
id: string;
psqlId: string;
originatorAddress: string;
originatorId: string;
originatorUsername: string;
registrarAddress: string;
registrarId: string;
registrarUsername: string;
blockNumber: string;
contentHash: string;
transactionHash: string;
transactionIndex: number;
nftContract?: string;
nftTokenId?: string;
dayBucket: number;
hourBucket: number;
metadata?: Record<string, any> & {
name?: string;
description?: string;
image?: string;
animation_url?: string;
external_url?: string;
attributes?: Array<any>;
royal?: {
provenance?: {
attributes?: Array<any>;
content_hash?: string;
file_locations?: Array<{
url: string;
}>;
title?: string;
};
};
};
createdAt: string;
updatedAt: string;
};

Error Handling

When a search fails, the client will return a response with empty data:

{
data: [],
total: 0,
numPages: 0
}

Additional Information

For complete API integration tips, please refer to the API Guidelines. To examine the full implementation of the search client, see the SearchClient class.


Note: This documentation covers only the Search API for querying provenance claims and accounts. For information about registering new claims, please see the Registration section.