streamgine — Python SDK
Diff by Streamgine lives under the diff module. Install once; add more Streamgine modules (training data, etc.) under the same package later.
This directory is the customer package published to PyPI. Repo-only load tests and dev agents live in tools/python/ — not shipped to customers.
Today: one wheel streamgine = Diff (from streamgine import diff). Next products (e.g. training-data) get their own wheels (streamgine-diff, streamgine-training, …) under the same streamgine import namespace — see PUBLISHING.md and .cursor/rules/python-client.mdc. Do not grow a fat single package.
Product: diff.streamgine.com · Docs: docs.md · California: coverage · Use cases: risk monitoring, AI agents · Repo: github.com/scurtutech/diff-events-service
from streamgine import diff
# Once at startup — pick ONE download from /account:
diff.configure("diff-streamgine-credentials.json")
# OR: source diff-streamgine-env.sh then diff.configure()
client = diff.DiffClient()
Install from PyPI:
python3 -m pip install streamgine
Or from this repo:
cd clients/python
python3 -m venv .venv && source .venv/bin/activate
python -m pip install .
Requires Python 3.10+. One dependency: httpx (TLS verification enabled by default).
Credentials (one setup point)
Call diff.configure() once at process startup. Every DiffClient() and verify_webhook() reads from that config.
Download from /account or checkout — filenames are fixed:
| Download | Then |
|---|---|
diff-streamgine-credentials.json |
diff.configure("diff-streamgine-credentials.json") |
diff-streamgine-env.sh |
source diff-streamgine-env.sh then diff.configure() |
Option A — credentials JSON:
diff.configure("diff-streamgine-credentials.json")
Option B — env script:
source diff-streamgine-env.sh
diff.configure()
Do not pass API keys or signing secrets to DiffClient() or verify_webhook() in normal use.
Zero-setup agent (copy-paste)
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e . fastapi uvicorn
# Customer path: download from /account, then ONE of:
# source diff-streamgine-env.sh
# # or keep diff-streamgine-credentials.json next to the process
# Local repo seed (AUTH_ENABLED): npm run seed:dev-customer, then export printed keys
source diff-streamgine-env.sh # or configure("diff-streamgine-credentials.json") in code
python -m uvicorn examples.agent:app --port 8000
Runnable source: examples/agent.py. Calls register_test() on startup; within ~1s you should see after={'test': 'success'} on topic diff-event.test.
Serverless (AWS Lambda): examples/serverless/ — deploy handler.py, run register.py once, receive test heartbeats in CloudWatch.
Agent journey (production filters): examples/agent_journey.py.
Docker worker reaching a host agent:
export DIFF_CALLBACK_URL=http://host.docker.internal:8000/webhooks/diff
Test heartbeats (start here)
Before wiring real registry events, confirm your agent receives signed webhooks:
from streamgine import diff
diff.configure() # after: source diff-streamgine-env.sh OR configure("diff-streamgine-credentials.json")
client = diff.DiffClient()
client.register_test(callback_url="https://your-agent.example/webhooks/diff")
Filter on event.is_test_heartbeat (or after == {"test": "success"}). The service sends this every second:
{
"action": "INSERT",
"after": { "test": "success" }
}
No entity_id on test events.
Quick start (production registry events)
from streamgine import diff
diff.configure()
client = diff.DiffClient()
client.register(
match={
"state": "CA",
"principal_city": "San Francisco",
},
actions=["INSERT"],
callback_url="https://your-agent.example/webhooks/diff",
)
client.close()
INSERT = newly added company, UPDATE = changed, DELETE = removed. Omit actions to receive every matching state/city event.
Search current companies (full story)
Webhooks deliver changes. Search returns current snapshots:
from streamgine import diff
diff.configure()
client = diff.DiffClient()
result = client.search(
query={"match": {"principalCity": "San Francisco"}},
size=10,
)
for company in result["entities"]:
print(company.get("entity_name"), company.get("entity_number"))
Agent journey: Search → Watch → Qualify → Act → Stay current (see /docs.md).
2. Verify inbound webhooks (required)
Always verify raw request bytes before trusting JSON. The worker signs the exact JSON body with HMAC-SHA256.
from streamgine import diff
diff.configure()
def handle_webhook(raw_body: bytes, signature: str | None):
try:
event = diff.verify_webhook(raw_body, signature)
except diff.WebhookVerificationError:
return 401, {"error": "invalid signature"}
print(event.action, event.entity_id, event.after)
return 200, {"ok": True}
FastAPI
from fastapi import FastAPI, Header, Request, Response
from streamgine import diff
app = FastAPI()
@app.on_event("startup")
def setup() -> None:
diff.configure()
@app.post("/webhooks/diff")
async def diff_webhook(
request: Request,
response: Response,
x_diff_signature: str | None = Header(default=None, alias="X-Diff-Signature"),
):
raw = await request.body()
try:
event = diff.verify_webhook(raw, x_diff_signature)
except diff.WebhookVerificationError:
response.status_code = 401
return {"error": "invalid signature"}
# Your agent logic here
return {"ok": True, "entity_id": event.entity_id}
Flask
from flask import Flask, request
from streamgine import diff
app = Flask(__name__)
diff.configure()
@app.post("/webhooks/diff")
def webhook():
try:
event = diff.verify_webhook(
request.get_data(),
request.headers.get("X-Diff-Signature"),
)
except diff.WebhookVerificationError:
return {"error": "invalid signature"}, 401
return {"ok": True, "action": event.action}
Security
| Practice | How this client helps |
|---|---|
| Verify every webhook | diff.verify_webhook() uses hmac.compare_digest (timing-safe) on the raw body |
| Match worker algorithm | Same as Node: HMAC-SHA256(secret, raw_json_bytes) → header X-Diff-Signature: sha256=<hex> |
| Parse JSON only after verify | Tampered bodies fail before WebhookEvent is built |
| HTTPS in production | DiffClient(verify_tls=True) (default); use https:// callback URLs |
| Keep secrets out of code | One configure() from JSON or env — never scatter keys in constructors |
Never log the signing secret or skip signature verification in production.
Credentials file (after checkout)
Download diff-streamgine-credentials.json (or diff-streamgine-env.sh) from /account / checkout. JSON format (version 1):
{
"version": 1,
"service": "diff.streamgine.com",
"customer_id": "cus_…",
"api_key": "de_live_…",
"signing_secret": "whsec_…",
"api_url": "https://diff.streamgine.com",
"env": {
"DIFF_API_KEY": "de_live_…",
"DIFF_SIGNING_SECRET": "whsec_…",
"DIFF_API_URL": "https://diff.streamgine.com"
}
}
from streamgine import diff
diff.configure("diff-streamgine-credentials.json")
client = diff.DiffClient()
# diff.verify_webhook(...) uses the same signing secret automatically
Auth
Env (via configure()) |
Used for |
|---|---|
DIFF_API_KEY |
register() / register_test() (customer Bearer) |
DIFF_PROVIDER_API_KEY |
get_state() and provider ingest when provider auth is enabled |
Register responses are slim (ok / subscription fields only — no Redis index maps).
API surface (streamgine.diff)
| Symbol | Role |
|---|---|
configure() |
Load credentials once (JSON path or DIFF_* env) |
get_config() |
Read configured ClientConfig |
DiffClient |
register(), register_test(), health(), get_state() |
verify_webhook() |
Verify signature + return WebhookEvent |
DIFF_* env name constants |
API_URL_ENV, API_KEY_ENV, SIGNING_SECRET_ENV, … |
WebhookEvent |
Parsed action, optional entity_id, optional after |
WebhookVerificationError |
Invalid/missing signature or malformed payload |
SIGNATURE_HEADER |
"X-Diff-Signature" |
Direct imports also work: from streamgine.diff import DiffClient.
Development
cd clients/python
python -m pip install -e ".[dev]"
pytest
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file streamgine-1.0.0.tar.gz.
File metadata
- Download URL: streamgine-1.0.0.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76eefb4cc55f22dd035727dd9321066a77259130078f3fade383a51ef398c456
|
|
| MD5 |
4ee84696a70a8b264a040a9b3ad52953
|
|
| BLAKE2b-256 |
af014bff8d71c72a86bab77eab69a57eeac39aac0962b64ffa5f6b3c989a9f99
|
Provenance
The following attestation bundles were made for streamgine-1.0.0.tar.gz:
Publisher:
publish-python.yml on scurtutech/diff-events-service
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
streamgine-1.0.0.tar.gz -
Subject digest:
76eefb4cc55f22dd035727dd9321066a77259130078f3fade383a51ef398c456 - Sigstore transparency entry: 2732871255
- Sigstore integration time:
-
Permalink:
scurtutech/diff-events-service@42648becd5ab839196a6edaac7e9bb1a25214eda -
Branch / Tag:
refs/tags/python-v1.0.0 - Owner: https://github.com/scurtutech
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@42648becd5ab839196a6edaac7e9bb1a25214eda -
Trigger Event:
release
-
Statement type:
File details
Details for the file streamgine-1.0.0-py3-none-any.whl.
File metadata
- Download URL: streamgine-1.0.0-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb84739d8cf1232381cee1a8231f71ab57e9414209beb0be11eaefd7efd2d06a
|
|
| MD5 |
394eecb29cb26a01bfc12a68cfe15685
|
|
| BLAKE2b-256 |
81c6b5d171d1065a5d5e165f024de9f3c184c379304a2b1979fa07c4f5ca075d
|
Provenance
The following attestation bundles were made for streamgine-1.0.0-py3-none-any.whl:
Publisher:
publish-python.yml on scurtutech/diff-events-service
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
streamgine-1.0.0-py3-none-any.whl -
Subject digest:
bb84739d8cf1232381cee1a8231f71ab57e9414209beb0be11eaefd7efd2d06a - Sigstore transparency entry: 2732871272
- Sigstore integration time:
-
Permalink:
scurtutech/diff-events-service@42648becd5ab839196a6edaac7e9bb1a25214eda -
Branch / Tag:
refs/tags/python-v1.0.0 - Owner: https://github.com/scurtutech
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@42648becd5ab839196a6edaac7e9bb1a25214eda -
Trigger Event:
release
-
Statement type: