Installation
Official clients are published for six languages. Each exposes the same resources and method names as this reference, so content.list is client.content.list() in every one of them.
Install the client
pip install zelf-sdkSet your key
export ZELF_API_KEY="<your-api-key>"A key is issued per brand. Create one in the dashboard, then keep it out of the code you commit.
Make a call
Pythonimport os from zelf import ZelfAPIClient client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"]) result = client.content.list( search="running shoes", posted_within_days=30, ) print(result)That returns the posts matching the search, newest first, as one page of the standard envelope. Every filter the search takes is on the Content page.
Client behaviour
A client reads the key from ZELF_API_KEY and the base URL from ZELF_BASE_URL when neither is passed. It walks pagination, retries safe requests, verifies webhook signatures, and raises a typed error carrying the log_id.
Source and per-language documentation: github.com/hellozelf/zelf-sdk
Pagination
A list call returns one page. Walking the rest takes one of three bounds: everything, at most N pages, or at most N items. The item bound never fetches a page it does not need, and the envelope stays on the page itself: item_count, page, applied_filters, log_id.
for item in page.auto_paging(max_pages=5):
print(item.id)Typed errors
Every failure is a typed error carrying the status, the error code and the log_id to quote in a support request. The type follows the status, so a retry decision never has to parse a message. A network problem raises a connection or timeout error instead.
try:
client.content.details("con_nope")
except zelf.NotFoundError as error:
print(error.status_code, error.code, error.log_id)- 400
BadRequestErrorVALIDATION_ERRORINVALID_IDBRAND_ID_REQUIRED - 401
AuthenticationErrorINVALID_API_KEYEXPIRED_API_KEYREVOKED_API_KEY - 403
PermissionDeniedErrorPERMISSION_DENIED - 404
NotFoundErrorNOT_FOUND - 406
NotAcceptableErrorNOT_ACCEPTABLE - 409
ConflictErrorA conflicting write - 429
RateLimitErrorRATE_LIMIT_EXCEEDED - 500
InternalServerErrorINTERNAL_ERROR - 503
ServiceUnavailableErrorSERVICE_UNAVAILABLE - no reply
ZelfConnectionError, ZelfTimeoutErrorThe request never reached the API, or timed out
Retries
A failed GET is retried twice by default, honouring Retry-After and otherwise backing off exponentially with jitter, capped at 8 seconds. Writes are never retried: the API publishes no idempotency key, so a retried detection.create would start a second billable run. Opt in per client if your call site can tolerate it.
client = ZelfAPIClient(max_retries=5, retry_writes=True)Webhook verification
parse checks the signature and returns a typed event. Verification uses each language's constant-time comparison, enforces a 300 second timestamp window against replays, and accepts a list of secrets so a rotation does not drop deliveries. For a manifest delivery, rows downloads the NDJSON and verifies the published SHA-256 over each body before yielding anything.
from zelf import webhooks
event = webhooks.parse(request.body, request.headers, secret)
if event.event_type is webhooks.EventType.CONTENT_SNAPSHOT:
for row in event.items:
print(row["id"])Async
Python ships a second client with the same surface.
import asyncio
from zelf import ZelfAPIClientAsync
async def main():
async with ZelfAPIClientAsync() as client:
page = await client.content.list(search="running shoes")
print(page.item_count)
asyncio.run(main())