Skip to main content

Enigma's Public API SDK

Project description

Enigma API Client

Python SDK for the Enigma GraphQL business intelligence API. Query Enigma's database of 250M+ businesses using raw GraphQL or natural language prompts.

Installation

# Core client (raw GraphQL only)
pip install enigma-api-client

# With Claude agent (skill-based generation, requires Anthropic API key)
pip install enigma-api-client[anthropic]

Quick Start

The client supports both raw GraphQL queries and natural language queries.

  • Below example showcases the raw GraphQL approach.
  • Subseqent examples show how to use the natural language strategies.

Using GraphQL Queries

import asyncio
from enigma_api_client import Client, ClientConfig

async def main():
    config = ClientConfig(enigma_api_key="your-api-key")
    async with Client(config) as client:
        # Example, sending off a handwritten GraphQL query
        response = await client.search(
            query="""query {
              search(searchInput: { name: "Starbucks", entityType: BRAND }) {
                ... on Brand {
                  id
                  names(first: 1) { edges { node { name } } }
                }
              }
            }"""
        )
        print(response.data)

asyncio.run(main())

Connection lifecycle. A Client holds reusable keep-alive connections for the GraphQL endpoint and the query strategy. Reuse one client across requests and release it when done — use it as an async context manager (async with Client(config) as client:, shown above) or call await client.aclose().

Natural Language Query strategies

The client supports three strategies for converting natural language prompts into GraphQL queries. Pass a strategy via ClientConfig.query_strategy to enable client.search(prompt="...").

All strategies require the ANTHROPIC_API_KEY environment variable. The AgentStrategy additionally requires the claude_agent_sdk package (pip install enigma-api-client[anthropic]).

Service Strategy (default)

Will execute a http request to perform query generation using any of the strategies below on the server side.

import asyncio
from enigma_api_client import Client, ClientConfig

client = Client(ClientConfig(
    enigma_api_key="your-api-key",
    # will use ServiceStrategy by default
))

async def main():
    # Brand lookup
    response = await client.search(prompt="Tell me about Chipotle")
    print(response.data)

    # Location search
    response = await client.search(prompt="Find Starbucks locations in California")
    print(response.data)

    # Business discovery
    response = await client.search(prompt="Find coffee shops in Denver")
    print(response.data)

    # Person search
    response = await client.search(prompt="Find companies owned by Elon Musk")
    print(response.data)

    # KYB verification
    response = await client.search(prompt="Verify legal entity for Enigma Technologies in NY")
    print(response.data)

asyncio.run(main())

TemplateStrategy — LLM-classified, template-built

Uses an LLM (via Anthropic Messages API) to classify the user's prompt into one of 13 pre-defined query templates and extract parameters, then assembles the GraphQL query deterministically from the matching template. Fast and reliable — no hallucinated field names since the GraphQL is built from verified templates.

import asyncio
from enigma_api_client import Client, ClientConfig
from enigma_api_client.strategies import TemplateStrategy

client = Client(ClientConfig(
    enigma_api_key="your-api-key",
    query_strategy=TemplateStrategy(),
))

async def main():
    # Brand lookup
    response = await client.search(prompt="Tell me about Chipotle")
    print(response.data)

    # Location search
    response = await client.search(prompt="Find Starbucks locations in California")
    print(response.data)

    # Business discovery
    response = await client.search(prompt="Find coffee shops in Denver")
    print(response.data)

    # Person search
    response = await client.search(prompt="Find companies owned by Elon Musk")
    print(response.data)

    # KYB verification
    response = await client.search(prompt="Verify legal entity for Enigma Technologies in NY")
    print(response.data)

asyncio.run(main())

The template strategy covers query templates: brand profiles, brand lookups by website, locations, business discovery, person search, corporate officers, legal entity verification, contacts, watchlist screening, operating location profiles, aggregate counts, and risk assessment. Prompts that don't map to any template raise an EnigmaClientException.

GenerativeStrategy — end-to-end LLM query generation

Uses a single LLM call (via Anthropic Messages API) to generate the full GraphQL query and variables directly. The LLM receives the complete Enigma GraphQL API skill reference as context. More flexible than TemplateStrategy for complex or unusual queries that don't fit neatly into pre-defined templates, but slower and carries some risk of hallucinated field names.

import asyncio
from enigma_api_client import Client, ClientConfig
from enigma_api_client.strategies import GenerativeStrategy

client = Client(ClientConfig(
    enigma_api_key="your-api-key",
    query_strategy=GenerativeStrategy(),
))

async def main():
    response = await client.search(
        prompt="Find all open Dunkin' Donuts locations in Massachusetts with phone numbers"
    )
    print(response.data)

asyncio.run(main())

AgentStrategy — Claude Agent SDK with skill

Uses the Claude Agent SDK (claude_agent_sdk) to generate GraphQL queries via an interactive agent that has access to the full enigma-graphql skill — including the schema, examples, field corrections, and pagination templates. The agent can read skill files, reason about the query, and iteratively refine its output. Produces the highest quality queries for complex scenarios but is the slowest option.

Requires: pip install enigma-api-client[anthropic]

import asyncio
from enigma_api_client import Client, ClientConfig
from enigma_api_client.strategies import AgentStrategy

client = Client(ClientConfig(
    enigma_api_key="your-api-key",
    query_strategy=AgentStrategy(),
))

async def main():
    response = await client.search(
        prompt="Find all open Dunkin' Donuts locations in Massachusetts with phone numbers"
    )
    print(response.data)

asyncio.run(main())

Strategy comparison

Strategy Approach Speed Quality Extra deps
TemplateStrategy LLM classifies → deterministic template build ~1-3s Reliable, no hallucination None
GenerativeStrategy LLM generates full GraphQL end-to-end ~3-10s Flexible, some hallucination risk None
AgentStrategy Claude agent with skill + tool access ~10-60s Highest quality, iterative refinement claude_agent_sdk

When to use which:

  • TemplateStrategy (default): Best for production use. Covers 13 common query patterns with zero hallucination risk. The LLM only classifies and extracts parameters — the GraphQL is deterministic.
  • GenerativeStrategy: Best for complex or unusual queries that don't fit the 13 templates. The LLM sees the full API reference and generates custom GraphQL. Good for prototyping and exploratory queries.
  • AgentStrategy: Best for maximum quality when latency is not a concern. The agent can read examples, check field corrections, and reason about the query. Good for batch processing or one-off complex queries.

Caveats: LLM-generated GraphQL

The Enigma GraphQL schema has several non-obvious conventions that make LLM-generated queries unreliable without guardrails. Understanding these is important regardless of which strategy you use.

Why this is hard for LLMs

The Enigma schema has ~50 field names, 4 entity types, 10+ filter operators, and 6 connection patterns. Many field names are unintuitive — LLMs consistently guess wrong:

LLMs guess Actual field name
status operatingStatus
url website
description industryDesc
title jobTitle
amount projectedQuantity
averageRating reviewScoreAvg
formationDate formationYear (Int, not Date)

These cause HTTP 400 errors ("Cannot query field") that are silent failures if not handled.

Structural pitfalls

Beyond field names, the graph structure has patterns that LLMs regularly get wrong:

  • search returns a flat list, not a connection. LLMs write search { edges { node { ... } } } — the correct form is search { ... on Brand { ... } }.
  • LegalEntity.persons is almost always empty. To find officers, you must traverse registeredEntities → registrations → roles → legalEntities. LLMs take the direct (empty) path.
  • Searching OPERATING_LOCATION by brand name returns nothing. You must search BRAND and filter its operatingLocations connection. LLMs don't know this.
  • name vs prompt on SearchInput are completely different modes. name does entity resolution ("Starbucks"); prompt does semantic discovery ("coffee shop"). Using name: "coffee shop" returns nothing useful.
  • totalCount does not exist on connections. Requesting it causes HTTP 400. Use aggregate queries instead.
  • Cursor pagination uses one query, not two. A single query with $cursor: String + after: $cursor paginates every page — pass cursor: null on page 1 (null starts from the beginning; omitting the declared variable is what causes HTTP 400 "Undefined variable"). Keep the connection's conditions/orderBy fixed across a run, since cursors are bound to the arguments that minted them.

Data quality traps

Even syntactically valid queries can return silently wrong data:

  • Franchise resolution: Searching BRAND for a local franchise (e.g., a single Days Inn) returns the parent chain's data — 1,969 locations rolled up instead of the single franchisee.
  • websiteContents is a connection, not a scalar. Must use websiteContents(first: 1) { edges { node { httpStatusCode } } }.

How the strategies handle this

TemplateStrategy avoids all of the above. The LLM only classifies the prompt into a template and extracts parameters (company name, state, city, etc.). The actual GraphQL is assembled from 13 hand-written, tested templates. Zero hallucination risk, but limited to the patterns those templates cover.

GenerativeStrategy sends the full API skill reference (~600 lines of documentation, guardrails, and examples) as system prompt context. This covers most pitfalls, but the LLM can still hallucinate field names or miss structural rules — especially for unusual queries. Validate generated queries before using them in production.

AgentStrategy has full access to the skill files, examples, field corrections reference, and can iteratively refine queries. Highest quality, but slowest and most expensive. The agent can introspect the schema if it encounters errors.

Recommendations

  • For production automation, use TemplateStrategy or raw GraphQL. The 13 templates cover the most common query patterns and are guaranteed correct.
  • For prototyping or one-off complex queries, use GenerativeStrategy or AgentStrategy but always review the generated query before trusting the results.
  • Always check response.is_success() and inspect response.errors before using response.data. A plausible-looking query can still fail at the API level.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

enigma_api_client-0.5.2-py3-none-any.whl (250.7 kB view details)

Uploaded Python 3

File details

Details for the file enigma_api_client-0.5.2-py3-none-any.whl.

File metadata

File hashes

Hashes for enigma_api_client-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5ed6373c01bdfef75eb06c6dc03c35ac265183482806dc402acac9dd6f4e1135
MD5 1a7aa35972324644f40557c939b6a6ca
BLAKE2b-256 d0b2799a4cbd1fbc630d256a26adc56673cea31f268f9e633bb00b9c42055006

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page