Skip to content

Repository files navigation

@inheritage-foundation/sdk

npm version npm downloads License CI TypeScript

Official TypeScript SDK for the Inheritage Foundation API
Access India's documented cultural heritage programmatically—5000+ temples, monuments, and cultural sites with zero gatekeeping, full attribution, and production-grade ergonomics.

Designed & Engineered by Ayush MishraTeam Inheritage
License: Apache 2.0 (SDK code) | Data: CC BY 4.0 (requires attribution)
API DocsSDK ReferencePlayground


✨ Why Use This SDK?

  • 🏛️ 5000+ Heritage Sites — Temples, forts, monuments, UNESCO sites across India
  • 🗺️ GeoJSON-First — Native geospatial APIs with EPSG:4326, bbox queries, nearby search
  • 🤖 AI-Ready — 1536-d embeddings, semantic search, LangChain/LangGraph adapters
  • ⚛️ React HooksuseHeritage, useAIContext with auto-caching, loading states
  • 🏛️ Museum Standards — CIDOC-CRM JSON-LD, LIDO XML, OAI-PMH for aggregators
  • 🎨 CC BY Compliance<InheritageCitation /> component for attribution
  • 📦 Tree-Shakeable — ESM/CJS dual build, zero runtime dependencies
  • 🔒 Type-Safe — Full TypeScript definitions from OpenAPI 3.1 spec
  • Smart Caching — ETag, If-None-Match, stale-while-revalidate
  • 🌐 Multi-Format — JSON, GeoJSON, NDJSON, XML, JSON-LD

📑 Table of Contents


📦 Installation

Package Managers

# npm
npm install @inheritage-foundation/sdk

# yarn
yarn add @inheritage-foundation/sdk

# pnpm
pnpm add @inheritage-foundation/sdk

# bun
bun add @inheritage-foundation/sdk

Peer Dependencies

The SDK has zero runtime dependencies except for React (optional):

{
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0"
  },
  "peerDependenciesMeta": {
    "react": {
      "optional": true
    }
  }
}

Install React only if using hooks or components:

# For React projects
npm install @inheritage-foundation/sdk react react-dom

# For Node.js / vanilla TypeScript projects (no React needed)
npm install @inheritage-foundation/sdk

CDN / ESM Import

For browser usage without bundlers:

<script type="module">
  import { InheritageClient } from 'https://esm.sh/@inheritage-foundation/sdk'
  
  const client = new InheritageClient()
  const site = await client.getHeritage('taj-mahal')
  console.log(site.data.name)
</script>

🚀 Quick Start

Basic Usage

import { InheritageClient } from '@inheritage-foundation/sdk'

const client = new InheritageClient({
  baseUrl: 'https://www.inheritage.foundation/api/v1', // optional, this is default
  attribution: 'visible', // required for CC BY 4.0 compliance
})

// Fetch a heritage site
const site = await client.getHeritage('hoysaleswara-temple')
console.log(site.data.name) // "Hoysaleswara Temple"
console.log(site.data.state) // "Karnataka"

// List heritage sites with filters
const sites = await client.listHeritage({
  state: 'Karnataka',
  category: 'Temple',
  limit: 10,
  offset: 0,
})
console.log(sites.data.data.length) // 10
console.log(sites.data.meta.total) // 450

// Nearby search (GeoJSON)
const nearby = await client.getGeoNearby({
  lat: 28.6139,
  lon: 77.2090,
  radius: 10, // km
  limit: 5,
})
console.log(nearby.data.type) // "FeatureCollection"
console.log(nearby.data.features[0].properties.name) // "Qutb Minar"

React Hooks

import { useHeritage, useAIContext, InheritageCitation } from '@inheritage-foundation/sdk'

function HeritagePage({ slug }: { slug: string }) {
  const { data, loading, error } = useHeritage(slug)
  const { data: aiContext } = useAIContext(slug)

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!data) return <div>Not found</div>

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      
      {aiContext && (
        <div>
          <h2>AI Context</h2>
          <p>{aiContext.context}</p>
          <small>Embedding dimensions: {aiContext.embedding_dimensions}</small>
        </div>
      )}
      
      <InheritageCitation citation={data.citations} display="block" showBadge />
    </div>
  )
}

AI & Semantic Search

// Get AI context and embeddings
const context = await client.getAIContext('taj-mahal')
console.log(context.data.context) // "The Taj Mahal is a 17th-century mausoleum..."
console.log(context.data.embedding.length) // 1536
console.log(context.data.embedding_checksum) // "a1b2c3d4..."

// Find similar sites
const similar = await client.findSimilar({
  slug: 'taj-mahal',
  limit: 5,
})
similar.data.data.forEach(entry => {
  console.log(`${entry.score.toFixed(3)} - ${entry.site.name}`)
})
// Output:
// 0.987 - Humayun's Tomb
// 0.954 - Red Fort
// 0.932 - Agra Fort

// Get AI metadata bundle
const metadata = await client.getAIMetadata('taj-mahal')
console.log(metadata.data.model) // "inheritage-d1"
console.log(metadata.data.model_version) // "2025-01-15"
console.log(metadata.data.license_url) // "https://www.inheritage.foundation/license/ai"

// Stream vector index for database sync
const vectors = await client.getAIVectorIndex({ limit: 100, offset: 0 })
vectors.data.forEach(record => {
  console.log(record.slug, record.vector.length, record.embedding_checksum)
})

LangChain Integration

import { InheritageClient, createHeritageContextRunnable, createInheritageToolkit } from '@inheritage-foundation/sdk/langchain'
import { ChatOpenAI } from '@langchain/openai'

const client = new InheritageClient({ attribution: 'visible' })

// Create a runnable for AI context retrieval
const heritageContextChain = createHeritageContextRunnable({ 
  client,
  includeHeaders: false, // set true to include API metadata
})

const result = await heritageContextChain.invoke({ slug: 'khajuraho' })
console.log(result.context)
console.log(result.embedding_dimensions) // 1536

// Create tools for LangChain agents
const tools = createInheritageToolkit(client)
const llm = new ChatOpenAI({ modelName: 'gpt-4-turbo' })

// Agent can now use:
// - get_heritage_ai_context
// - find_similar_heritage_sites
// - get_heritage_ai_metadata
// - get_heritage_ai_license

API Coverage

Heritage API

Endpoints: GET /heritage/:slug, GET /heritage, GET /heritage/featured, GET /heritage/top

Fetch detailed information about cultural heritage sites including:

  • Name, description, historical context
  • Location (state, coordinates, geolocation)
  • Architecture (style, materials, construction)
  • Visitor information (hours, fees, facilities)
  • Media (images, videos, 360° panoramas, floor plans)
  • Timeline events, references, analytics

Example:

const site = await client.getHeritage('ram-mandir-ayodhya')
console.log(site.data.architecture.style) // "Nagara Style"
console.log(site.data.visitor_info.entry_fee) // "Free"
console.log(site.data.media.primary_image) // "https://cdn.inheritage.foundation/..."

Geospatial API

Endpoints: GET /geo/nearby, GET /geo/region, GET /geo/:slug

GeoJSON-first geospatial queries:

  • Nearby search by lat/lon with radius
  • Region/bounding box queries
  • Single-site GeoJSON feature
  • EPSG:4326 coordinates, Accept: application/geo+json header support

Example:

const nearby = await client.getGeoNearby({
  lat: 19.0760,
  lon: 72.8777,
  radius: 5, // km
  limit: 10,
})
nearby.data.features.forEach(feature => {
  console.log(feature.properties.name, feature.geometry.coordinates)
})

Media API

Endpoints: GET /media/:slug

Fetch media bundles including:

  • Primary images, galleries, panoramas
  • 360° virtual tours, floor plans, site plans
  • Point clouds, mesh data, CAD files
  • Videos, documents

Example:

const media = await client.getMedia('hoysaleswara-temple')
console.log(media.data.primary_image) // "https://cdn.inheritage.foundation/..."
console.log(media.data.gallery.length) // 24
console.log(media.data.panoramas[0].url) // "https://cdn.inheritage.foundation/..."

Citation API

Endpoints: GET /citation/:entityId

Retrieve attribution metadata for any entity:

const citation = await client.getCitation('taj-mahal')
console.log(citation.data.required_display) // "Data © Inheritage Foundation"
console.log(citation.data.license) // "CC BY 4.0"

CIDOC-CRM & Institutional APIs

Endpoints: GET /cidoc/:slug, GET /lido/:slug, GET /lido/export, GET /oai-pmh

Access heritage data in international museum standards:

CIDOC-CRM JSON-LD (ISO 21127:2023):

const cidoc = await client.getHeritageCIDOC('hoysaleswara-temple')
console.log(cidoc.data['@type']) // "E22_Human-Made_Object"
console.log(cidoc.data.sameAs) // ["https://www.wikidata.org/entity/Q570336", ...]

LIDO XML (for museums, Europeana):

// Single site
const lido = await client.getHeritageLIDO('red-fort', false)
console.log(lido.data) // "<lido:lido>...</lido:lido>"

// Bulk export (ZIP)
const lidoZip = await client.exportHeritageLIDO({
  state: 'Karnataka',
  category: 'Temple',
  limit: 100,
})
// Returns ZIP blob with multiple LIDO XML files

OAI-PMH 2.0 (for automated harvesting):

// Repository identification
const identify = await client.oaipmhIdentify()

// List all records in LIDO format
const records = await client.oaipmhListRecords('lido', {
  from: '2025-01-01T00:00:00Z',
  set: 'state:Karnataka',
})

// Get specific record
const record = await client.oaipmhGetRecord(
  'oai:inheritage.foundation:heritage:taj-mahal',
  'lido'
)

AI Context, Metadata & Federation

Endpoints: GET /ai/context/:slug, /ai/embedding/:slug, POST /ai/similar, GET /ai/meta/:slug, POST /ai/vision/context, GET /ai/vector-index.ndjson, GET /license/ai

Features:

  • Deterministic narratives + 1536-d embeddings with checksum + model version headers
  • Similarity endpoint accepts either slug or a custom embedding array, returning cosine-ranked matches with reference metadata
  • Metadata endpoint mirrors the production schema (embedding_checksum, sources, same_as) for LangChain/LangGraph ingestion
  • Vision ingress classifies an image (URL/Base64) into probable heritage sites with captions + style predictions
  • Vector feed emits NDJSON slices for Pinecone/Weaviate/Chroma syncing; use getAIVectorIndex with limit/offset pagination
  • AI license endpoint provides the JSON addendum required for policy auditors and automated agents

Example:

// AI Context
const context = await client.getAIContext('ajanta-caves-maharashtra')
console.log(context.data.context) // "The Ajanta Caves are a UNESCO World Heritage Site..."
console.log(context.data.embedding_checksum) // SHA-256 checksum for reproducibility

// Similar Sites
const similar = await client.findSimilar({ slug: 'ajanta-caves-maharashtra', limit: 5 })
console.table(similar.data.data.map(entry => ({
  score: entry.score.toFixed(3),
  slug: entry.site.slug,
  state: entry.site.state
})))

// AI Metadata
const metadata = await client.getAIMetadata('ajanta-caves-maharashtra')
console.log(metadata.data.embedding_checksum) // Stable SHA-256 checksum
console.log(metadata.data.license_url) // "https://www.inheritage.foundation/license/ai"

// Vector Index Feed
const vectorFeed = await client.getAIVectorIndex({ limit: 100 })
vectorFeed.data.forEach(record => {
  console.log(record.slug, record.embedding_checksum)
})

// Vision Context
const vision = await client.getAIVisionContext({ 
  image_url: 'https://cdn.inheritage.foundation/hoysaleswara/front.jpg' 
})
console.log(vision.data.caption) // "A detailed view of the Hoysaleswara Temple facade."
console.log(vision.data.architectural_style_prediction) // "Hoysala"

// AI License
const license = await client.getAILicense()
console.log(license.data.requirements.ai_headers['AI-Use-Allowed']) // "true"

React Hooks Reference

useHeritage(slug, options?)

Fetch a single heritage site with automatic loading/error states.

const { data, loading, error, refetch } = useHeritage('taj-mahal', {
  client: customClient, // optional
  enabled: true, // optional, default true
})

useHeritageList(params?, options?)

Fetch paginated heritage sites with filters.

const { data, loading, error, refetch } = useHeritageList({
  state: 'Karnataka',
  category: 'Temple',
  limit: 20,
}, { enabled: true })

useGeoNearby(params, options?)

Fetch nearby heritage sites as GeoJSON.

const { data, loading, error, refetch } = useGeoNearby({
  lat: 28.6139,
  lon: 77.2090,
  radius: 10,
})

useAIContext(slug, options?)

Fetch AI context and embeddings.

const { data, loading, error, refetch } = useAIContext('khajuraho')

useSimilarSites(params, options?)

Find semantically similar sites.

const { data, loading, error, refetch } = useSimilarSites({
  slug: 'taj-mahal',
  limit: 5,
})

useAIVectorIndex(params?, options?)

Paginate through the vector index with infinite scroll support.

const { data, loading, error, hasMore, loadMore } = useAIVectorIndex({
  limit: 100,
})

// Call loadMore() to fetch next page

Components Reference

<InheritageCitation />

Renders CC BY 4.0 attribution for Inheritage data.

Props:

  • citation (CitationEntry): Citation data from API response
  • display ('inline' | 'block'): Display mode (default: 'inline')
  • className (string): Custom CSS class
  • style (CSSProperties): Custom inline styles
  • showBadge (boolean): Show CC BY 4.0 badge (default: false)
  • showLegal (boolean): Show full legal text (default: false)

Examples:

// Inline (compact)
<InheritageCitation citation={response.citations} />

// Block with badge
<InheritageCitation 
  citation={response.citations} 
  display="block" 
  showBadge 
/>

// Full legal notice
<InheritageCitation 
  citation={response.citations} 
  display="block" 
  showBadge 
  showLegal 
/>

Advanced Features

Caching & Conditional Requests

// Use ETag for conditional requests
const response1 = await client.getHeritage('taj-mahal')
const etag = response1.headers?.get('ETag')

const response2 = await client.getHeritage('taj-mahal', { ifNoneMatch: etag })
if (response2.notModified) {
  console.log('Use cached data')
} else {
  console.log('Fresh data:', response2.data)
}

// If-Modified-Since
const lastModified = response1.headers?.get('Last-Modified')
const response3 = await client.getHeritage('taj-mahal', { ifModifiedSince: lastModified })

Rate Limit Handling

const response = await client.getHeritage('taj-mahal')
if (response.rateLimit) {
  console.log(`${response.rateLimit.remaining}/${response.rateLimit.limit} requests remaining`)
  console.log(`Resets at: ${new Date(response.rateLimit.reset * 1000)}`)
}

// Handle 429 errors
try {
  await client.listHeritage({ limit: 1000 })
} catch (error) {
  if (error.statusCode === 429) {
    const retryAfter = error.retryAfter // seconds
    console.log(`Retry after ${retryAfter} seconds`)
  }
}

Abort Requests

const controller = new AbortController()
const promise = client.getHeritage('taj-mahal', { signal: controller.signal })

// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000)

try {
  await promise
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request cancelled')
  }
}

Testing

The SDK includes comprehensive test coverage:

# Run all tests
npm test

# Watch mode
npm run test:watch

# Unit tests only
npm test -- --grep "unit"

# Integration tests only
npm test -- --grep "integration"

# E2E tests only
npm test -- --grep "e2e"

Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.


License & Attribution

  • SDK Code: Apache 2.0
  • API Data: CC BY 4.0 (requires attribution: "Data © Inheritage Foundation")
  • AI Usage: See AI Usage Policy

When using this SDK, you must provide visible attribution per CC BY 4.0. The SDK automatically includes required headers. For web applications, use the <InheritageCitation /> component.


Resources


👨‍💻 Created by

Ayush Mishra
CTO & Lead Designerayush.studio

Built with ❤️ by Team Inheritage — Preserving India's cultural heritage through open data and modern developer tools.


📞 Support & Community


🙏 Acknowledgments

Special thanks to the open-source community and cultural heritage institutions worldwide for making this project possible.


Built with ❤️ by Ayush Mishra | Team Inheritage | Preserving India's cultural heritage through open data

About

Access India's cultural heritage programmatically. Query thousands of monuments, temples, and cultural sites—open data, CC BY 4.0, ready for maps, AI, and education.

Topics

Resources

Contributing

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages