Typed models
Resource client methods return Pydantic models generated directly from the Apify OpenAPI specification. You get IDE autocompletion, runtime validation of API responses, and a Python-idiomatic snake_case interface on top of the underlying camelCase API.
Accessing response fields
Every method that returns a structured payload returns a Pydantic model. Fields are accessed using their Python snake_case names regardless of the camelCase used by the API, and the static type of each field comes through to your editor.
- Async client
- Sync client
from apify_client import ApifyClientAsync
TOKEN = 'MY-APIFY-TOKEN'
async def main() -> None:
apify_client = ApifyClientAsync(TOKEN)
# `get` returns an `Actor` Pydantic model — fields are typed and IDE-completable.
actor = await apify_client.actor('apify/hello-world').get()
if actor is None:
return
print(actor.id) # str
print(actor.username) # str
print(actor.is_public) # bool
print(actor.created_at) # datetime.datetime (timezone-aware)
print(actor.stats.total_runs) # int — nested model, attribute access all the way down
from apify_client import ApifyClient
TOKEN = 'MY-APIFY-TOKEN'
def main() -> None:
apify_client = ApifyClient(TOKEN)
# `get` returns an `Actor` Pydantic model — fields are typed and IDE-completable.
actor = apify_client.actor('apify/hello-world').get()
if actor is None:
return
print(actor.id) # str
print(actor.username) # str
print(actor.is_public) # bool
print(actor.created_at) # datetime.datetime (timezone-aware)
print(actor.stats.total_runs) # int — nested model, attribute access all the way down
Date strings are automatically parsed into timezone-aware datetime.datetime objects, enums into Literal aliases, and nested objects into their own typed models, so you can compose attribute access without manual conversion.
Providing structured input
A Pydantic model returned from one client call can be passed directly into any other method that accepts the same shape — useful for round-trip flows where you read a resource, tweak it, and write it back.
For input you construct yourself, plain dictionaries work on every input method. Each input shape has a matching TypedDict that documents the expected keys.
- Async client
- Sync client
from apify_client import ApifyClientAsync
TOKEN = 'MY-APIFY-TOKEN'
async def main() -> None:
apify_client = ApifyClientAsync(TOKEN)
rq_client = apify_client.request_queue('REQUEST-QUEUE-ID')
# Plain dict — keys may be snake_case or camelCase.
await rq_client.add_request(
{
'url': 'https://example.com',
'unique_key': 'https://example.com',
'method': 'GET',
}
)
from apify_client import ApifyClient
TOKEN = 'MY-APIFY-TOKEN'
def main() -> None:
apify_client = ApifyClient(TOKEN)
rq_client = apify_client.request_queue('REQUEST-QUEUE-ID')
# Plain dict — keys may be snake_case or camelCase.
rq_client.add_request(
{
'url': 'https://example.com',
'unique_key': 'https://example.com',
'method': 'GET',
}
)
Forward compatibility
Generated models are configured with extra='allow'. Any new fields the API starts returning in the future are preserved on the model instance — they simply do not yet have a typed attribute. Upgrading the client to pick up a newer OpenAPI spec is a non-breaking change for code that reads existing fields.
Browsing all models
The full list of generated models and TypedDicts is available in the API reference under the Models and Typed dicts groups.
Methods that return plain types
A few endpoints intentionally return plain Python types instead of Pydantic models because their payloads are user-defined or inherently unstructured:
DatasetClient.list_items()returns aDatasetItemsPagewhoseitemsfield islist[dict[str, Any]]. Dataset items follow the Actor output schema, which the client cannot know in advance.KeyValueStoreClient.get_record()returns adictwithkey,value, andcontent_typekeys. The shape ofvalueis determined by the record's content type.
For background on the migration from plain dicts to typed models, see Upgrading to v3.