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
34 changes: 33 additions & 1 deletion .sdk.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"id": "3d6cb3a1-0777-4d71-9f1d-ee4c757afc03",
"id": "8535dd0e-5fe8-4908-8220-9772d176fe80",
"tracked_paths": [
{
"editable": true,
Expand Down Expand Up @@ -29,6 +29,18 @@
"editable": true,
"path": "magic_hour/resources/v1/__init__.py"
},
{
"editable": true,
"path": "magic_hour/resources/v1/account/README.md"
},
{
"editable": true,
"path": "magic_hour/resources/v1/account/__init__.py"
},
{
"editable": true,
"path": "magic_hour/resources/v1/account/client.py"
},
{
"editable": true,
"path": "magic_hour/resources/v1/ai_clothes_changer/README.md"
Expand Down Expand Up @@ -433,6 +445,22 @@
"editable": true,
"path": "magic_hour/types/models/__init__.py"
},
{
"editable": false,
"path": "magic_hour/types/models/v1_account_list_response.py"
},
{
"editable": false,
"path": "magic_hour/types/models/v1_account_list_response_subscription.py"
},
{
"editable": false,
"path": "magic_hour/types/models/v1_account_list_response_subscription_discount.py"
},
{
"editable": false,
"path": "magic_hour/types/models/v1_account_list_response_subscription_price.py"
},
{
"editable": false,
"path": "magic_hour/types/models/v1_ai_clothes_changer_create_response.py"
Expand Down Expand Up @@ -917,6 +945,10 @@
"editable": true,
"path": "pyproject.toml"
},
{
"editable": false,
"path": "tests/test_v1_account_client.py"
},
{
"editable": false,
"path": "tests/test_v1_ai_clothes_changer_client.py"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ download_urls = result.downloads

## Module Documentation and Snippets

### [v1.account](magic_hour/resources/v1/account/README.md)

- [list](magic_hour/resources/v1/account/README.md#list) - Get account details

### [v1.ai_clothes_changer](magic_hour/resources/v1/ai_clothes_changer/README.md)

- [create](magic_hour/resources/v1/ai_clothes_changer/README.md#create) - AI Clothes Changer
Expand Down
1 change: 1 addition & 0 deletions magic_hour/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Submodules

- [account](resources/v1/account/README.md) - account
- [ai_clothes_changer](resources/v1/ai_clothes_changer/README.md) - ai_clothes_changer
- [ai_face_editor](resources/v1/ai_face_editor/README.md) - ai_face_editor
- [ai_gif_generator](resources/v1/ai_gif_generator/README.md) - ai_gif_generator
Expand Down
2 changes: 1 addition & 1 deletion magic_hour/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Environment(enum.Enum):
"""Pre-defined base URLs for the API"""

ENVIRONMENT = "https://api.magichour.ai"
MOCK_SERVER = "https://api.sideko.dev/v1/mock/magichour/magic-hour/0.78.1"
MOCK_SERVER = "https://api.sideko.dev/v1/mock/magichour/magic-hour/0.79.0"


def _get_base_url(
Expand Down
1 change: 1 addition & 0 deletions magic_hour/resources/v1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Submodules

- [account](account/README.md) - account
- [ai_clothes_changer](ai_clothes_changer/README.md) - ai_clothes_changer
- [ai_face_editor](ai_face_editor/README.md) - ai_face_editor
- [ai_gif_generator](ai_gif_generator/README.md) - ai_gif_generator
Expand Down
41 changes: 41 additions & 0 deletions magic_hour/resources/v1/account/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# v1.account

## Module Functions

### Get account details <a name="list"></a>

Get the current credit balance and subscription details of the account that owns the API key.

**API Endpoint**: `GET /v1/account`

#### Synchronous Client

```python
from magic_hour import Client
from os import getenv

client = Client(token=getenv("API_TOKEN"))
res = client.v1.account.list()
```

#### Asynchronous Client

```python
from magic_hour import AsyncClient
from os import getenv

client = AsyncClient(token=getenv("API_TOKEN"))
res = await client.v1.account.list()
```

#### Response

##### Type

[V1AccountListResponse](/magic_hour/types/models/v1_account_list_response.py)

##### Example

```python
{"credits": 12500, "email": "user@example.com", "id": "cuid-example", "subscription": {"billing_interval": "month", "cancel_at_period_end": False, "current_period_end": "2026-10-01T00:00:00.000Z", "discount": {"amount_off": 123, "percent_off": 20.0}, "name": "Pro", "price": {"amount": 4900, "currency": "usd"}, "status": "active"}, "tier": "pro"}
```
4 changes: 4 additions & 0 deletions magic_hour/resources/v1/account/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .client import AccountClient, AsyncAccountClient


__all__ = ["AccountClient", "AsyncAccountClient"]
85 changes: 85 additions & 0 deletions magic_hour/resources/v1/account/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import typing

from magic_hour.types import models
from make_api_request import (
AsyncBaseClient,
RequestOptions,
SyncBaseClient,
default_request_options,
)


class AccountClient:
def __init__(self, *, base_client: SyncBaseClient):
self._base_client = base_client

def list(
self, *, request_options: typing.Optional[RequestOptions] = None
) -> models.V1AccountListResponse:
"""
Get account details

Get the current credit balance and subscription details of the account that owns the API key.

GET /v1/account

Args:
request_options: Additional options to customize the HTTP request

Returns:
200

Raises:
ApiError: A custom exception class that provides additional context
for API errors, including the HTTP status code and response body.

Examples:
```py
client.v1.account.list()
```
"""
return self._base_client.request(
method="GET",
path="/v1/account",
auth_names=["bearerAuth"],
cast_to=models.V1AccountListResponse,
request_options=request_options or default_request_options(),
)


class AsyncAccountClient:
def __init__(self, *, base_client: AsyncBaseClient):
self._base_client = base_client

async def list(
self, *, request_options: typing.Optional[RequestOptions] = None
) -> models.V1AccountListResponse:
"""
Get account details

Get the current credit balance and subscription details of the account that owns the API key.

GET /v1/account

Args:
request_options: Additional options to customize the HTTP request

Returns:
200

Raises:
ApiError: A custom exception class that provides additional context
for API errors, including the HTTP status code and response body.

Examples:
```py
await client.v1.account.list()
```
"""
return await self._base_client.request(
method="GET",
path="/v1/account",
auth_names=["bearerAuth"],
cast_to=models.V1AccountListResponse,
request_options=request_options or default_request_options(),
)
3 changes: 3 additions & 0 deletions magic_hour/resources/v1/client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from magic_hour.resources.v1.account import AccountClient, AsyncAccountClient
from magic_hour.resources.v1.ai_clothes_changer import (
AiClothesChangerClient,
AsyncAiClothesChangerClient,
Expand Down Expand Up @@ -155,6 +156,7 @@ def __init__(self, *, base_client: SyncBaseClient):
self.audio_to_video = AudioToVideoClient(base_client=self._base_client)
self.ai_video_editor = AiVideoEditorClient(base_client=self._base_client)
self.character_replace = CharacterReplaceClient(base_client=self._base_client)
self.account = AccountClient(base_client=self._base_client)


class AsyncV1Client:
Expand Down Expand Up @@ -213,3 +215,4 @@ def __init__(self, *, base_client: AsyncBaseClient):
self.character_replace = AsyncCharacterReplaceClient(
base_client=self._base_client
)
self.account = AsyncAccountClient(base_client=self._base_client)
12 changes: 12 additions & 0 deletions magic_hour/types/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
from .v1_account_list_response import V1AccountListResponse
from .v1_account_list_response_subscription import V1AccountListResponseSubscription
from .v1_account_list_response_subscription_discount import (
V1AccountListResponseSubscriptionDiscount,
)
from .v1_account_list_response_subscription_price import (
V1AccountListResponseSubscriptionPrice,
)
from .v1_ai_clothes_changer_create_response import V1AiClothesChangerCreateResponse
from .v1_ai_face_editor_create_response import V1AiFaceEditorCreateResponse
from .v1_ai_gif_generator_create_response import V1AiGifGeneratorCreateResponse
Expand Down Expand Up @@ -59,6 +67,10 @@


__all__ = [
"V1AccountListResponse",
"V1AccountListResponseSubscription",
"V1AccountListResponseSubscriptionDiscount",
"V1AccountListResponseSubscriptionPrice",
"V1AiClothesChangerCreateResponse",
"V1AiFaceEditorCreateResponse",
"V1AiGifGeneratorCreateResponse",
Expand Down
51 changes: 51 additions & 0 deletions magic_hour/types/models/v1_account_list_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pydantic
import typing
import typing_extensions

from .v1_account_list_response_subscription import V1AccountListResponseSubscription


class V1AccountListResponse(pydantic.BaseModel):
"""
V1AccountListResponse
"""

model_config = pydantic.ConfigDict(
arbitrary_types_allowed=True,
populate_by_name=True,
)

credits: int = pydantic.Field(
alias="credits",
)
"""
Credits currently available to spend. Includes subscription credits and any purchased credit packs.
"""
email: typing.Optional[str] = pydantic.Field(
alias="email",
)
"""
Email address of the account.
"""
id: str = pydantic.Field(
alias="id",
)
"""
Unique ID of the account that owns the API key.
"""
subscription: typing.Optional[V1AccountListResponseSubscription] = pydantic.Field(
alias="subscription",
)
"""
Details of the account's subscription plan. `null` if the account has no subscription, e.g. a free account, an account that only purchased credit packs, or an account on usage-based API pricing.

Reflects the plan currently configured on the subscription. If a plan change is scheduled, `tier` stays on the current plan until the next payment succeeds, so `tier` and `name` can briefly disagree.
"""
tier: typing_extensions.Literal["business", "creator", "free", "pro"] = (
pydantic.Field(
alias="tier",
)
)
"""
Subscription tier in effect for the account. `free` if there is no active subscription, including while a subscription is `past_due`.
"""
69 changes: 69 additions & 0 deletions magic_hour/types/models/v1_account_list_response_subscription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import pydantic
import typing
import typing_extensions

from .v1_account_list_response_subscription_discount import (
V1AccountListResponseSubscriptionDiscount,
)
from .v1_account_list_response_subscription_price import (
V1AccountListResponseSubscriptionPrice,
)


class V1AccountListResponseSubscription(pydantic.BaseModel):
"""
Details of the account's subscription plan. `null` if the account has no subscription, e.g. a free account, an account that only purchased credit packs, or an account on usage-based API pricing.

Reflects the plan currently configured on the subscription. If a plan change is scheduled, `tier` stays on the current plan until the next payment succeeds, so `tier` and `name` can briefly disagree.
"""

model_config = pydantic.ConfigDict(
arbitrary_types_allowed=True,
populate_by_name=True,
)

billing_interval: typing.Optional[typing_extensions.Literal["month", "year"]] = (
pydantic.Field(
alias="billing_interval",
)
)
"""
How often the subscription is billed. `null` if unknown.
"""
cancel_at_period_end: bool = pydantic.Field(
alias="cancel_at_period_end",
)
"""
Whether the subscription is scheduled to end at `current_period_end` instead of renewing. The subscription stays usable until then.
"""
current_period_end: typing.Optional[str] = pydantic.Field(
alias="current_period_end",
)
"""
End of the current billing period, in ISO 8601 format. The subscription renews at this time, or ends if `cancel_at_period_end` is `true`.
"""
discount: typing.Optional[V1AccountListResponseSubscriptionDiscount] = (
pydantic.Field(
alias="discount",
)
)
"""
Discount applied to the subscription. `null` if no discount is applied.
"""
name: typing.Optional[str] = pydantic.Field(
alias="name",
)
"""
Name of the current subscription plan, e.g. `Creator`, `Pro`, `Pro Plus`, `Business`. `null` if the plan cannot be determined. Use `tier` for a machine-readable value.
"""
price: V1AccountListResponseSubscriptionPrice = pydantic.Field(
alias="price",
)
status: typing_extensions.Literal["active", "past_due"] = pydantic.Field(
alias="status",
)
"""
Status of the subscription.
- `active`: payments are up to date.
- `past_due`: the latest payment failed. `tier` is `free` until payment succeeds. The subscription is canceled if payment keeps failing.
"""
Loading
Loading