Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
shell: bash
run: |-
curl https://openapi-v2.exoscale.com/source.json | ./.sort-enums.py | jq > exoscale/openapi.json

curl https://partner-api.exoscale.com/v1.alpha/openapi.json | ./.sort-enums.py | jq > exoscale/partner-api.json
- name: Commit and push if changed
run: |-
git config user.name "Automated"
Expand Down
7 changes: 7 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
---------

0.15.0 (unreleased)
-------------------

* Add Partner API client for distributor operations
* Partner API client follows same patterns as V2 API
* Automatic hourly updates of Partner API OpenAPI spec

0.14.0 (2025-08-28)
-------------------

Expand Down
8 changes: 8 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@ This provides Python bindings for the `Exoscale`_ cloud platform API.
versions: Python 3.9+. Older Python versions may be compatible but such
compatibility is not guaranteed.

Installation
------------

Install the package using pip::

pip install exoscale

.. toctree::
:maxdepth: 2

v2
partner
changes
81 changes: 81 additions & 0 deletions docs/partner.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
Partner API
===========

The Partner API client provides access to distributor operations for managing
sub-organizations in Exoscale.

Basic Usage
-----------

Creating a client
~~~~~~~~~~~~~~~~~

.. code-block:: python

from exoscale.api.partner import Client

# Create client with API credentials
client = Client(
key="EXO...",
secret="..."
)

Managing Organizations
~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

# List all distributor organizations
result = client.list_distributor_organizations()
for org in result['organizations']:
print(f"{org['name']} - {org['id']}")

# Create a new organization
new_org = client.create_distributor_organization(
organization={
"name": "Customer Corp",
"address": "123 Business Ave",
"city": "Zurich",
"postcode": "8001",
"country": "CH",
"owner-email": "admin@customer.com",
"client-id": "internal-123" # Optional
}
)

# Activate/Suspend organizations
client.activate_distributor_organization(id=org_id)
client.suspend_distributor_organization(id=org_id)

# Get usage information
usage = client.list_distributor_organization_usage(
id=org_id,
period="2025-01"
)

Error Handling
--------------

The Partner API client uses the same error handling as the V2 API:

.. code-block:: python

from exoscale.api.exceptions import (
ExoscaleAPIAuthException,
ExoscaleAPIClientException,
ExoscaleAPIServerException
)

try:
client.get_distributor_organization(id="invalid")
except ExoscaleAPIClientException as e:
print(f"Client error: {e}")
except ExoscaleAPIServerException as e:
print(f"Server error: {e}")

API Reference
-------------

.. autoclass:: exoscale.api.partner.Client
:members:
:inherited-members:
1 change: 1 addition & 0 deletions exoscale/api/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def _return_docstring(api_spec, operation):

return "\n ".join(status_codes_docs)


class BaseClient:
_api_spec = None
_by_operation = None
Expand Down
59 changes: 59 additions & 0 deletions exoscale/api/partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Exoscale Partner API client

This module provides a client for the Exoscale Partner API, which allows
distributors to manage sub-organizations.
"""

import json
from pathlib import Path

from .generator import create_client_class
from .v2 import Client as V2Client


with open(Path(__file__).parent.parent / "partner-api.json", "r") as f:
partner_api_spec = json.load(f)
BasePartnerClient = create_client_class(partner_api_spec)


class Client(BasePartnerClient):
"""
Partner API client with Exoscale authentication.

This client provides access to distributor operations for managing
sub-organizations. It uses the same authentication mechanism as the
V2 API client.

Args:
key (str): Exoscale API key
secret (str): Exoscale API secret
url (str): Override endpoint URL (optional)
zone (str): Exoscale zone (optional)

Example:
>>> from exoscale.api.partner import Client
>>> client = Client("EXO...", "secret")
>>> orgs = client.list_distributor_organizations()
"""

def __init__(self, key, secret, *args, url=None, **kwargs):
# Initialize with Partner API endpoint
partner_url = (
url if url else "https://partner-api.exoscale.com/v1.alpha"
)
super().__init__(*args, url=partner_url, **kwargs)

# Reuse the v2 client's authentication mechanism
v2_client = V2Client(key, secret, *args, url=url, **kwargs)

self.http_client = v2_client.http_client
self.key = key

self._v2_client = v2_client

def __repr__(self):
return (
f"<Client endpoint={self.endpoint} "
f"key={self.key} secret=**masked**>"
)
Loading
Loading