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

# Python SDK Reference

## Overview

The Magic package for Python is your entry-point to secure, passwordless authentication for your application. This guide will cover some important topics for getting started with Magic Python package and to make the most of Magic's features.

## Getting Started

The Magic class is the entry-point to the Magic SDK. It must be instantiated with a Magic **secret** key.

### Installation

The Magic Admin Python SDK requires Python 3.11 or higher.

<CodeGroup>
  ```bash pip icon=square-terminal theme={null}
  pip install magic-admin
  ```

  ```bash uv icon=square-terminal theme={null}
  uv add magic-admin
  ```
</CodeGroup>

### Constructor

**`Magic()`**

|                   |      |                                                                            |
| ----------------- | ---- | -------------------------------------------------------------------------- |
| Parameter         | Type | Definition                                                                 |
| `api_secret_key`  | str  | Your **secret** API Key retrieved from the Magic Dashboard.                |
| `client_id?`      | str  | Your Magic client ID. If not provided, will be fetched automatically.      |
| `retries?`        | num  | Total number of retries to allow. Default: 3.                              |
| `timeout?`        | num  | A period of time the request is going to wait for a response. Default: 10. |
| `backoff_factor?` | num  | A backoff factor to apply between retry attempts. Default: 0.02.           |

### Initialization

Initialize Magic instance.

```python Python icon=python theme={null}
from magic_admin import Magic

magic = Magic(api_secret_key='<SECRET_API_KEY>')
```

## Token Resource

The token resource and its methods are accessible on the Magic instance by the `Token` attribute. It provides methods to interact with the DID Token.

<Note>
  The token resource does **not** make any API calls to the Magic server.
</Note>

### `get_issuer`

Extracts the `iss` from the [DID Token](/embedded-wallets/authentication/features/decentralized-id).

```python Python icon=python theme={null}
Token.get_issuer(did_token)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic User on the client-side

**Raises**

* `DIDTokenMalformed` if the given DID Token is malformed

**Returns**

* A Decentralized ID (`iss`) of the Magic user who generated the DID Token

### `get_public_address`

Gets the cryptographic [public address](https://support.blockchain.com/hc/en-us/articles/4417082520724-What-are-public-and-private-keys-and-how-do-they-work-) of the Magic User who generated the supplied DID Token.

```python Python icon=python theme={null}
Token.get_public_address(did_token)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic user on the client-side

**Raises**

* `DIDTokenMalformed` if the given DID Token is malformed

**Returns**

* A [public address](https://support.blockchain.com/hc/en-us/articles/4417082520724-What-are-public-and-private-keys-and-how-do-they-work-) of the Magic User who generated the DID Token. Currently, this value is associated with the Ethereum blockchain.

### `decode`

Decodes a DID Token from a Base64 string into a tuple of its individual components: `proof` and `claim`. This method allows you decode the DID Token and inspect the token. You can apply your own rules and validations on top of the current [Token.validate](#validate) method.

```python Python icon=python theme={null}
Token.decode(did_token)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic user on the client-side

**Raises**

* `DIDTokenMalformed` if the given DID Token is malformed

**Returns**

* `proof` (str): A digital signature that proves the validity of the given `claim`
* `claim` (dict): Unsigned data the user asserts. This should equal the `proof` after Elliptic Curve recovery. See [Decentralized ID Token Specification](/embedded-wallets/authentication/features/decentralized-id#decentralized-id-token-specification) for fields inside the `claim`.

### `validate`

Validates a DID token.

```python Python icon=python theme={null}
magic.Token.validate(did_token)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic user on the client-side

**Raises**

* `DIDTokenMalformed` if the given DID Token is malformed
* `DIDTokenInvalid` if the given DID Token is invalid

**Returns**

* *None.*

## User Resource

The user resource and its methods are accessible on the Magic instance by the `User` attribute. It provides methods to interact with the User.

### `get_metadata_by_email`

Retrieves information about the user by the supplied `email` address. Resolves both email-based and Google OAuth users. When both an email user and an OAuth user share the same email (apps without Google autolinking), the email user is returned by default; pass `provider` to explicitly target an OAuth user.

```python Python icon=python theme={null}
User.get_metadata_by_email(email, provider=None)
```

**Arguments**

* `email` (str): The user's email address
* `provider` (str, optional): Optional OAuth provider filter (e.g. `"google"`). When set, the lookup targets the OAuth user with this email and provider directly, bypassing the default email lookup.

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains all of the user meta information.
  * `email` (str): The user's email address
  * `phone_number` (str): The user's phone number
  * `subject` (str): The federated identity subject, if any
  * `oauth_provider` (str): OAuth provider, if any
  * `wallets` (arr): Array of the user's wallets

**Example**

```python Python icon=python theme={null}
from magic_admin import Magic

magic = Magic(api_secret_key='<SECRET_API_KEY>')

# Default lookup (email user takes precedence)
response = magic.User.get_metadata_by_email("user@example.com")

# Explicitly target a Google OAuth user with the same email
response = magic.User.get_metadata_by_email("user@example.com", provider="google")
```

### `get_metadata_by_issuer`

Retrieves information about the user by the supplied `iss` from the DID Token. This method is useful if you store the `iss` with your user data, **which is recommended**.

```python Python icon=python theme={null}
User.get_metadata_by_issuer(issuer)
```

**Arguments**

* `issuer` (str): The user's Decentralized ID, which can be parsed using [Token.get\_issuer](#get_issuer)

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains all of the user meta information.
  * `issuer` (str): The user's Decentralized ID
  * `public_address` (str): The authenticated user's public address (a.k.a.: public key). Currently, this value is associated with the Ethereum blockchain.
  * `email` (str): The user's email address
  * `phone_number` (str): The user's phone number
  * `oauth_provider` (str): OAuth provider, if any
  * `wallets` (arr): Array of user's wallet addresses

### `get_metadata_by_public_address`

Retrieves information about the user by the supplied `public_address`. This method is useful if you store the `public_address` with your user data.

```python Python icon=python theme={null}
User.get_metadata_by_public_address(public_address)
```

**Arguments**

* `public_address` (str): The user's Ethereum public address, which can be parsed using [Token.get\_public\_address](#get_public_address)

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time.
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains all of the user meta information.
  * `issuer` (str): The user's Decentralized ID
  * `public_address` (str): The authenticated user's public address (a.k.a.: public key). Currently, this value is associated with the Ethereum blockchain.
  * `email` (str): The user's email address
  * `phone_number` (str): The user's phone number
  * `oauth_provider` (str): OAuth provider, if any
  * `wallets` (arr): Array of user's wallet addresses

### `get_metadata_by_public_addresses`

Retrieves metadata for a batch of users by their Ethereum public addresses in a single request. This method is useful when you need to look up information for a large number of users, as it avoids the rate limiting issues you would encounter by calling [`get_metadata_by_public_address`](#get_metadata_by_public_address) in a loop.

```python Python icon=python theme={null}
User.get_metadata_by_public_addresses(public_addresses)
```

**Arguments**

* `public_addresses` (arr): Array of Ethereum public addresses. Maximum of 500 addresses per request.

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time.
* `BadRequestError`: If the batch size exceeds 500 addresses, or if any other supplied parameters are invalid.
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains:
  * `users` (list): Successfully resolved users. Each entry contains:
    * `issuer` (str): The user's Decentralized ID
    * `public_address` (str): The user's Ethereum public address
    * `email` (str): The user's email address
    * `phone_number` (str): The user's phone number
    * `oauth_provider` (str): OAuth provider, if any
    * `subject` (str): Federated identity subject, if any
    * `username` (str): WebAuthn username, if any
    * `wallets` (arr): Array of user's wallet addresses
  * `errors` (dict): A mapping of `public_address` → error message for any addresses that could not be resolved (e.g. user not found, address belongs to a different app, or malformed address). Successfully resolved addresses are not present in this dict.

### `get_metadata_by_token`

Retrieves information about the user by the supplied DID Token.

```python Python icon=python theme={null}
User.get_metadata_by_token(did_token)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic User on the client-side.

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains all of the user meta information.
  * `issuer` (str): The user's Decentralized ID
  * `public_address` (str): The authenticated user's public address (a.k.a.: public key). Currently, this value is associated with the Ethereum blockchain.
  * `email` (str): The user's email address
  * `phone_number` (str): The user's phone number
  * `oauth_provider` (str): OAuth provider, if any
  * `wallets` (arr): Array of user's wallet addresses

### `logout_by_issuer`

Logs a user out of all Magic SDK sessions given the user's Decentralized ID (`iss`). This method is useful if you store the `iss` with your user data, which is recommended.

```python Python icon=python theme={null}
User.logout_by_issuer(issuer)
```

**Arguments**

* `issuer` (str): The user's Decentralized ID, which can be parsed using [Token.get\_issuer](#get_issuer)

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse)

### `logout_by_public_address`

Logs a user out of all Magic SDK sessions given the user's public address. This method is useful if you store the `public_address`.

```python Python icon=python theme={null}
User.logout_by_public_address(public_address)
```

**Arguments**

* `public_address` (str): The user's Ethereum public address

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse)

### `logout_by_token`

Logs a user out of all Magic SDK sessions given the DID Token.

```python Python icon=python theme={null}
User.logout_by_token(did_token)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic user on the client-side

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse)

### `remove_mfa_by_public_address`

Removes (deactivates) all multi-factor authentication (MFA) for the user with the supplied `public_address`. This is useful for building your own support flows—for example, helping a user who has lost access to their authenticator app regain access to their account. All active MFA factors for the user are deactivated, matching the behavior of disabling MFA from the Magic Dashboard.

<Note>
  Available in `magic-admin` 2.5.0 and later. The user must belong to the app associated with your API **secret** key; otherwise the request is rejected with a `ForbiddenError`.
</Note>

```python Python icon=python theme={null}
User.remove_mfa_by_public_address(public_address)
```

**Arguments**

* `public_address` (str): The user's Ethereum public address, which can be parsed using [Token.get\_public\_address](#get_public_address)

**Raises**

* `RateLimitingError`: If you have sent too many requests within a given period of time
* `BadRequestError`: If the supplied parameters are invalid, or no user is found for the supplied public address
* `AuthenticationError`: If your API **secret** key cannot be authenticated with Magic API server
* `ForbiddenError`: If your API **secret** key is not authorized to access the resources
* `APIError`: For any other API error
* `APIConnectionError`: If your server cannot communicate with the Magic server. Normally this is a network communication error.

<Note>
  See [Error Handling](#response-and-error-handling) for more examples.
</Note>

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse)

**Example**

```python Python icon=python theme={null}
from magic_admin import Magic

magic = Magic(api_secret_key='<SECRET_API_KEY>')

# Remove all MFA for a user who is locked out of their authenticator
magic.User.remove_mfa_by_public_address("0x...")
```

## Utils Resource

The utils resource provides utility methods for common operations like parsing authorization headers and validating token ownership for NFT gating.

### `parse_authorization_header`

Extracts a DID token from an HTTP Authorization header.

```python Python icon=python theme={null}
Utils.parse_authorization_header(header)
```

**Arguments**

* `header` (str): The Authorization header string in `Bearer {token}` format

**Raises**

* `ExpectedBearerStringError`: If header is not in the expected format

**Returns**

* `str`: The DID token extracted from the header

**Example**

```python Python icon=python theme={null}
from magic_admin import Magic

magic = Magic(api_secret_key='<SECRET_API_KEY>')

# Extract token from Authorization header
auth_header = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ..."
did_token = magic.Utils.parse_authorization_header(auth_header)
```

### `validate_token_ownership`

Validates that a user owns a specific NFT token for token gating functionality.

```python Python icon=python theme={null}
Utils.validate_token_ownership(did_token, contract_address, contract_type, rpc_url, token_id=None)
```

**Arguments**

* `did_token` (str): The DID token to validate
* `contract_address` (str): The smart contract address of the NFT
* `contract_type` (str): Either `'ERC721'` or `'ERC1155'`
* `rpc_url` (str): The RPC endpoint URL for the blockchain
* `token_id` (str, optional): Required for ERC1155 contracts

**Raises**

* `ValueError`: If ERC1155 is specified without token\_id
* `Exception`: If DID token validation fails

**Returns**

* `dict`: Response with validation result
  * `valid` (bool): Whether the user owns the token
  * `error_code` (str): Error code if validation fails
  * `message` (str): Human-readable error message

**Example**

```python Python icon=python theme={null}
from magic_admin import Magic

magic = Magic(api_secret_key='<SECRET_API_KEY>')

# Validate ERC721 token ownership
result = magic.Utils.validate_token_ownership(
    did_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ...",
    contract_address="0x1234567890123456789012345678901234567890",
    contract_type="ERC721",
    rpc_url="https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
)

if result['valid']:
    print("User owns the NFT!")
else:
    print(f"Validation failed: {result['message']}")
```

## WalletType Enum

The `WalletType` enum provides support for multiple blockchain networks.

**Supported Networks**

* **EVM Compatible**: ETH, AVAX, CELO, HARMONY, ICON, ZILLIQA, HEDERA, CONFLUX, TERRA, TAQUITO, ED
* **Non-EVM**: SOLANA, POLKADOT, NEAR, FLOW, TEZOS, COSMOS, ALGOD, BITCOIN, HELIUM

## Multi-Chain User Metadata

The User resource supports retrieving metadata for specific wallet types across different blockchains.

### `get_metadata_by_issuer_and_wallet`

Retrieves user metadata for a specific wallet type by issuer.

```python Python icon=python theme={null}
User.get_metadata_by_issuer_and_wallet(issuer, wallet_type)
```

**Arguments**

* `issuer` (str): The user's Decentralized ID
* `wallet_type` (WalletType): The specific wallet type to query

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains user metadata for the specified wallet type

### `get_metadata_by_public_address_and_wallet`

Retrieves user metadata for a specific wallet type by public address.

```python Python icon=python theme={null}
User.get_metadata_by_public_address_and_wallet(public_address, wallet_type)
```

**Arguments**

* `public_address` (str): The user's public address
* `wallet_type` (WalletType): The specific wallet type to query

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains user metadata for the specified wallet type

### `get_metadata_by_token_and_wallet`

Retrieves user metadata for a specific wallet type by DID token.

```python Python icon=python theme={null}
User.get_metadata_by_token_and_wallet(did_token, wallet_type)
```

**Arguments**

* `did_token` (str): A DID Token generated by a Magic user
* `wallet_type` (WalletType): The specific wallet type to query

**Returns**

* A [`MagicResponse`](/embedded-wallets/sdk/server-side/python#magicresponse): The `data` field contains user metadata for the specified wallet type

**Example**

```python Python icon=python theme={null}
from magic_admin import Magic
from magic_admin.resources.wallet import WalletType

magic = Magic(api_secret_key='<SECRET_API_KEY>')

# Get user metadata for Solana wallet
response = magic.User.get_metadata_by_token_and_wallet(
    did_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ...",
    wallet_type=WalletType.SOLANA
)

print(f"Solana wallet address: {response.data['public_address']}")
```

## Response and Error Handling

### Response

There is only one response object that will be returned from a successful API call.

### MagicResponse

This is the interface to interact Magic API responses. It will only be returned if the API request status code is between 200 (inclusive) and 300 (exclusive).

You will have access to the following attributes:

* `content` (bytes): Raw content returned by the API response
* `status_code` (num): HTTP status code for the given request
* `data` (dict): Parsed content

```python Python icon=python theme={null}
from magic_admin.response import MagicResponse

MagicResponse.content
MagicResponse.status
MagicResponse.data
```

### Errors

The conventional HTTP response is adopted by the SDK. For the status code in:

* `2XX` - Indicates success
* `4XX` - Indicates client errors. Information provided to the SDK is invalid.
* `5XX` - Indicates server errors

Below is the error class inheritance which can help developers to programmatically handle the error cases.

```json theme={null}
MagicError
    |
    |------- RequestError
                  |
                  | ------- RateLimitingError
                  | ------- BadRequestError
                  | ------- AuthenticationError
                  | ------- ForbiddenError
                  | ------- APIError
                  | ------- APIConnectionError
   |
   | ------- DIDTokenInvalid
   |
   | ------- DIDTokenMalformed
   |
   | ------- DIDTokenExpired
   |
   | ------- ExpectedBearerStringError
```

### MagicError

This is the base class of all the Magic SDK errors.

```python Python icon=python theme={null}
MagicError(message=None)
```

### RequestError

This is the base class of all the Magic API request errors. This error class will provide details of unsuccessful API requests.

```python Python icon=python theme={null}
RequestError(
    message=None, http_status=None, http_code=None, http_resp_data=None,
    http_message=None, http_error_code=None, http_request_params=None,
    http_request_data=None, http_method=None,
)
```

|      |                       |                                                                                                                                           |
| ---- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Code | Error                 | Description                                                                                                                               |
| 429  | `RateLimitingError`   | Too many requests are submitted for a given period of time.                                                                               |
| 400  | `BadRequestError`     | The API requests might have missing required fields or bad inputs.                                                                        |
| 401  | `AuthenticationError` | This means your API **secret** key is invalid.                                                                                            |
| 403  | `ForbiddenError`      | This normally means the given API **secret** key doesn't have permission to perform the action on the given resources.                    |
| –    | `APIError`            | This is a generic API error that handles other status codes that are not explicitly handled. Ex: `500` , `404` , etc.                     |
| –    | `APIConnectionError`  | Network connection error. This normally means the connection between between your application and Magic API server cannot be established. |

### DIDTokenInvalid

This means the given token fails the validation.

### DIDTokenMalformed

This means the given token format is invalid.

### DIDTokenExpired

This means the given token has expired.

### ExpectedBearerStringError

This means the Authorization header is not in the expected `Bearer {token}` format.

### Error Handling

It is recommended to implement error handling for API responses.

```python Python icon=python theme={null}
from magic_admin import Magic
from magic_admin.error import (
    RateLimitingError, BadRequestError, AuthenticationError, 
    ForbiddenError, APIError, APIConnectionError,
    DIDTokenInvalid, DIDTokenMalformed, DIDTokenExpired,
    ExpectedBearerStringError
)

magic = Magic(api_secret_key='<SECRET_API_KEY>')

try:
    # Validate a DID token
    magic.Token.validate(did_token)
    print("Token is valid!")
    
    # Get user metadata
    user_data = magic.User.get_metadata_by_token(did_token)
    print(f"User email: {user_data.data['email']}")
    
except DIDTokenExpired:
    print("Token has expired, please login again")
except DIDTokenInvalid:
    print("Invalid token")
except DIDTokenMalformed:
    print("Malformed token")
except ExpectedBearerStringError:
    print("Invalid Authorization header format")
except RateLimitingError as e:
    print(f"Rate limit exceeded: {e}")
except AuthenticationError as e:
    print(f"Authentication failed: {e}")
except APIError as e:
    print(f"API error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")
```

## Resources

* [GitHub Repository](https://github.com/magiclabs/magic-admin-python)
* [PyPI Package](https://pypi.org/project/magic-admin)
* [Magic Dashboard](https://dashboard.magic.link)
