{"openapi":"3.1.0","info":{"title":"OutReply Public API","version":"1.3.0","description":"Programmatic access to OutReply — list brands/pages, schedule posts, publish immediately, upload media, generate images, videos and captions with AI (spends AI credits, see `/account/credits`), read and reply to comments, and subscribe to real-time webhooks. All endpoints are authenticated with a bearer token (`outreply_live_*`). Quotas are now monthly and action-based (publishes, replies, reads, webhooks). See the error catalog at `/errors` for `MONTHLY_QUOTA_EXCEEDED`, `BRAND_PUBLISH_GUARDRAIL`, `PAGE_PUBLISH_GUARDRAIL`.","contact":{"name":"OutReply Support","url":"https://outreply.com","email":"support@outreply.com"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://api.outreply.com/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account","description":"Current token & quota."},{"name":"Brands","description":"Your brands and their linked pages."},{"name":"Pages","description":"Individual platform pages/accounts."},{"name":"Posts","description":"Publish immediately, schedule, list, cancel posts."},{"name":"Comments","description":"Read and reply to comments."},{"name":"Media","description":"Upload and manage media assets."},{"name":"AI","description":"Generate images, videos and captions. Each call spends AI credits (plan credits first, then purchased bonus credits) and is refunded when generation fails."},{"name":"Webhooks","description":"Subscribe to real-time events."}],"x-scopes":[{"scope":"read:account","label":"Read account info & quota","group":"Account"},{"scope":"read:brands","label":"List your brands","group":"Discovery"},{"scope":"read:pages","label":"List connected pages","group":"Discovery"},{"scope":"read:posts","label":"Read scheduled / published posts","group":"Posts"},{"scope":"write:posts","label":"Schedule & cancel posts","group":"Posts"},{"scope":"read:comments","label":"List comments on your posts","group":"Comments"},{"scope":"write:comments","label":"Reply to comments","group":"Comments"},{"scope":"read:media","label":"List your API uploads","group":"Media"},{"scope":"write:media","label":"Upload & delete media","group":"Media"},{"scope":"manage:webhooks","label":"Subscribe & manage webhooks (required by Zapier / Make.com)","group":"Webhooks"},{"scope":"write:ai","label":"Generate images, videos & captions with AI (spends credits)","group":"AI"}],"x-webhook-events":["post.published","post.failed","comment.received","comment.replied","account.quota.warning","ai.job.completed","ai.job.failed"],"paths":{"/account":{"get":{"tags":["Account"],"summary":"Current token info & quota","x-scope":"read:account","responses":{"200":{"description":"OK"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/brands":{"get":{"tags":["Brands"],"summary":"List your brands and their linked pages","x-scope":"read:brands","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"brands":{"type":"array","items":{"$ref":"#/components/schemas/Brand"}}}}}}}}}},"/pages":{"get":{"tags":["Pages"],"summary":"List connected pages, optionally filtered","x-scope":"read:pages","parameters":[{"name":"platform","in":"query","schema":{"type":"string","enum":["FB","IG","LN","TT","TW","YT"]}},{"name":"brand_id","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"pages":{"type":"array","items":{"$ref":"#/components/schemas/Page"}}}}}}}}}},"/posts/schedule":{"post":{"tags":["Posts"],"summary":"Schedule a new post","x-scope":"write:posts","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["page_id","scheduled_at"],"properties":{"page_id":{"type":"string"},"message":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time"},"media_ids":{"type":"array","items":{"type":"string"}},"media_urls":{"type":"array","items":{"type":"string","format":"uri"}}}}}}},"responses":{"201":{"description":"Scheduled"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/posts/publish":{"post":{"tags":["Posts"],"summary":"Publish a post immediately","description":"Synchronously publishes a post to the target page. The response is only returned after the upstream platform accepts the post. Large video uploads can take multiple seconds.","x-scope":"write:posts","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["page_id"],"properties":{"page_id":{"type":"string"},"message":{"type":"string"},"media_ids":{"type":"array","items":{"type":"string"}},"media_urls":{"type":"array","items":{"type":"string","format":"uri"}},"first_comment":{"type":"string"},"tiktok_settings":{"type":"object","additionalProperties":true}}}}}},"responses":{"201":{"description":"Published","content":{"application/json":{"schema":{"type":"object","properties":{"post_id":{"type":"string"},"platform":{"type":"string"},"page_id":{"type":"string"},"brand_id":{"type":"string"},"message":{"type":"string"},"media":{"type":"array","items":{"type":"object"}},"status":{"type":"string"},"was_published":{"type":"boolean"},"platform_post_id":{"type":"string","nullable":true},"published_at":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream platform rejected the post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/posts/scheduled":{"get":{"tags":["Posts"],"summary":"List scheduled posts","x-scope":"read:posts","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/ScheduledPost"}}}}}}}}}},"/posts/scheduled/{id}":{"delete":{"tags":["Posts"],"summary":"Cancel a scheduled post","x-scope":"write:posts","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancelled"},"404":{"description":"Not found"}}}},"/posts/published":{"get":{"tags":["Posts"],"summary":"List posts successfully published through OutReply","x-scope":"read:posts","responses":{"200":{"description":"OK"}}}},"/comments":{"get":{"tags":["Comments"],"summary":"List comments on a post","x-scope":"read:comments","parameters":[{"name":"page_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"post_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"comments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}}}}}}}},"/comments/reply":{"post":{"tags":["Comments"],"summary":"Reply to a comment","x-scope":"write:comments","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["page_id","comment_id","message"],"properties":{"page_id":{"type":"string"},"comment_id":{"type":"string"},"message":{"type":"string","maxLength":8000}}}}}},"responses":{"201":{"description":"Reply sent"},"400":{"description":"Validation error"},"502":{"description":"Platform rejected reply"}}}},"/media/upload":{"post":{"tags":["Media"],"summary":"Upload a media file (multipart/form-data)","x-scope":"write:media","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"}}}},"400":{"description":"File too large or invalid"}}}},"/media":{"get":{"tags":["Media"],"summary":"List your uploaded media","x-scope":"read:media","responses":{"200":{"description":"OK"}}}},"/media/{id}":{"delete":{"tags":["Media"],"summary":"Delete a media upload","x-scope":"write:media","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"404":{"description":"Not found"}}}},"/posts/published/{id}/engagement":{"get":{"tags":["Posts"],"summary":"Live engagement (likes, comments, shares) for a published post — Facebook & Instagram","x-scope":"read:posts","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"id from GET /posts/published"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string"},"platform_post_id":{"type":"string"},"page_id":{"type":"string"},"brand_id":{"type":"string"},"engagement":{"type":"object","properties":{"likes":{"type":"integer"},"comments":{"type":"integer"},"shares":{"type":"integer","nullable":true},"total_interactions":{"type":"integer"},"permalink":{"type":"string","nullable":true},"published_at":{"type":"string","format":"date-time"}}},"fetched_at":{"type":"string","format":"date-time"}}}}}},"400":{"description":"UNSUPPORTED_PLATFORM / PAGE_EXPIRED"},"404":{"description":"Not found"},"502":{"description":"PLATFORM_ERROR"}}}},"/account/credits":{"get":{"tags":["Account","AI"],"summary":"AI credit balance, per-action costs, credit packs and auto-refill status","x-scope":"read:account","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsBalance"}}}}}}},"/ai/images":{"post":{"tags":["AI"],"summary":"Generate an image (10 credits)","description":"Generates an image with OutReply's AI image model and registers it as media (use the returned `media_id` in /posts/schedule). Pass `brand_id` to apply that brand's image guidelines. `model: \"pro\"` requires the Elite plan.","x-scope":"write:ai","x-credits":10,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":2000},"aspect_ratio":{"type":"string","enum":["default","1:1","16:9","9:16","4:3","3:4"],"default":"default"},"model":{"type":"string","enum":["flash","pro"],"default":"flash","description":"pro = higher quality, Elite plan only"},"reference_image_urls":{"type":"array","maxItems":3,"items":{"type":"string","format":"uri"},"description":"Public image URLs used as style/subject references"},"reference_media_ids":{"type":"array","maxItems":3,"items":{"type":"string"},"description":"Ids of images you uploaded via /media/upload"},"brand_id":{"type":"string"}}}}}},"responses":{"201":{"description":"Image generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiResult"}}}},"400":{"description":"Validation error / INVALID_REFERENCE_MEDIA"},"402":{"description":"INSUFFICIENT_CREDITS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCredits"}}}},"403":{"description":"PLAN_REQUIRED (pro model) / MISSING_SCOPE"},"413":{"description":"QUOTA_EXCEEDED (storage)"},"502":{"description":"AI_GENERATION_FAILED (credits refunded)"}}}},"/ai/images/edit":{"post":{"tags":["AI"],"summary":"Edit an image with an instruction (10 credits)","x-scope":"write:ai","x-credits":10,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":2000,"description":"The edit instruction, e.g. \"make the background sunset orange\""},"image_url":{"type":"string","format":"uri","description":"Public image URL to edit (or pass media_id)"},"media_id":{"type":"string","description":"Id of an uploaded or generated image"},"model":{"type":"string","enum":["flash","pro"],"default":"flash"}}}}}},"responses":{"201":{"description":"Image edited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiResult"}}}},"402":{"description":"INSUFFICIENT_CREDITS"},"502":{"description":"AI_GENERATION_FAILED (credits refunded)"}}}},"/ai/videos":{"post":{"tags":["AI"],"summary":"Generate a short video asynchronously (90 credits, Elite plan)","description":"Starts a video generation job (text-to-video, or image-to-video when `image_url`/`media_id` is given). Returns 202 immediately; poll `/ai/jobs/{id}` (usually 1–3 minutes) or subscribe to the `ai.job.completed` / `ai.job.failed` webhooks. Credits are charged up front and refunded if the job fails.","x-scope":"write:ai","x-credits":90,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":2000},"aspect_ratio":{"type":"string","enum":["default","16:9","9:16"],"default":"default"},"image_url":{"type":"string","format":"uri","description":"Optional image to animate"},"media_id":{"type":"string","description":"Optional uploaded/generated image to animate"},"brand_id":{"type":"string"}}}}}},"responses":{"202":{"description":"Job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiJobAccepted"}}}},"402":{"description":"INSUFFICIENT_CREDITS"},"403":{"description":"PLAN_REQUIRED (Elite plan)"}}}},"/ai/jobs":{"get":{"tags":["AI"],"summary":"List your AI generation jobs","x-scope":"write:ai","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":50}},{"name":"kind","in":"query","schema":{"type":"string","enum":["image","image_edit","video"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/AiJob"}}}}}}}}}},"/ai/jobs/{id}":{"get":{"tags":["AI"],"summary":"Get one AI job (poll video generation)","x-scope":"write:ai","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiResult"}}}},"404":{"description":"Not found"}}}},"/ai/captions":{"post":{"tags":["AI"],"summary":"Generate post text in the brand's voice (1 credit)","x-scope":"write:ai","x-credits":1,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["brand_id","instruction"],"properties":{"brand_id":{"type":"string"},"instruction":{"type":"string","maxLength":2000,"description":"What the post should be about"},"words":{"type":"integer","default":60,"minimum":10,"maximum":300},"edit_text":{"type":"string","description":"Existing post text to rewrite instead of writing from scratch"},"custom_instructions":{"type":"string","description":"Strict instructions that override the brand configuration"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"brand_id":{"type":"string"},"words_requested":{"type":"integer"},"credits":{"$ref":"#/components/schemas/CreditsAfterCharge"}}}}}},"402":{"description":"INSUFFICIENT_CREDITS"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List your webhook subscriptions","x-scope":"manage:webhooks","responses":{"200":{"description":"OK"}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook subscription (returns the signing secret once)","x-scope":"manage:webhooks","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","url","events"],"properties":{"name":{"type":"string","maxLength":80},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["post.published","post.failed","comment.received","comment.replied","account.quota.warning","ai.job.completed","ai.job.failed"]},"minItems":1},"brand_ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Validation error"}}}},"/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"Fetch a webhook subscription","x-scope":"manage:webhooks","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"delete":{"tags":["Webhooks"],"summary":"Unsubscribe (delete) a webhook","x-scope":"manage:webhooks","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"404":{"description":"Not found"}}}}},"webhooks":{"post.published":{"post":{"summary":"Fired when a scheduled post is successfully published.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}},"post.failed":{"post":{"summary":"Fired when a scheduled post fails after all retries.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}},"comment.received":{"post":{"summary":"Fired when a new comment is received on one of your posts.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}},"comment.replied":{"post":{"summary":"Fired when a reply is posted through the API.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}},"account.quota.warning":{"post":{"summary":"Fired once per month per bucket when a monthly action quota (publishes/replies/reads/webhooks) crosses 80%.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}},"ai.job.completed":{"post":{"summary":"Fired when an asynchronous AI job (POST /ai/videos) finishes. `data.job` is an AiJob and `data.media` the registered media (pass its media_id to /posts/schedule).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}},"ai.job.failed":{"post":{"summary":"Fired when an asynchronous AI job fails. Credits were refunded; `data.job.error` explains why.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Return 2xx to acknowledge."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"outreply_live_*","description":"Provide your API token via the `Authorization: Bearer outreply_live_...` header. Tokens are created in the Dashboard → API Keys screen."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable message."},"code":{"type":"string","description":"Machine-readable error code (stable)."}},"example":{"error":"Invalid API key","code":"INVALID_KEY"}},"Brand":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"pages":{"type":"array","items":{"$ref":"#/components/schemas/Page"}}}},"Page":{"type":"object","properties":{"id":{"type":"string","description":"OutReply SocialAccount id."},"platform":{"type":"string","enum":["FB","IG","LN","TT","TW","YT"]},"name":{"type":"string"},"username":{"type":"string","nullable":true},"account_id":{"type":"string","description":"Native platform id."},"brand_id":{"type":"string"},"followers":{"type":"integer"},"picture":{"type":"string","nullable":true},"expired":{"type":"boolean"}}},"ScheduledPost":{"type":"object","properties":{"id":{"type":"string"},"page_id":{"type":"string"},"brand_id":{"type":"string"},"platform":{"type":"string"},"message":{"type":"string","nullable":true},"media_ids":{"type":"array","items":{"type":"string"}},"media_urls":{"type":"array","items":{"type":"string","format":"uri"}},"scheduled_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["queued","published","failed","cancelled"]},"created_at":{"type":"string","format":"date-time"}}},"Media":{"type":"object","properties":{"media_id":{"type":"string"},"mime_type":{"type":"string"},"bytes":{"type":"integer"},"url":{"type":"string","format":"uri"},"created_at":{"type":"string","format":"date-time"}}},"Comment":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"from":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"created_time":{"type":"string","format":"date-time"},"reply_count":{"type":"integer"}}},"AiJob":{"type":"object","properties":{"job_id":{"type":"string"},"kind":{"type":"string","enum":["image","image_edit","video"]},"status":{"type":"string","enum":["processing","completed","failed"]},"prompt":{"type":"string"},"url":{"type":"string","nullable":true,"description":"Public URL of the generated asset (null while processing)"},"media_id":{"type":"string","nullable":true,"description":"Registered media id, usable as media_ids in /posts/schedule"},"media_type":{"type":"string","enum":["photo","video"]},"mime_type":{"type":"string","nullable":true},"size_bytes":{"type":"integer"},"credits_charged":{"type":"integer","description":"0 after a refund"},"params":{"type":"object","properties":{"aspect_ratio":{"type":"string","nullable":true},"model":{"type":"string","nullable":true},"image_to_video":{"type":"boolean"}}},"error":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time","nullable":true}}},"AiResult":{"type":"object","properties":{"job":{"$ref":"#/components/schemas/AiJob"},"media":{"oneOf":[{"$ref":"#/components/schemas/Media"},{"type":"null"}],"description":"Registered media (null while a video is still processing)"},"credits":{"$ref":"#/components/schemas/CreditsAfterCharge"}}},"AiJobAccepted":{"type":"object","properties":{"job":{"$ref":"#/components/schemas/AiJob"},"poll_url":{"type":"string","example":"/api/v1/ai/jobs/66f1..."},"credits":{"$ref":"#/components/schemas/CreditsAfterCharge"}}},"CreditsAfterCharge":{"type":"object","description":"Balance after this call. Also sent as the X-Credits-Remaining response header.","properties":{"charged":{"type":"integer"},"remaining":{"type":"integer","description":"Total spendable credits (plan + bonus)"},"plan_remaining":{"type":"integer"},"bonus":{"type":"integer","description":"Purchased credits, never expire"},"plan":{"type":"string"}}},"CreditsBalance":{"type":"object","properties":{"credits":{"type":"object","properties":{"available":{"type":"integer"},"plan":{"type":"string"},"plan_allowance":{"type":"integer"},"plan_used":{"type":"integer"},"plan_remaining":{"type":"integer"},"bonus":{"type":"integer"},"referral":{"type":"integer"},"next_reset_at":{"type":"string","format":"date-time","nullable":true}}},"costs":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"label":{"type":"string"},"credits":{"type":"integer"}}}},"packs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"credits":{"type":"integer"},"priceUsd":{"type":"number"},"pricePerCredit":{"type":"number"},"available":{"type":"boolean"}}}},"auto_refill":{"type":"object","properties":{"available":{"type":"boolean"},"enabled":{"type":"boolean"},"status":{"type":"string"},"threshold":{"type":"integer","nullable":true},"amount":{"type":"integer","nullable":true},"unitCredits":{"type":"integer"},"unitPriceUsd":{"type":"number"},"amounts":{"type":"array","items":{"type":"integer"}}}},"billing_url":{"type":"string"}}},"InsufficientCredits":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["INSUFFICIENT_CREDITS"]},"required":{"type":"integer"},"available":{"type":"integer"},"plan_remaining":{"type":"integer"},"bonus":{"type":"integer"},"billing_url":{"type":"string"},"packs_url":{"type":"string"},"auto_refill_url":{"type":"string"}}},"WebhookEnvelope":{"type":"object","required":["event","created_at","data"],"properties":{"event":{"type":"string","enum":["post.published","post.failed","comment.received","comment.replied","account.quota.warning","ai.job.completed","ai.job.failed"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object"}}}}}}