Skip to main content

Python client for Keyban API

Project description

Keyban API Client

A Python client library for interacting with the Keyban DPP API. Supports passport creation with on-chain certification, field-level encryption, and UNTP granularity levels (model, batch, item).

Features

  • Passport management — create, update, list, delete passports at any granularity
  • On-chain certification — automatic W3C Verifiable Credential (VC) issuance with Starknet anchoring
  • Selective certificationcertifiedPaths to choose which fields from data are included in the certificate
  • Field-level encryption — SHA-256 hashing and AES-256-GCM encryption
  • Type-safe models — Pydantic v2 request/response validation
  • Filtering & pagination — query passports with flexible filters

Quick Start

Create a Certified Passport (Model Level)

import base64, os
from uuid import UUID, uuid4
from keyban_api_client import (
    DppClient, ProductFields, CreatePassportRequest,
)

client = DppClient(
    base_url="https://api.keyban.localtest.me",
    api_key="your-api-key",
)

# Generate an encryption key for sensitive fields
encryption_key = base64.b64encode(os.urandom(32)).decode("ascii")

# Build data with encrypted fields
data = ProductFields.create_encrypted(
    confidential_paths=["serial_number"],
    enc_algorithm="aes-256-gcm",
    enc_key=encryption_key,
    name="My Certified Product",
    serial_number="SN-CONFIDENTIAL-123",
    brand="MyBrand",
)

# Create passport — certification triggers automatically for model granularity
passport = client.create_passport(CreatePassportRequest(
    application=UUID("your-application-id"),
    network="StarknetSepolia",
    granularity="model",
    modelNumber=f"my-model-{uuid4().hex[:8]}",
    data=data.model_dump(),
))

print(f"Passport ID: {passport.id}")
print(f"Encryption Key: {encryption_key}")

client.close()

When data is provided for a model-level passport, the backend automatically:

  1. Builds a W3C Verifiable Credential with a Data Integrity proof (P-256 ecdsa-jcs-2019); credentialSubject is the certified content byte-for-byte (no injected identifier)
  2. Uploads the signed VC to IPFS
  3. Publishes a certification event on Starknet with the CID, a SHA-256 canonical content hash (enables trustless verification without knowing the passport id), and the certifier public key

Encryption & Hashing

Protect sensitive fields before sending to the API using ProductFields.create_encrypted().

Algorithm Reversible Use Case
sha256 No Integrity verification (prove value existed)
aes-256-gcm Yes Confidential data (decryptable with key)
from keyban_api_client import ProductFields
import base64, os

# SHA256 hashing (irreversible)
data = ProductFields.create_encrypted(
    confidential_paths=["supplier_id"],
    enc_algorithm="sha256",
    name="My Product",
    supplier_id="SECRET-123",
)

# AES-256-GCM encryption (reversible)
key = base64.b64encode(os.urandom(32)).decode("ascii")
data = ProductFields.create_encrypted(
    confidential_paths=["serial_number"],
    enc_algorithm="aes-256-gcm",
    enc_key=key,
    name="My Product",
    serial_number="SN-CONFIDENTIAL-789",
)
print(f"Save this key: {data.encryption_key}")

# Nested paths supported
data = ProductFields.create_encrypted(
    confidential_paths=["brand.supplier_id"],
    enc_algorithm="sha256",
    brand={"name": "Public", "supplier_id": "SECRET"},
)

Advanced Usage

Filtering & Pagination

from keyban_api_client import FilterOperator

# Filter passports by model number
f = FilterOperator(field="modelNumber", operator="contains", value="lead")
passports = client.list_passports(filters=[f], page_size=20)

for p in passports.data:
    print(f"- {p.model_number} ({p.granularity})")

# Paginate
all_passports = []
page = 1
while True:
    response = client.list_passports(current_page=page, page_size=50)
    all_passports.extend(response.data)
    if len(response.data) < 50:
        break
    page += 1

Selective Certification with certifiedPaths

By default, the entire data object is certified. Use certifiedPaths to certify only specific fields — updating non-certified fields won't trigger re-certification.

# Only certify brand and gtin — other fields in data are stored but not signed
passport = client.create_passport(CreatePassportRequest(
    application=UUID("your-application-id"),
    network="StarknetSepolia",
    granularity="model",
    modelNumber="selective-cert",
    data={"brand": "Acme", "gtin": "3760001000001", "notes": "internal memo"},
    certifiedPaths=["brand", "gtin"],
))

# Update a non-certified field — NO re-certification
client.update_passport(passport.id, UpdatePassportRequest(
    data={"brand": "Acme", "gtin": "3760001000001", "notes": "updated memo"},
))

# Update a certified field — re-certification triggers automatically
client.update_passport(passport.id, UpdatePassportRequest(
    data={"brand": "NewBrand", "gtin": "3760001000001", "notes": "updated memo"},
))

# Change the selection itself — re-certification triggers
client.update_passport(passport.id, UpdatePassportRequest(
    certifiedPaths=["brand", "gtin", "notes"],
))

Update a Passport (Re-certification)

When data or certifiedPaths changes on a model-level passport, re-certification is triggered automatically (only if the resulting certificate content actually changed).

from keyban_api_client import UpdatePassportRequest

updated = client.update_passport(
    passport.id,
    UpdatePassportRequest(
        data={"name": "Updated Product", "brand": "NewBrand"},
    ),
)

Error Handling

from keyban_api_client import DppClient, KeybanAPIError

client = DppClient(base_url="...", api_key="...")

try:
    passport = client.create_passport(request)
except KeybanAPIError as e:
    print(e.status_code)  # 400
    print(e.detail)       # Full API response body

    if e.status_code == 401:
        print("Authentication failed - check your API key")
    elif e.status_code == 404:
        print("Resource not found")
finally:
    client.close()

Context Manager

with DppClient(base_url="...", api_key="...") as client:
    passports = client.list_passports()

API Reference

DppClient

Main client class. Constructor:

DppClient(
    base_url: str,
    api_key: str,
    api_version: str = "v1",
    timeout: int = 30,
)

Methods

Method Description
list_passports(filters, current_page, page_size) List passports with filtering
get_passport(passport_id) Get a passport by ID
create_passport(data) Create passport (certifies if model + data)
update_passport(passport_id, data) Update passport (re-certifies if certificate content changed)
delete_passport(passport_id) Delete a passport
create_passport_model(data) Shorthand for create_passport with model granularity

Data Models

DppPassport

  • id: UUID
  • application: Application
  • network: str (StarknetSepolia, StarknetMainnet, etc.)
  • granularity: str (model, batch, or item)
  • status: str (always published)
  • model_number: str (nullable)
  • batch_number: str (nullable)
  • item_number: str (nullable)
  • data: Dict[str, Any] (all passport data)
  • certified_paths: List[str] (nullable, model only — fields to certify; empty = all)
  • token_id: str
  • ipfs_cid: str (nullable — IPFS CID of the signed VC after certification)
  • allowed_claim_email: str (nullable, item only)
  • created_at, updated_at: datetime

CreatePassportRequest

  • application: UUID (required)
  • network: str (default: StarknetSepolia)
  • granularity: str (required — model, batch, or item)
  • modelNumber: str (identifier for model-level)
  • batchNumber: str (identifier for batch-level)
  • itemNumber: str (identifier for item-level)
  • data: Dict[str, Any] (passport data)
  • certifiedPaths: List[str] (model only — dot-notation paths to certify; omit or [] = all)
  • allowedClaimEmail: str (item only — triggers minting)

UpdatePassportRequest

  • data: Dict[str, Any] (passport data)
  • certifiedPaths: List[str] (model only — dot-notation paths to certify)
  • allowedClaimEmail: str (item only)

API Endpoints

All operations go through a single unified endpoint:

Endpoint Method Description
/v1/dpp/passports GET List passports (filterable by granularity)
/v1/dpp/passports/:id GET Get a passport
/v1/dpp/passports POST Create a passport
/v1/dpp/passports/:id PATCH Update a passport
/v1/dpp/passports/:id DELETE Delete a passport

Migrating from 0.0.x to 1.0.0

Breaking changes

  • Passport status is now always published. The status field is no longer accepted in create or update requests.

Restored

  • certifiedPaths — available again on CreatePassportRequest, UpdatePassportRequest, and DppPassport. Was present in the old product API (0.0.6), lost during the passport migration (0.0.8), now restored on passport models. Selects which fields from data are included in the certificate. Omit or set to [] to certify everything.

Migration steps

  1. Update the client: pip install --upgrade keyban-api-client
  2. Remove any status field from your create/update calls (or ignore — the API will reject it).
  3. Existing calls without certifiedPaths continue to work as before (all data is certified).

Changelog

1.0.0 (2026-04-14)

  • Restore certifiedPaths on passport models (create, update, response)
  • Passports are always published — status no longer configurable via API
  • Smart re-certification: only re-certifies when the resulting certificate content actually changes
  • Remove last_certificate_hash from response model (internal field)

License

This client is part of the DAP (Digital Asset Platform) by Keyban project.

Project details


Download files

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

Source Distribution

keyban_api_client-1.0.0.tar.gz (15.6 kB view details)

Uploaded Source

Built Distribution

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

keyban_api_client-1.0.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file keyban_api_client-1.0.0.tar.gz.

File metadata

  • Download URL: keyban_api_client-1.0.0.tar.gz
  • Upload date:
  • Size: 15.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for keyban_api_client-1.0.0.tar.gz
Algorithm Hash digest
SHA256 85b1a7455b7e3d03401deb84d84da7abb25b769769c5904e839368a53b0d65cc
MD5 0b227362929cbe493aa357cbe256ff51
BLAKE2b-256 d3dec2b317ea605a83c6f29437f81ffa26991f9b6bf9db0da2a9601ccbec76fd

See more details on using hashes here.

File details

Details for the file keyban_api_client-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for keyban_api_client-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2b84bee421e665d17a450c10470bba6e7d27549445c25611de269eb4376c2b90
MD5 b8e1532f23046d4d3cc37df762ec1780
BLAKE2b-256 4c440446ef37231a0ae506a1bfb81c4f8f4c72c6eb628a6ead2d325969a7a5c6

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