Skip to main content

Overview

Two official clients wrap the REST API. Both are generated from the same OpenAPI document as this reference, so every endpoint and field is typed, and both add the parts you would otherwise write yourself:
  • Auth and version pinning: pass your mk_live_ key once. Each SDK release pins Marky-Version to the API version it was built from, so upgrading the API never changes the response shapes your code sees.
  • Typed errors: every non-2xx response becomes an error you can catch by class (NotFoundError, RateLimitError, …) with the stable code, request_id and param.
  • Safe retries: rate limits (429) are retried after Retry-After. Server errors and network failures are retried only when repeating cannot duplicate anything, and create calls carry an automatic Idempotency-Key, so a retry after a timeout returns the original post instead of making a second one.
  • Webhook verification: one call checks the X-Marky-Signature HMAC and the X-Marky-Timestamp replay window, then returns the event.
Agencies that need a fully white-label integration can call the REST API directly; the SDKs are a convenience over the same endpoints.

TypeScript

This is the flow we run against the live API before every release: it creates a draft (status NEW), so nothing is published, and deletes it at the end. To attach an image, upload it with uploadMediaFromUrl({ workspace_id, url }) and pass media_ids: [media.id]; to schedule, send status: "SCHEDULED" with a future scheduled_publish_time. Named helpers cover the core workflow: listWorkspaces, getWorkspace, listIntegrations, listPosts, createPost, getPost, updatePost, deletePost, schedulePost, uploadMediaFromUrl, createWebhook, listWebhooks, deleteWebhook and paginate (getPost, updatePost and deletePost since 0.1.1). Every other endpoint is available, fully typed, on api.client:

Python

Each endpoint is a module under mymarky.generated.api.<group> with sync, sync_detailed, asyncio and asyncio_detailed functions. Pass client=marky.client to any of them. Workspace operations live in the businesses group, and routes inside a workspace name their first argument business_id: pass the workspace ID.

Handling errors

Match on err.code (see Error codes), never on the message text.

Verifying webhooks

Pass the raw request body exactly as received, plus the request headers. Parsing and re-serializing the JSON changes the bytes and the signature will not match. The SDKs implement the scheme on Webhooks: HMAC-SHA256 over "{X-Marky-Timestamp}." + raw body, and deliveries more than 5 minutes old are rejected (pass toleranceSeconds / tolerance_seconds to change that).