Metadata-Version: 2.5
Name: mymarky
Version: 0.1.1
Summary: Typed Python client for the Marky REST API: create, schedule and publish posts, upload media, and verify webhooks.
License-Expression: MIT
Requires-Python: >=3.11
Requires-Dist: attrs>=23.1
Requires-Dist: httpx<1,>=0.27
Description-Content-Type: text/markdown

# mymarky

Typed Python client for the Marky REST API. Python 3.11+.

```bash
pip install mymarky
```

```python
import os

from mymarky import Marky, NotFoundError
from mymarky.generated.api.businesses import get_workspace, list_workspaces
from mymarky.generated.api.integrations import list_connected_social_accounts
from mymarky.generated.api.posts import create_post, delete_post, get_post
from mymarky.generated.models import PostCreateRequest, PostResponse

workspace_id = os.environ["MARKY_WORKSPACE_ID"]

with Marky(api_key=os.environ["MARKY_API_KEY"]) as marky:
    workspaces = list(marky.paginate(list_workspaces.sync))
    workspace = get_workspace.sync(workspace_id, client=marky.client)
    accounts = list_connected_social_accounts.sync(workspace_id, client=marky.client)

    # A draft: status NEW and no scheduled_publish_time, so nothing is published.
    draft = create_post.sync(
        workspace_id,
        client=marky.client,
        body=PostCreateRequest(caption="Hello from the SDK", status="NEW"),
    )
    assert isinstance(draft, PostResponse)

    post = get_post.sync(workspace_id, draft.id, client=marky.client)
    delete_post.sync(workspace_id, draft.id, client=marky.client)

    try:
        get_post.sync(workspace_id, draft.id, client=marky.client)
    except NotFoundError as err:
        print(err.status, err.code)  # 404 resource_not_found
```

That flow is our release smoke test, run end to end against the live API. To
schedule instead of drafting, send `status="SCHEDULED"` with a future
`scheduled_publish_time`, or call `schedule_post` later.

Every operation lives in `mymarky.generated.api.<tag>.<operation>` with
`sync`, `sync_detailed`, `asyncio` and `asyncio_detailed` variants; pass
`client=marky.client`.

Workspace operations (`list_workspaces`, `get_workspace`, `create_workspace`,
`update_workspace`, `delete_workspace`) live in the `businesses` tag module.
Routes inside a workspace keep their `/api/businesses/{business_id}/...` path,
so their first argument is named `business_id`: pass the workspace ID.

- **Errors**: any non-2xx raises an `ApiError` subclass (`NotFoundError`,
  `RateLimitError`, ...). Branch on `err.code`, never on the message. So a
  `sync` call returns the success model (typed `PostResponse | None`, where
  `None` means a 2xx status the spec does not list).
- **IDs are strings**: path IDs take the same `str` the API returns in `.id`
  (since 0.1.1; 0.1.0 typed most of them as `uuid.UUID`).
- **Retries**: 429s, and 5xx/network errors on requests that are safe to repeat.
  Create calls get an `Idempotency-Key` automatically, so a retry never makes a
  duplicate. Pass `idempotency_key=` to make your own retries safe too.
- **Unknown values**: enums are plain strings, so a new status or platform never
  breaks parsing; unknown fields land in `.additional_properties`.
- **Renamed "business" to "workspace"**: `list_businesses`, `get_business`,
  `create_business`, `update_business`, `delete_business` and the `business_id`
  field on media upload bodies still work but are deprecated; use the
  `*_workspace(s)` functions and `workspace_id`.
- **Webhooks**: `construct_event(raw_body, request.headers, secret)` checks the
  `X-Marky-Signature` HMAC over `"{X-Marky-Timestamp}." + raw body`, rejects
  deliveries older than 5 minutes (replays), and returns the event.
