> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nomiq.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Nomiq Python SDK — Complete Installation and Usage Guide

> Install and use the official Nomiq Python SDK to integrate AI-powered brand generation into Python applications and automation pipelines.

The `nomiq-python` package is the official SDK for integrating Nomiq's AI brand generation engine into Python applications. It provides a clean, synchronous client interface over the Nomiq REST API, handles bearer token authentication on every request, and includes a built-in HMAC verification helper for securing your webhook endpoints — everything you need to go from install to your first generated brand identity in minutes.

## Requirements

Before installing the SDK, confirm your environment meets the minimum version requirement:

* **Python 3.9 or higher** — the SDK uses type hints and language features introduced in Python 3.9.

***

<Steps>
  <Step title="Install the SDK">
    Install `nomiq-python` from PyPI using your preferred package manager.

    <CodeGroup>
      ```bash pip theme={null}
      pip install nomiq-python
      ```

      ```bash pip3 theme={null}
      pip3 install nomiq-python
      ```

      ```bash uv theme={null}
      uv add nomiq-python
      ```
    </CodeGroup>

    <Warning>
      Never hardcode your API key directly in your source files or commit it to version control. Always load secrets from environment variables or a secrets manager such as AWS Secrets Manager or HashiCorp Vault.
    </Warning>
  </Step>

  <Step title="Initialize the Client">
    Import the `nomiq` module and instantiate a `Client` by passing your API key. The client is the single entry point for all SDK methods and authenticates every request automatically.

    ```python theme={null}
    import os
    import nomiq

    client = nomiq.Client(api_key=os.environ['NOMIQ_API_KEY'])
    ```

    The `Client` attaches your key as a `Bearer` token on the `Authorization` header for every outbound request to `https://api.nomiq.com/v1`. For local development, use a `.env` file with a library such as `python-dotenv` to load `NOMIQ_API_KEY` into your environment before your script runs.
  </Step>

  <Step title="Create a Project">
    Projects are the top-level containers for all brand assets and generation history. You must create a project before you can dispatch a generation job.

    ```python theme={null}
    project = client.projects.create(
        name='Acme Corp Rebrand',
        description='Enterprise software client — Q3 rebrand initiative.',
    )

    print(project.id)   # "proj_1A2b3C4d5E"
    print(project.name) # "Acme Corp Rebrand"
    ```

    A successful response returns a project object you can immediately use:

    ```json theme={null}
    {
      "id": "proj_1A2b3C4d5E",
      "object": "project",
      "name": "Acme Corp Rebrand",
      "description": "Enterprise software client — Q3 rebrand initiative.",
      "created_at": 1677649420,
      "metadata": {}
    }
    ```
  </Step>

  <Step title="Generate a Brand">
    Call `client.brands.generate()` with your `project_id` and a detailed semantic `prompt`. Generation runs asynchronously — you receive a `202 Accepted` response with a job object immediately, and the completed assets are delivered to your webhook URL when the AI Engine finishes.

    ```python theme={null}
    job = client.brands.generate(
        project_id='proj_1A2b3C4d5E',
        prompt=(
            'A modern coffee shop in Brooklyn specializing in cold brew. '
            'The logo should feature a minimalistic cold brew glass with a '
            'deep indigo and cream color palette. Typography should be a '
            'clean sans-serif.'
        ),
    )

    print(job.status) # "queued"
    print(job.id)     # "job_9x8y7z6w"
    ```

    The returned job object confirms the request is in the queue:

    ```json theme={null}
    {
      "object": "job",
      "id": "job_9x8y7z6w",
      "project_id": "proj_1A2b3C4d5E",
      "status": "queued",
      "created_at": 1677649420
    }
    ```
  </Step>

  <Step title="Handle the Webhook">
    Configure your webhook endpoint URL in **Workspace Settings** and listen for `generation.success` or `generation.failed` events. Nomiq signs every webhook request with an HMAC-SHA256 signature in the `Nomiq-Signature` header — you must verify this before processing any payload.

    The example below shows a complete Flask webhook handler using Python's built-in `hmac` module for constant-time signature comparison.

    ```python theme={null}
    import os
    import hmac
    import hashlib
    from flask import Flask, request, jsonify

    app = Flask(__name__)
    WEBHOOK_SECRET = os.environ['NOMIQ_WEBHOOK_SECRET']

    @app.route('/webhook/nomiq', methods=['POST'])
    def nomiq_webhook():
        raw_body = request.get_data()
        incoming_sig = request.headers.get('Nomiq-Signature', '')

        # Compute the expected HMAC-SHA256 signature
        expected_sig = hmac.new(
            WEBHOOK_SECRET.encode('utf-8'),
            raw_body,
            hashlib.sha256,
        ).hexdigest()

        # Use compare_digest to prevent timing attacks
        if not hmac.compare_digest(expected_sig, incoming_sig):
            return jsonify(error='Invalid signature.'), 400

        event = request.get_json()

        if event['type'] == 'generation.success':
            job_id = event['data']['job_id']
            project_id = event['data']['project_id']
            assets = event['data']['assets']

            print(f'Job {job_id} complete for project {project_id}')
            print('Logo SVG:', assets['logo_svg'])
            print('Primary color:', assets['primary_color'])
            print('Font family:', assets['font_family'])

            # Queue further processing asynchronously; do not block this handler.

        elif event['type'] == 'generation.failed':
            print(f"Job {event['data']['job_id']} failed:", event['data']['error']['message'])

        # Return 200 immediately to acknowledge receipt.
        return jsonify(success=True), 200

    if __name__ == '__main__':
        app.run(port=3000)
    ```
  </Step>
</Steps>

***

## Projects

The `client.projects` namespace exposes the full Projects API, letting you create and manage project containers programmatically.

### Create a Project

```python theme={null}
project = client.projects.create(
    name='Velocity Fitness App',
    description='Brand identity for a B2C fitness tracking startup.',
)

print(project.id) # "proj_1A2b3C4d5E"
```

### Retrieve a Project

Fetch the current state of any existing project by its ID.

```python theme={null}
project = client.projects.retrieve('proj_1A2b3C4d5E')

print(project.name)       # "Velocity Fitness App"
print(project.created_at) # 1677649420
```

### List Projects

Returns all projects in your workspace sorted newest-first. The response supports cursor-based pagination via `limit` and `starting_after`.

```python theme={null}
response = client.projects.list(limit=20)

for project in response.data:
    print(f'{project.id}: {project.name}')

# Paginate to the next page using the last item's ID as the cursor.
if response.data:
    next_page = client.projects.list(
        limit=20,
        starting_after=response.data[-1].id,
    )
```

### Delete a Project

```python theme={null}
client.projects.delete('proj_1A2b3C4d5E')
```

<Warning>
  Deleting a project is permanent and irreversible. All associated generated assets, history nodes, and memory data are immediately removed from the database. This action cannot be undone.
</Warning>

***

## Brand Generation

Dispatch a brand generation job by providing a `project_id` and a rich semantic `prompt`. You can optionally pass a `webhook_url` to override the default delivery endpoint configured in your Workspace Settings on a per-request basis.

```python theme={null}
job = client.brands.generate(
    project_id='proj_1A2b3C4d5E',
    prompt=(
        'A boutique law firm in Chicago focused on intellectual property. '
        'Professional and authoritative tone. Navy blue and gold color '
        'palette with a classic serif typeface.'
    ),
    webhook_url='https://your-app.com/webhooks/nomiq',  # optional override
)

print(job.id)     # "job_9x8y7z6w"
print(job.status) # "queued"
```

Generation jobs typically complete within 3–10 seconds depending on asset complexity. Do not poll the API for status — Nomiq will `POST` the completed assets to your webhook endpoint automatically.

***

## Handling Webhooks

Nomiq delivers the completed brand assets via a `POST` request to your configured webhook URL. The full `generation.success` payload contains the SVG markup, primary color hex value, and font family:

```json theme={null}
{
  "event_id": "evt_5k6l7m8n",
  "type": "generation.success",
  "created_at": 1677649428,
  "data": {
    "job_id": "job_9x8y7z6w",
    "project_id": "proj_1A2b3C4d5E",
    "memory_id": "mem_X1y2Z3w4",
    "assets": {
      "logo_svg": "<svg>...</svg>",
      "primary_color": "#4f46e5",
      "font_family": "Inter"
    }
  }
}
```

The `memory_id` field identifies the Memory Node created for this generation. Store it alongside your job record — pass it back to `client.brands.generate()` as the `memory_id` parameter to refine this brand in a subsequent iteration rather than generating from scratch.

Return a `200 OK` response within 5 seconds of receiving the webhook. Offload any heavy work — database writes, file storage, downstream notifications — to an asynchronous task queue such as Celery or RQ. If Nomiq does not receive a `200` within the timeout window, it retries with exponential backoff.

***

## Error Handling

The SDK raises structured exceptions when the API returns a non-2xx response. Wrap your calls in `try/except` and inspect the exception's attributes to implement granular error handling.

```python theme={null}
import os
import nomiq
from nomiq.errors import NomiqAPIError

client = nomiq.Client(api_key=os.environ['NOMIQ_API_KEY'])

def safe_generate(project_id: str, prompt: str):
    try:
        job = client.brands.generate(
            project_id=project_id,
            prompt=prompt,
        )
        return job
    except NomiqAPIError as e:
        if e.code == 'authentication_error':
            print('Invalid API key. Check your NOMIQ_API_KEY environment variable.')
        elif e.code == 'rate_limit_exceeded':
            print(f'Rate limit exceeded. Retry after {e.retry_after} seconds.')
        elif e.code == 'invalid_project':
            print(f'Project not found: {project_id}')
        else:
            print(f'Nomiq API error [{e.code}]: {e.message}')
        return None
    except Exception as e:
        # Re-raise unexpected network or runtime errors
        raise
```

The `NomiqAPIError` exception exposes the following attributes for structured handling:

| Attribute     | Type          | Description                                                |
| ------------- | ------------- | ---------------------------------------------------------- |
| `code`        | `str`         | Machine-readable error code (e.g., `rate_limit_exceeded`). |
| `message`     | `str`         | Human-readable description of the error.                   |
| `status`      | `int`         | The HTTP status code returned by the API.                  |
| `retry_after` | `int \| None` | Seconds to wait before retrying (set on `429` responses).  |

***

<CardGroup cols={2}>
  <Card title="Node.js SDK" icon="node-js" href="/sdks/javascript">
    Use the official Nomiq Node.js SDK to integrate brand generation into JavaScript and TypeScript applications.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/generation">
    Explore the full REST API reference, including all endpoints, request parameters, and response schemas.
  </Card>
</CardGroup>
