Metadata-Version: 2.4
Name: humanos
Version: 1.0.1
Summary: Official Humanos API SDK for Python with automatic request signing and webhook verification
Author-email: Humanos <tech@humanos.tech>
Maintainer-email: Humanos <tech@humanos.tech>
License: MIT
Project-URL: Homepage, https://humanos.id
Project-URL: Documentation, https://humanos.mintlify.app
Project-URL: Repository, https://github.com/Humanos-App/humanos-sdks
Project-URL: Bug Tracker, https://github.com/Humanos-App/humanos-sdks/issues
Project-URL: Changelog, https://github.com/Humanos-App/humanos-sdks/blob/main/python/CHANGELOG.md
Keywords: humanos,api,sdk,verifiable-credentials,did,identity,kyc,authentication,credentials
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Requires-Dist: cryptography>=3.4.0
Requires-Dist: urllib3>=1.25.3
Requires-Dist: python-dateutil>=2.8.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: typing-extensions>=4.0.0
Provides-Extra: flask
Requires-Dist: flask>=2.0.0; extra == "flask"
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.68.0; extra == "fastapi"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.20.0; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
Dynamic: license-file

# Humanos SDK for Python

Official Python SDK for the [Humanos](https://humanos.id) API. Provides automatic request signing, webhook verification and decryption, and full API access for credential management.

[![PyPI version](https://badge.fury.io/py/humanos.svg)](https://pypi.org/project/humanos/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- **Automatic Request Signing** - All API requests are signed with HMAC-SHA256
- **Webhook Verification** - Verify signatures and decrypt encrypted payloads
- **Type Hints** - Full type annotations with Pydantic models
- **Simple API** - Clean interface for all Humanos endpoints

## Getting Started

### 1. Install the SDK

```bash
pip install humanos
```

### 2. Create an Account

Sign up at [humanos.id](https://humanos.id) and create your organization.

### 3. Get Your API Keys

In the Humanos Dashboard, go to **Settings > API Keys** and copy:

- **API Key** - Used to authenticate requests
- **Signature Secret** - Used to sign requests with HMAC-SHA256

### 4. Get Your Webhook Keys

In the Humanos Dashboard, go to **Settings > Webhooks** and copy:

- **Webhook Signature Secret** - Used to verify incoming webhook signatures
- **Webhook Encryption Secret** - Used to decrypt webhook payloads
- **Webhook Encryption Salt** - Used alongside the encryption secret

### 5. Initialize the Client

```python
from humanos_sdk import HumanosClient, HumanosClientConfig

client = HumanosClient(HumanosClientConfig(
    base_path="https://api.humanos.id",
    api_key=os.environ["HUMANOS_API_KEY"],
    signature_secret=os.environ["HUMANOS_SIGNATURE_SECRET"],
))
```

### 6. Make Your First API Call

Fetch all your credential requests:

```python
response = client.requests.get_requests()
print(response.data)
```

## Usage Examples

### Create a Credential Request

Send a credential request to one or more contacts using pre-configured resources:

```python
from humanos_sdk import GenerateRequestDto

request = client.requests.generate(GenerateRequestDto(
    contacts=["user@example.com"],
    security_level="CONTACT",
    resources_ids=["your-resource-id"],
))

print("Request ID:", request.id)
print("Credentials:", request.credentials)
```

You can also use group IDs to include all resources in a group:

```python
request = client.requests.generate(GenerateRequestDto(
    contacts=["user@example.com"],
    security_level="CONTACT",
    group_ids=["your-group-id"],
))
```

Or provide inline credential data directly:

```python
from humanos_sdk import CredentialDto, MandateDataDto, MandateDataDtoValue

request = client.requests.generate(GenerateRequestDto(
    contacts=["user@example.com"],
    security_level="CONTACT",
    credentials=[
        CredentialDto(
            scope="onboarding",
            type="JSON",
            name="Service Agreement",
            data=[
                MandateDataDto(label="Company", type="string", value=MandateDataDtoValue("Acme Corp")),
                MandateDataDto(label="Plan", type="string", value=MandateDataDtoValue("Enterprise")),
            ],
        ),
    ],
))
```

### Receive Webhooks

Humanos sends webhook events when credentials are signed, identity checks complete, or OTPs fail. Payloads are encrypted and signed.

The SDK provides `create_flask_webhook_handler` which handles signature verification and payload decryption automatically:

```python
from flask import Flask
from humanos_sdk import create_flask_webhook_handler, WebhookConfig

app = Flask(__name__)

webhook_config = WebhookConfig(
    signature_secret=os.environ["HUMANOS_WEBHOOK_SIGNATURE_SECRET"],
    encryption_secret=os.environ["HUMANOS_WEBHOOK_ENCRYPTION_SECRET"],
    encryption_salt=os.environ["HUMANOS_WEBHOOK_ENCRYPTION_SALT"],
)

def on_webhook(payload):
    print("Event type:", payload.get("eventType"))

    event_type = payload.get("eventType")
    if event_type == "credential":
        print("Credential signed:", payload.get("requestId"))
    elif event_type == "identity":
        print("Identity verified:", payload.get("requestId"))
    elif event_type == "otp.failed":
        print("OTP failed:", payload.get("requestId"))
    elif event_type == "test":
        print("Test event received")

app.add_url_rule(
    "/webhook",
    "webhook",
    create_flask_webhook_handler(webhook_config, on_webhook),
    methods=["POST"],
)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=3000)
```

For local development, use [ngrok](https://ngrok.com) to expose your server:

```bash
ngrok http 3000
```

Then set the ngrok URL (e.g. `https://xxxx.ngrok-free.app/webhook`) as your webhook URL in the Humanos Dashboard under **Settings > Webhooks**.

## API Reference

### Resources

```python
# List resources
resources = client.resources.get_resources()

# List resource groups
groups = client.resources.get_groups()
```

### Requests

```python
# List requests
requests = client.requests.get_requests()

# Get request details
detail = client.requests.get_request_detail(request_id)

# Create a credential request
request = client.requests.generate(GenerateRequestDto(...))

# Cancel a request
client.requests.cancel_request(request_id)

# Resend OTP
client.requests.resend_otp(request_id, contact="user@example.com")
```

### Users

```python
from humanos_sdk import CreateSubjectDto, IdentityDto

# Create or update users
users = client.users.create([
    CreateSubjectDto(
        contact="user@example.com",
        internal_id="your-internal-id",
        identity=IdentityDto(
            full_name="John Doe",
            birth="1990-01-01",
            doc_id="123456789",
            country_alpha3="USA",
        ),
    )
])
```

### Credentials

```python
# Get credential by ID
credential = client.credentials.get_credential(credential_id)

# Get credential with PDF
credential = client.credentials.get_credential(credential_id, include_pdf=True)
```

## Error Handling

The SDK raises `ApiException` for failed requests. The exception includes the HTTP status and response body:

```python
from humanos_sdk import ApiException

try:
    request = client.requests.generate(GenerateRequestDto(...))
except ApiException as e:
    print(f"Status: {e.status}")
    print(f"Body: {e.body}")
except Exception as e:
    print(f"Error: {e}")
```

## Documentation

- [API Documentation](https://humanos.mintlify.app/)
- [Humanos Website](https://humanos.id)

## Support

- **Email**: tech@humanos.tech

## License

MIT License - see [LICENSE](./LICENSE) file for details.
