---
title: "Python: no SDK, thirty lines of plain HTTP"
summary: "This is an integration pattern over the HTTP API, not a shipped connector. There is no package, no managed application, no marketplace listing and nothing to install: what is described below is the shape of the integration you would build, written down because knowing the shape in advance is most of the work. No client library ships either — no package on the index, no generated SDK, no vendored types. The API is plain JSON over HTTPS with a bearer token and a published schema, so any HTTP client will do, and the code below is the whole of what a wrapper would have contained. Thirty lines you can read beat a dependency nobody is maintaining."
canonical_url: https://entitybind.com/integrations/python
last_updated: 2026-10-12
copy: full
---

# Python: no SDK, thirty lines of plain HTTP

> This is an integration pattern over the HTTP API, not a shipped connector. There is no package, no managed application, no marketplace listing and nothing to install: what is described below is the shape of the integration you would build, written down because knowing the shape in advance is most of the work. No client library ships either — no package on the index, no generated SDK, no vendored types. The API is plain JSON over HTTPS with a bearer token and a published schema, so any HTTP client will do, and the code below is the whole of what a wrapper would have contained. Thirty lines you can read beat a dependency nobody is maintaining.

Canonical page: https://entitybind.com/integrations/python
Last updated: 2026-10-12

## Entity Bind and Python

Pattern over the HTTP API

This is an integration pattern over the HTTP API, not a shipped connector. There is no package, no managed application, no marketplace listing and nothing to install: what is described below is the shape of the integration you would build, written down because knowing the shape in advance is most of the work. No client library ships either — no package on the index, no generated SDK, no vendored types. The API is plain JSON over HTTPS with a bearer token and a published schema, so any HTTP client will do, and the code below is the whole of what a wrapper would have contained. Thirty lines you can read beat a dependency nobody is maintaining.

- What this is: A pattern you build
- Steps to working: 4 below
- Limits: 5 below
- Written back to your systems: Nothing
- To install: Nothing at all

Before you build any of it: The answers land on your own rows before any code does, and looking costs no integration work. [Start free →](https://app.entitybind.com/app?signup=1)

By [James Rooney](https://entitybind.com/about), founder of Entity Bind · Last revised 12 October 2026

## How you get a key

Create your workspace online and verify your email, then create your own read or resolve API keys, each shown once and revocable. Free includes 300 credits and needs no card. Paid subscriptions are purchased through Stripe in Billing, with applicable VAT and no automatic usage or overage charges.

`host.example.com` is a placeholder everywhere below, and a client configured against it will not connect. The hosted base URL is https://app.entitybind.com. Replace the placeholder with that origin; registry checks follow your activated plan.

The full-pipeline evaluation is arranged separately and is not activated by signup. Request it for your workspace; we confirm availability, sources and the start date before activation. It starts with a conversation about your file.

Create your workspace online, verify your email and create your own API key. Free includes 300 credits and shallow matching with no card; choose a paid subscription in Billing when you need registry checks. [Start free →](https://app.entitybind.com/app?signup=1)

## What you would build for Python

There is nothing to install, so the blocks below are the job itself: the query, the request, and the branch on what comes back. Endpoint paths, header names and field names are the API's own and are exact — the code around them is a shape to fit to your own stack.

### 01 One call, to see the shape

Send at least one identifying field. Unknown fields are rejected rather than ignored, which is deliberate: a field dropped in silence is a wrong answer arriving in silence. client_ref takes up to 200 characters, comes back verbatim, and is how the response joins to your data on your own key.

```
import os
import httpx

response = httpx.post(
    f"{os.environ['ENTITYBIND_BASE_URL']}/v1/resolve",
    headers={"Authorization": f"Bearer {os.environ['ENTITYBIND_API_KEY']}"},
    json={
        "name": "Acme Widgets Ltd",
        "domain": "acmewidgets.co.uk",
        "country": "GB",
        "depth": "research",
        "client_ref": "crm-4417",
    },
    timeout=60.0,
)
response.raise_for_status()
result = response.json()
```

### 02 Branch on the outcome first

A match below 0.90 confidence is unrepresentable. The record comes back as an abstention with a ranked shortlist instead. The rule lives in the model that carries the result rather than in a caller who could skip it. Enforced as a domain invariant on the resolution outcome and again by a predicate called on the online, batch and replay paths, so a sub-floor accepted match cannot be constructed on any of them. A cached replay whose inherited confidence has fallen below the floor is withheld rather than re-served. So an accepted match has already cleared the floor by the time you read it. Branch on whether the record resolved and treat every abstention as a work list. If your policy needs a stricter threshold, measure what it costs you in coverage on labelled records first. Confidence bounds depend on the recorded evidence population; there is no universal score for every match. Read match_confidence_basis and the evidence. A 0.99 filter can return some v8 adjudicated matches while excluding valid identifier matches, so validate its coverage cost on your own inputs.

```
if result["decision"] == "match":
    entity_id = result["entity_id"]
    decision_id = result["decision_id"]      # reopens the evidence trail
else:
    # Not an error. A ranked shortlist, a typed reason, the column that
    # would have decided, and a review id — and it cost nothing.
    reason = result["reason_code"]
    shortlist = result["candidates"]
    prescription = result.get("prescription_fields")
```

### 03 Batch when you have more than a handful

Up to 500 records a request, treated as an unordered set, with a repeated idempotency key recognised as the same request and one ledger row written per outcome. Batches run one at a time rather than queueing, so plan a large file as a window rather than as a rate. A byte-identical replay is free — per tenant, per exact content, with no expiry — so an interrupted job restarts without paying twice for the rows it already did.

### 04 Read the usage block rather than counting calls

Every metered response carries a usage block, and the module that quotes the price in that block is the same module that writes the ledger row and serves the public pricing endpoint. The number in your response, the number in your usage export and the number you are charged cannot drift apart, so there is nothing to reconcile and no reason to keep a count of your own.

If a step above fails against your own deployment, send us what the client reported rather than working around it. [Talk to us →](https://entitybind.com/contact)

## What this route gets you

Every surface runs the same pipeline: the same cascade, the same confidence floor, the same evidence and the same credit rule. These are the things this route adds on top of it.

- A plain JSON API with a published schema and no client library between you and it, so a change in the payload is visible in your code rather than absorbed by a wrapper.
- Your own key echoed on every row, so results join to your data without a mapping table.
- Free replays: a byte-identical request costs nothing, per tenant, per exact content, with no expiry — which makes retry logic cheap and restarts safe.
- An NDJSON export of the whole catalogue, so leaving is a download — portability in the sense the data protection regulation uses the word.

## What it will not do

Start with the first one: it decides whether there is anything to install at all. The rest are the parts of the shape that most often get scoped wrong.

01. This is an integration pattern over the HTTP API, not a shipped connector. There is no package, no managed application, no marketplace listing and nothing to install: what is described below is the shape of the integration you would build, written down because knowing the shape in advance is most of the work.
02. No package to install, no async helper, no retry policy and no pagination helper. You write those, and the API documentation is written on the assumption that you will.
03. The OAuth endpoints are excluded from the published schema on purpose: they are form-encoded, browser-facing, and answer with a different error body, so a client generated from the schema must never call them.
04. Rate limits are per tenant and shared with every other surface, so a Python job and an editor agent draw on one budget.
05. Scope is company and organisation identity. Not people, vessels, bank-account ownership, sanctions or emissions, and results may not be used for eligibility decisions about individuals, including employment, credit and tenancy.

Check these integration limits before building. Create your Free workspace to inspect your own rows and keys; contact us if you need help choosing a supported integration shape. [Start free →](https://app.entitybind.com/app?signup=1)

## The other ways in

3 of the 6 are shipped integrations and 3 are patterns over the HTTP API. Every card says which kind it is, so you know what you are scoping before you open it.

- [Claude Code](https://entitybind.com/integrations/claude-code) (Shipped): 4 steps · 4 named limits
- [Claude Desktop](https://entitybind.com/integrations/claude-desktop) (Shipped): 4 steps · 4 named limits
- [Cursor](https://entitybind.com/integrations/cursor) (Shipped): 4 steps · 3 named limits
- [Snowflake](https://entitybind.com/integrations/snowflake) (Pattern): 4 steps · 5 named limits
- [Salesforce](https://entitybind.com/integrations/salesforce) (Pattern): 4 steps · 5 named limits

Python sits with Snowflake and Salesforce on the same shelf: nothing to install. If you are weighing a shipped integration against a pattern, [the line between the two shelves](https://entitybind.com/integrations#the-line) is drawn on the hub.

Whichever surface you land on, the cheapest first move is the same: a few hundred of your own rows. [Start free →](https://app.entitybind.com/app?signup=1)

## What to read next

The work this surface is installed to do, the method behind the answers it returns, and the terms those answers use. Each card names its own shelf.

- [AI agents](https://entitybind.com/use-cases/ai-agents) (Use case): A counterparty check before the agent acts, and a receipt for what it acted on.
- [Reference data](https://entitybind.com/use-cases/reference-data) (Use case): Every identifier a company is known by, each separately cited — and the ones nobody holds.
- [What is entity resolution?](https://entitybind.com/guides/what-is-entity-resolution) (Guide): Entity resolution decides which records refer to the same real-world thing. What it is, why company identity is hard, deterministic versus probabilistic matching, and why fuzzy matching is not entity resolution.
- [Abstention](https://entitybind.com/glossary/abstention) (Definition): An abstention is a first-class 'we do not know' returned instead of a match: the record comes back unresolved, with a ranked shortlist, a typed reason and the column that would have decided it.
- [Idempotency](https://entitybind.com/glossary/idempotency) (Definition): An operation is idempotent when performing it repeatedly has the same effect as performing it once, which is what makes a retry after a timeout safe rather than duplicating work.
- [Replay](https://entitybind.com/glossary/replay) (Definition): Replay is re-serving a previous decision for byte-identical content rather than recomputing it, which makes repeated submissions free and deterministic — provided the replayed decision is still one the system would stand behind.

## Start with a file, not an integration.

Create your workspace, verify your email and run your first company file. The Free plan needs no card. Create API keys in your workspace when you need an integration.

[Start free](https://app.entitybind.com/app?signup=1) · [Read the API docs](https://entitybind.com/api)

300 credits. No card.

For a guided review of your file, explore [the Merge Safety Sprint](https://entitybind.com/audit-pack).

## Questions about Python

### Is there a Python SDK?

No, and none is planned until there are enough integrations running to keep one current. The API is JSON over HTTPS with a bearer token and a published schema; a wrapper would add a dependency, a version skew and a layer that hides payload changes from you, in exchange for saving about thirty lines. If you want a typed client, generate one from the schema — with the caveat that the OAuth endpoints are excluded from it on purpose, so a generated client must never call them.

### What confidence threshold should I use in my code?

Start by branching on the outcome and sending abstentions to a review queue. The 0.90 floor is already enforced in the engine: a match below it cannot be constructed at all, because the rule lives in the model that carries the result — a domain invariant — and a predicate checks it again on the online, batch and replay paths. Anything you receive as an accepted match has already cleared it. It is an acceptance contract, not calibration evidence: it says what we refuse to return, not how often an accepted match is right. Read it with the coverage it costs. A stricter threshold is possible, and worth evaluating for precision and coverage on your own labelled records before you ship it. Confidence bounds depend on the recorded evidence population; there is no universal score for every match. Read match_confidence_basis and the evidence. A 0.99 filter can return some v8 adjudicated matches while excluding valid identifier matches, so validate its coverage cost on your own inputs.

---

Internal fixtures only. The historical 2026-08-29 per-tier recording covers 317 GB companies with identifier-rich arrivals seeding the catalogue first; the context tier includes country and registered-town prose. Its legacy replay has no full-prompt-verified calls and cannot certify current calibration. The September 5 CI reports cover 1,176 labelled pairs and 705 records over 250 companies using offline stubs. These are not independent customer holdouts or live production validation; the 99% minimum-input product target remains unmet. Scope is company and organisation identity only — not people, vessels, bank-account ownership, sanctions or emissions. Results may not be used for eligibility decisions about individuals, including employment, credit and tenancy.

Entity Bind resolves companies and organisations only. It does not resolve people, vessels, bank-account ownership, sanctions exposure, emissions or geolocation, and its results may not be used for eligibility decisions about individuals, including employment, credit and tenancy.

This is the Markdown copy of https://entitybind.com/integrations/python, assembled from the same data the page renders and carrying every sentence, table row, figure and question the page's main content carries. The HTML page is canonical; it adds the layout, the navigation and the interactive parts (the ask panel, the forms), which a copy can name but not run. Every page on the site, with a line on each: https://entitybind.com/llms.txt.
