# Distru Python SDK
Official Python SDK for the [Distru API](https://distru.com) - Cannabis supply chain management platform.
[](https://badge.fury.io/py/distru-sdk)
[](https://pypi.org/project/distru-sdk/)
[](https://opensource.org/licenses/MIT)
## Installation
```bash
pip install distru-sdk
```
## Quick Start
```python
from distru_sdk import DistruClient
# Initialize the client with your API token
client = DistruClient(api_token="your_api_token_here")
# List products
products = client.products.list()
for product in products.auto_paginate():
print(f"{product['name']} - ${product['sale_price']}")
# Create an order
order = client.orders.create(
company_relationship_id=123,
order_date="2025-10-06T12:00:00Z",
order_items=[
{
"product_id": "prod-uuid-123",
"quantity": 10,
"unit_price": "15.00"
}
]
)
print(f"Order created: {order['order_number']}")
```
## Authentication
The Distru API uses JWT Bearer token authentication. To get an API token:
1. Log into your Distru account
2. Navigate to **Settings** → **API Keys**
3. Click **Create API Key**
4. Copy the generated token
5. Store it securely (never commit to source control!)
```python
# Initialize client
client = DistruClient(api_token="your_api_token_here")
# Optional: Configure timeout and retries
client = DistruClient(
api_token="your_api_token_here",
timeout=60.0, # Request timeout in seconds
max_retries=5 # Maximum retry attempts
)
```
## Usage
### Products
```python
# List all products
products = client.products.list()
# Auto-paginate through all results
for product in products.auto_paginate():
print(product['name'])
# Search products
products = client.products.list(search="Blue Dream")
# Get a specific product
product = client.products.get("prod-uuid-123")
# Create a product
product = client.products.create(
name="Blue Dream 1g",
sku="BD-1G",
unit_type_id=1,
inventory_tracking_method="BATCH",
sale_price="15.00",
wholesale_price="10.00"
)
# Update a product
product = client.products.update(
"prod-uuid-123",
sale_price="17.00",
wholesale_price="11.00"
)
# Delete a product
client.products.delete("prod-uuid-123")
```
### Orders
```python
# List orders
orders = client.orders.list()
# Filter orders
orders = client.orders.list(
status="Submitted",
customer_id=123,
from_date="2025-01-01",
to_date="2025-12-31"
)
# Get a specific order
order = client.orders.get("order-uuid-123")
# Create an order
order = client.orders.create(
company_relationship_id=123,
order_date="2025-10-06T12:00:00Z",
due_date="2025-10-20T12:00:00Z",
order_items=[
{
"product_id": "prod-uuid-1",
"quantity": 10,
"unit_price": "15.00"
},
{
"product_id": "prod-uuid-2",
"quantity": 5,
"unit_price": "25.00"
}
]
)
```
### Invoices
```python
# List invoices
invoices = client.invoices.list()
# Filter invoices
invoices = client.invoices.list(
status="Not Paid",
customer_id=123
)
# Get a specific invoice
invoice = client.invoices.get(456)
# Create an invoice
invoice = client.invoices.create(
order_id="order-uuid-123",
invoice_date="2025-10-06T12:00:00Z",
due_date="2025-10-20T12:00:00Z",
invoice_items=[
{
"order_item_id": "order-item-uuid-1",
"quantity": 10
}
]
)
# Add a payment to an invoice
payment = client.invoices.add_payment(
456,
amount="150.00",
payment_date="2025-10-06T12:00:00Z",
payment_method_id=1
)
```
### Inventory
```python
# Get current inventory
inventory = client.inventory.list()
# Include cost information
inventory = client.inventory.list(include_costs=True)
# Filter by location
inventory = client.inventory.list(location_id=1)
# Filter by product
inventory = client.inventory.list(product_id="prod-uuid-123")
```
### Companies (Customers/Vendors)
```python
# List all companies
companies = client.companies.list()
# Search companies
companies = client.companies.list(search="Acme")
# Filter by state
companies = client.companies.list(us_state="CA")
# Get a specific company
company = client.companies.get(123)
```
### Batches
```python
# List batches
batches = client.batches.list()
# Filter by product
batches = client.batches.list(product_id="prod-uuid-123")
# Create a batch
batch = client.batches.create(
product_id="prod-uuid-123",
batch_number="BATCH-001",
harvest_date="2025-09-01T00:00:00Z",
expiration_date="2026-09-01T00:00:00Z"
)
```
### Purchases
```python
# List purchases
purchases = client.purchases.list()
# Create a purchase order
purchase = client.purchases.create(
company_relationship_id=456,
purchase_date="2025-10-06T12:00:00Z",
purchase_items=[
{
"product_id": "prod-uuid-1",
"quantity": 100,
"unit_cost": "8.00"
}
]
)
# Add a payment
payment = client.purchases.add_payment(
789,
amount="800.00",
payment_date="2025-10-06T12:00:00Z"
)
```
## Pagination
All list endpoints return paginated results. The SDK provides helper methods for easy pagination:
### Auto-Pagination
```python
# Automatically fetch all pages
products = client.products.list()
for product in products.auto_paginate():
print(product['name'])
```
### Manual Pagination
```python
# Iterate page by page
response = client.products.list()
for page in response.iter_pages():
print(f"Processing page with {len(page)} items")
for product in page:
print(product['name'])
```
### Page-by-Page
```python
# Fetch specific pages
page_1 = client.products.list(page=1, limit=100)
page_2 = client.products.list(page=2, limit=100)
```
## Error Handling
The SDK provides specific exception classes for different error types:
```python
from distru_sdk.exceptions import (
DistruAPIError,
AuthenticationError,
AuthorizationError,
NotFoundError,
ValidationError,
RateLimitError,
ServerError,
NetworkError,
TimeoutError,
)
try:
order = client.orders.get("invalid-uuid")
except NotFoundError as e:
print(f"Order not found: {e.message}")
except AuthenticationError as e:
print(f"Invalid API token: {e.message}")
except RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after} seconds")
except ValidationError as e:
print(f"Validation error: {e.message}")
print(f"Details: {e.details}")
except ServerError as e:
print(f"Server error: {e.message}")
except NetworkError as e:
print(f"Network error: {e.message}")
except TimeoutError as e:
print(f"Request timed out: {e.message}")
except DistruAPIError as e:
print(f"API error: {e.message}")
```
## Webhooks (Beta)
Handle webhook events from Distru:
```python
from distru_sdk.webhooks import WebhookHandler
# Create webhook handler
handler = WebhookHandler()
# Register event handlers
@handler.on('ORDER')
def handle_order_event(event):
if not event.before_changes: # New order
print(f"New order: {event.after_changes['order_number']}")
elif not event.after_changes: # Deleted order
print(f"Order deleted: {event.before_changes['order_number']}")
else: # Updated order
print(f"Order updated: {event.after_changes['order_number']}")
@handler.on('INVOICE')
def handle_invoice_event(event):
print(f"Invoice event: {event.type}")
# In your web framework (Flask, FastAPI, Django, etc.)
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhooks', methods=['POST'])
def webhook_endpoint():
payload = request.get_json()
handler.process(payload)
return {'status': 'ok'}
```
## Data Consistency
The Distru API uses eventual consistency. Changes may take up to **1 second** to propagate to GET endpoints.
**Best Practices:**
- Use the returned data from create/update operations immediately
- For critical operations, add a small delay before fetching updated data
- Implement idempotency using unique identifiers
```python
import time
# Create an order
order = client.orders.create(...)
# The response contains the created order immediately
print(order['order_number']) # Available immediately
# If you need to fetch it again, wait briefly
time.sleep(1.5)
order = client.orders.get(order['id']) # Now guaranteed to be available
```
## Rate Limiting
The SDK automatically handles rate limiting with exponential backoff:
- Automatic retry on 429 (rate limit) and 5xx errors
- Exponential backoff: 1s, 2s, 4s, 8s, 10s (max)
- Maximum 3 retries by default (configurable)
- Respects `Retry-After` headers
```python
# Configure retry behavior
client = DistruClient(
api_token="your_token",
max_retries=5, # Increase max retries
timeout=60.0 # Increase timeout
)
```
## Advanced Usage
### Context Manager
```python
# Automatically close connection
with DistruClient(api_token="your_token") as client:
products = client.products.list()
for product in products.auto_paginate():
print(product['name'])
# Connection closed automatically
```
### Custom HTTP Client
```python
import httpx
# Use custom httpx client
http_client = httpx.Client(
timeout=60.0,
limits=httpx.Limits(max_keepalive_connections=5)
)
client = DistruClient(
api_token="your_token",
http_client=http_client
)
```
## Requirements
- Python 3.8+
- httpx >= 0.25.0
- pydantic >= 2.0.0
## Development
### Setup
```bash
# Clone repository
git clone https://github.com/DistruApp/distru-api-sdk.git
cd distru-api-sdk/python
# Install in development mode
pip install -e ".[dev]"
```
### Running Tests
```bash
# Run all tests
pytest
# Run with coverage
pytest --cov=distru_sdk --cov-report=html
# Run specific test file
pytest tests/test_products.py
```
### Code Quality
```bash
# Format code
black distru_sdk tests
# Sort imports
isort distru_sdk tests
# Type checking
mypy distru_sdk
# Linting
flake8 distru_sdk tests
```
## Support
- **Documentation**: [GitHub Repository](https://github.com/DistruApp/distru-api-sdk)
- **Issues**: [GitHub Issues](https://github.com/DistruApp/distru-api-sdk/issues)
- **Email**: [support@distru.com](mailto:support@distru.com)
## License
MIT License - see [LICENSE](../LICENSE) file for details.
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for version history and changes.
Raw data
{
"_id": null,
"home_page": "https://github.com/DistruApp/distru-api-sdk",
"name": "distru-sdk",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "distru, api, sdk, cannabis, supply-chain, inventory, compliance",
"author": "Distru Inc.",
"author_email": "\"Distru Inc.\" <support@distru.com>",
"download_url": "https://files.pythonhosted.org/packages/97/d2/364256ef7901cd6ee939040e21e81c653c69fa75fcdcf3110bc7322f5614/distru_sdk-1.0.0.tar.gz",
"platform": null,
"description": "# Distru Python SDK\n\nOfficial Python SDK for the [Distru API](https://distru.com) - Cannabis supply chain management platform.\n\n[](https://badge.fury.io/py/distru-sdk)\n[](https://pypi.org/project/distru-sdk/)\n[](https://opensource.org/licenses/MIT)\n\n## Installation\n\n```bash\npip install distru-sdk\n```\n\n## Quick Start\n\n```python\nfrom distru_sdk import DistruClient\n\n# Initialize the client with your API token\nclient = DistruClient(api_token=\"your_api_token_here\")\n\n# List products\nproducts = client.products.list()\nfor product in products.auto_paginate():\n print(f\"{product['name']} - ${product['sale_price']}\")\n\n# Create an order\norder = client.orders.create(\n company_relationship_id=123,\n order_date=\"2025-10-06T12:00:00Z\",\n order_items=[\n {\n \"product_id\": \"prod-uuid-123\",\n \"quantity\": 10,\n \"unit_price\": \"15.00\"\n }\n ]\n)\nprint(f\"Order created: {order['order_number']}\")\n```\n\n## Authentication\n\nThe Distru API uses JWT Bearer token authentication. To get an API token:\n\n1. Log into your Distru account\n2. Navigate to **Settings** \u2192 **API Keys**\n3. Click **Create API Key**\n4. Copy the generated token\n5. Store it securely (never commit to source control!)\n\n```python\n# Initialize client\nclient = DistruClient(api_token=\"your_api_token_here\")\n\n# Optional: Configure timeout and retries\nclient = DistruClient(\n api_token=\"your_api_token_here\",\n timeout=60.0, # Request timeout in seconds\n max_retries=5 # Maximum retry attempts\n)\n```\n\n## Usage\n\n### Products\n\n```python\n# List all products\nproducts = client.products.list()\n\n# Auto-paginate through all results\nfor product in products.auto_paginate():\n print(product['name'])\n\n# Search products\nproducts = client.products.list(search=\"Blue Dream\")\n\n# Get a specific product\nproduct = client.products.get(\"prod-uuid-123\")\n\n# Create a product\nproduct = client.products.create(\n name=\"Blue Dream 1g\",\n sku=\"BD-1G\",\n unit_type_id=1,\n inventory_tracking_method=\"BATCH\",\n sale_price=\"15.00\",\n wholesale_price=\"10.00\"\n)\n\n# Update a product\nproduct = client.products.update(\n \"prod-uuid-123\",\n sale_price=\"17.00\",\n wholesale_price=\"11.00\"\n)\n\n# Delete a product\nclient.products.delete(\"prod-uuid-123\")\n```\n\n### Orders\n\n```python\n# List orders\norders = client.orders.list()\n\n# Filter orders\norders = client.orders.list(\n status=\"Submitted\",\n customer_id=123,\n from_date=\"2025-01-01\",\n to_date=\"2025-12-31\"\n)\n\n# Get a specific order\norder = client.orders.get(\"order-uuid-123\")\n\n# Create an order\norder = client.orders.create(\n company_relationship_id=123,\n order_date=\"2025-10-06T12:00:00Z\",\n due_date=\"2025-10-20T12:00:00Z\",\n order_items=[\n {\n \"product_id\": \"prod-uuid-1\",\n \"quantity\": 10,\n \"unit_price\": \"15.00\"\n },\n {\n \"product_id\": \"prod-uuid-2\",\n \"quantity\": 5,\n \"unit_price\": \"25.00\"\n }\n ]\n)\n```\n\n### Invoices\n\n```python\n# List invoices\ninvoices = client.invoices.list()\n\n# Filter invoices\ninvoices = client.invoices.list(\n status=\"Not Paid\",\n customer_id=123\n)\n\n# Get a specific invoice\ninvoice = client.invoices.get(456)\n\n# Create an invoice\ninvoice = client.invoices.create(\n order_id=\"order-uuid-123\",\n invoice_date=\"2025-10-06T12:00:00Z\",\n due_date=\"2025-10-20T12:00:00Z\",\n invoice_items=[\n {\n \"order_item_id\": \"order-item-uuid-1\",\n \"quantity\": 10\n }\n ]\n)\n\n# Add a payment to an invoice\npayment = client.invoices.add_payment(\n 456,\n amount=\"150.00\",\n payment_date=\"2025-10-06T12:00:00Z\",\n payment_method_id=1\n)\n```\n\n### Inventory\n\n```python\n# Get current inventory\ninventory = client.inventory.list()\n\n# Include cost information\ninventory = client.inventory.list(include_costs=True)\n\n# Filter by location\ninventory = client.inventory.list(location_id=1)\n\n# Filter by product\ninventory = client.inventory.list(product_id=\"prod-uuid-123\")\n```\n\n### Companies (Customers/Vendors)\n\n```python\n# List all companies\ncompanies = client.companies.list()\n\n# Search companies\ncompanies = client.companies.list(search=\"Acme\")\n\n# Filter by state\ncompanies = client.companies.list(us_state=\"CA\")\n\n# Get a specific company\ncompany = client.companies.get(123)\n```\n\n### Batches\n\n```python\n# List batches\nbatches = client.batches.list()\n\n# Filter by product\nbatches = client.batches.list(product_id=\"prod-uuid-123\")\n\n# Create a batch\nbatch = client.batches.create(\n product_id=\"prod-uuid-123\",\n batch_number=\"BATCH-001\",\n harvest_date=\"2025-09-01T00:00:00Z\",\n expiration_date=\"2026-09-01T00:00:00Z\"\n)\n```\n\n### Purchases\n\n```python\n# List purchases\npurchases = client.purchases.list()\n\n# Create a purchase order\npurchase = client.purchases.create(\n company_relationship_id=456,\n purchase_date=\"2025-10-06T12:00:00Z\",\n purchase_items=[\n {\n \"product_id\": \"prod-uuid-1\",\n \"quantity\": 100,\n \"unit_cost\": \"8.00\"\n }\n ]\n)\n\n# Add a payment\npayment = client.purchases.add_payment(\n 789,\n amount=\"800.00\",\n payment_date=\"2025-10-06T12:00:00Z\"\n)\n```\n\n## Pagination\n\nAll list endpoints return paginated results. The SDK provides helper methods for easy pagination:\n\n### Auto-Pagination\n\n```python\n# Automatically fetch all pages\nproducts = client.products.list()\nfor product in products.auto_paginate():\n print(product['name'])\n```\n\n### Manual Pagination\n\n```python\n# Iterate page by page\nresponse = client.products.list()\nfor page in response.iter_pages():\n print(f\"Processing page with {len(page)} items\")\n for product in page:\n print(product['name'])\n```\n\n### Page-by-Page\n\n```python\n# Fetch specific pages\npage_1 = client.products.list(page=1, limit=100)\npage_2 = client.products.list(page=2, limit=100)\n```\n\n## Error Handling\n\nThe SDK provides specific exception classes for different error types:\n\n```python\nfrom distru_sdk.exceptions import (\n DistruAPIError,\n AuthenticationError,\n AuthorizationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n ServerError,\n NetworkError,\n TimeoutError,\n)\n\ntry:\n order = client.orders.get(\"invalid-uuid\")\nexcept NotFoundError as e:\n print(f\"Order not found: {e.message}\")\nexcept AuthenticationError as e:\n print(f\"Invalid API token: {e.message}\")\nexcept RateLimitError as e:\n print(f\"Rate limited, retry after {e.retry_after} seconds\")\nexcept ValidationError as e:\n print(f\"Validation error: {e.message}\")\n print(f\"Details: {e.details}\")\nexcept ServerError as e:\n print(f\"Server error: {e.message}\")\nexcept NetworkError as e:\n print(f\"Network error: {e.message}\")\nexcept TimeoutError as e:\n print(f\"Request timed out: {e.message}\")\nexcept DistruAPIError as e:\n print(f\"API error: {e.message}\")\n```\n\n## Webhooks (Beta)\n\nHandle webhook events from Distru:\n\n```python\nfrom distru_sdk.webhooks import WebhookHandler\n\n# Create webhook handler\nhandler = WebhookHandler()\n\n# Register event handlers\n@handler.on('ORDER')\ndef handle_order_event(event):\n if not event.before_changes: # New order\n print(f\"New order: {event.after_changes['order_number']}\")\n elif not event.after_changes: # Deleted order\n print(f\"Order deleted: {event.before_changes['order_number']}\")\n else: # Updated order\n print(f\"Order updated: {event.after_changes['order_number']}\")\n\n@handler.on('INVOICE')\ndef handle_invoice_event(event):\n print(f\"Invoice event: {event.type}\")\n\n# In your web framework (Flask, FastAPI, Django, etc.)\nfrom flask import Flask, request\n\napp = Flask(__name__)\n\n@app.route('/webhooks', methods=['POST'])\ndef webhook_endpoint():\n payload = request.get_json()\n handler.process(payload)\n return {'status': 'ok'}\n```\n\n## Data Consistency\n\nThe Distru API uses eventual consistency. Changes may take up to **1 second** to propagate to GET endpoints.\n\n**Best Practices:**\n- Use the returned data from create/update operations immediately\n- For critical operations, add a small delay before fetching updated data\n- Implement idempotency using unique identifiers\n\n```python\nimport time\n\n# Create an order\norder = client.orders.create(...)\n\n# The response contains the created order immediately\nprint(order['order_number']) # Available immediately\n\n# If you need to fetch it again, wait briefly\ntime.sleep(1.5)\norder = client.orders.get(order['id']) # Now guaranteed to be available\n```\n\n## Rate Limiting\n\nThe SDK automatically handles rate limiting with exponential backoff:\n\n- Automatic retry on 429 (rate limit) and 5xx errors\n- Exponential backoff: 1s, 2s, 4s, 8s, 10s (max)\n- Maximum 3 retries by default (configurable)\n- Respects `Retry-After` headers\n\n```python\n# Configure retry behavior\nclient = DistruClient(\n api_token=\"your_token\",\n max_retries=5, # Increase max retries\n timeout=60.0 # Increase timeout\n)\n```\n\n## Advanced Usage\n\n### Context Manager\n\n```python\n# Automatically close connection\nwith DistruClient(api_token=\"your_token\") as client:\n products = client.products.list()\n for product in products.auto_paginate():\n print(product['name'])\n# Connection closed automatically\n```\n\n### Custom HTTP Client\n\n```python\nimport httpx\n\n# Use custom httpx client\nhttp_client = httpx.Client(\n timeout=60.0,\n limits=httpx.Limits(max_keepalive_connections=5)\n)\n\nclient = DistruClient(\n api_token=\"your_token\",\n http_client=http_client\n)\n```\n\n## Requirements\n\n- Python 3.8+\n- httpx >= 0.25.0\n- pydantic >= 2.0.0\n\n## Development\n\n### Setup\n\n```bash\n# Clone repository\ngit clone https://github.com/DistruApp/distru-api-sdk.git\ncd distru-api-sdk/python\n\n# Install in development mode\npip install -e \".[dev]\"\n```\n\n### Running Tests\n\n```bash\n# Run all tests\npytest\n\n# Run with coverage\npytest --cov=distru_sdk --cov-report=html\n\n# Run specific test file\npytest tests/test_products.py\n```\n\n### Code Quality\n\n```bash\n# Format code\nblack distru_sdk tests\n\n# Sort imports\nisort distru_sdk tests\n\n# Type checking\nmypy distru_sdk\n\n# Linting\nflake8 distru_sdk tests\n```\n\n## Support\n\n- **Documentation**: [GitHub Repository](https://github.com/DistruApp/distru-api-sdk)\n- **Issues**: [GitHub Issues](https://github.com/DistruApp/distru-api-sdk/issues)\n- **Email**: [support@distru.com](mailto:support@distru.com)\n\n## License\n\nMIT License - see [LICENSE](../LICENSE) file for details.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for version history and changes.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Official Python SDK for the Distru API - Cannabis supply chain management",
"version": "1.0.0",
"project_urls": {
"Documentation": "https://github.com/DistruApp/distru-api-sdk/tree/main/python",
"Homepage": "https://distru.com",
"Issues": "https://github.com/DistruApp/distru-api-sdk/issues",
"Repository": "https://github.com/DistruApp/distru-api-sdk"
},
"split_keywords": [
"distru",
" api",
" sdk",
" cannabis",
" supply-chain",
" inventory",
" compliance"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "42bfff308079db94a5620cb28cbce1c189a4fa6aab11de97afc19bc0edaed213",
"md5": "d67d0c5b380e331bce14c7f0abf44961",
"sha256": "0319204b6a019c241e690d6c1a8c6eec11b0e8b81673e8ecd142aed65368f3fe"
},
"downloads": -1,
"filename": "distru_sdk-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d67d0c5b380e331bce14c7f0abf44961",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 32319,
"upload_time": "2025-10-06T21:15:55",
"upload_time_iso_8601": "2025-10-06T21:15:55.262905Z",
"url": "https://files.pythonhosted.org/packages/42/bf/ff308079db94a5620cb28cbce1c189a4fa6aab11de97afc19bc0edaed213/distru_sdk-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "97d2364256ef7901cd6ee939040e21e81c653c69fa75fcdcf3110bc7322f5614",
"md5": "87f32de0d9b44493b82898bffc815b34",
"sha256": "e11d0dcad90feb8e6ffc5dd1a01f216867470f8d2919b994e1905fe6e8dd3f6e"
},
"downloads": -1,
"filename": "distru_sdk-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "87f32de0d9b44493b82898bffc815b34",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 28467,
"upload_time": "2025-10-06T21:15:56",
"upload_time_iso_8601": "2025-10-06T21:15:56.417501Z",
"url": "https://files.pythonhosted.org/packages/97/d2/364256ef7901cd6ee939040e21e81c653c69fa75fcdcf3110bc7322f5614/distru_sdk-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-06 21:15:56",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "DistruApp",
"github_project": "distru-api-sdk",
"github_not_found": true,
"lcname": "distru-sdk"
}