{"openapi":"3.1.0","info":{"title":"LinkedIn Posting System API","version":"1.0.0","description":"Public REST API for the LinkedIn Posting System. Manage the full post lifecycle (generate, edit, regenerate, image generation, schedule, publish), ideas, analytics and outbound webhooks.\n\nEvery API key is hard-scoped to exactly one member / LinkedIn profile. A key can never read, create, edit, schedule, publish or see analytics for another member's posts — cross-member access returns `404 not_found`.\n\nAuthenticate with `Authorization: Bearer lps_...`. Create and revoke keys in the dashboard under Settings → Integrations.","contact":{"name":"Developer Docs","url":"https://tidefall.de/api"}},"servers":[{"url":"https://app.tidefall.de/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Meta","description":"Service status and authenticated identity."},{"name":"Posts","description":"The full LinkedIn post lifecycle."},{"name":"Ideas","description":"Content ideas: generate, research, convert to posts."},{"name":"Analytics","description":"Account-level engagement metrics."},{"name":"Webhooks","description":"Outbound, signed event delivery."}],"paths":{"/health":{"get":{"tags":["Meta"],"summary":"Service health","description":"Liveness probe. No authentication required.","security":[],"responses":{"200":{"description":"Service is up.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"version":{"type":"string","example":"1.0.0"}},"required":["status"]}}}}}}},"/openapi.json":{"get":{"tags":["Meta"],"summary":"OpenAPI document","description":"Returns this OpenAPI 3.1 document. No authentication required.","security":[],"responses":{"200":{"description":"The OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/me":{"get":{"tags":["Meta"],"summary":"Authenticated member","description":"Returns the member/profile the presented API key is bound to. Use this to confirm which LinkedIn profile a key maps to.","responses":{"200":{"description":"The authenticated member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts":{"get":{"tags":["Posts"],"summary":"List posts","description":"List the authenticated member's posts, newest first, with cursor pagination. Optionally filter by `status`.","parameters":[{"name":"status","in":"query","required":false,"description":"Filter by post status.","schema":{"$ref":"#/components/schemas/PostStatus"}},{"name":"limit","in":"query","required":false,"description":"Page size, 1–100 (default 20).","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from a previous page's `page.next_cursor`.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of posts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedPosts"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Posts"],"summary":"Generate a post","description":"Generate a new LinkedIn post from an idea, synchronously, using the member-scoped RAG style. Supports the `Idempotency-Key` header.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idea":{"type":"string","description":"The idea / topic to write about."},"research":{"type":"boolean","default":false,"description":"Run web research before generating."},"template_id":{"type":"string","description":"Optional template id."}},"required":["idea"]}}}},"responses":{"201":{"description":"The generated post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Posts"],"summary":"Get a post","responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Posts"],"summary":"Edit a post body","description":"Edit the post body. Only allowed for non-published posts.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"The new post body."}},"required":["body"]}}}},"responses":{"200":{"description":"The updated post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"tags":["Posts"],"summary":"Delete a post","description":"Delete a post. Only allowed for non-published posts.","responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/regenerate":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Posts"],"summary":"Regenerate a post","description":"Regenerate the post body in place (synchronous).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"template_id":{"type":"string"}}}}}},"responses":{"200":{"description":"The regenerated post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/images":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Posts"],"summary":"Generate post images","description":"Queue image generation (background job). Returns `202 Accepted`; poll `GET /posts/{id}` until `image_candidates` are present, or subscribe to the `post.images_ready` webhook.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"scene":{"type":"string","description":"Optional scene hint."}}}}}},"responses":{"202":{"description":"Image generation queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/images/upload":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Posts"],"summary":"Upload a custom image or PDF","description":"Attach your OWN image (JPEG/PNG, ≤5 MB) **or a PDF document (≤10 MB)** to the post. Either multipart/form-data (field `file`) OR JSON `{ image_url }` (server fetches the public URL). The uploaded file becomes the post's image/document — then use `select-image` or publish directly without AI image generation.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"JPEG/PNG image (≤5 MB) or PDF (≤10 MB)."}},"required":["file"]}},"application/json":{"schema":{"type":"object","properties":{"image_url":{"type":"string","format":"uri","description":"Public URL of a JPEG/PNG image or PDF (≤5 MB). For PDFs up to 10 MB use multipart/form-data."}},"required":["image_url"]}}}},"responses":{"201":{"description":"The uploaded image URL + the post's candidate list.","content":{"application/json":{"schema":{"type":"object","properties":{"image_url":{"type":"string","format":"uri"},"candidates":{"type":"array","items":{"type":"object","properties":{"base_url":{"type":"string","format":"uri"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/select-image":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Posts"],"summary":"Select a post image","description":"Set the post's image from a generated candidate (by url or index).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image_url":{"type":"string","format":"uri"},"image_index":{"type":"integer","minimum":0},"use_overlay":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"The updated post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/schedule":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Posts"],"summary":"Schedule a post","description":"Schedule the post for publication at an ISO-8601 UTC time.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scheduled_at":{"type":"string","format":"date-time","description":"ISO-8601 UTC timestamp."}},"required":["scheduled_at"]}}}},"responses":{"200":{"description":"The scheduled post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/publish":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Posts"],"summary":"Publish a post","description":"Queue the post for immediate publication to LinkedIn (background job). Returns `202 Accepted`; poll `GET /posts/{id}` until `status=published` (and `linkedin_url` is set), or subscribe to the `post.published` / `post.publish_failed` webhooks. Publishing an already-published post returns `409 conflict`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"responses":{"202":{"description":"Publication queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/posts/{id}/analytics":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Posts"],"summary":"Post analytics","description":"Per-post engagement metrics (refreshed on read where possible).","responses":{"200":{"description":"Per-post analytics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostAnalytics"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/analytics":{"get":{"tags":["Analytics"],"summary":"Account analytics","description":"Account-level KPIs plus top posts for the authenticated member.","responses":{"200":{"description":"Account analytics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Analytics"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas":{"get":{"tags":["Ideas"],"summary":"List ideas","parameters":[{"name":"status","in":"query","required":false,"description":"Filter by idea status.","schema":{"type":"string","enum":["new","used","dismissed"]}}],"responses":{"200":{"description":"The member's ideas.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Idea"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas/generate":{"post":{"tags":["Ideas"],"summary":"Generate ideas","description":"Generate a fresh batch of content ideas (synchronous).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Generated ideas.","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string","description":"Human-readable summary."},"ideas":{"type":"array","items":{"$ref":"#/components/schemas/Idea"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas/research":{"post":{"tags":["Ideas"],"summary":"Research a keyword","description":"Queue keyword research (background job). Returns `202 Accepted`; poll `GET /ideas` for the resulting ideas.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"keyword":{"type":"string","description":"The keyword to research."}},"required":["keyword"]}}}},"responses":{"202":{"description":"Research queued.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"queued"},"poll":{"type":"string","example":"/api/v1/ideas"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"patch":{"tags":["Ideas"],"summary":"Update an idea","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"angle":{"type":"string"}}}}}},"responses":{"200":{"description":"The updated idea.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdeaEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas/{id}/create-post":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Ideas"],"summary":"Create a post from an idea","description":"Generate a post from an existing idea (synchronous).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique key so a retried request is processed once. Replays within 24h return the original response with `Idempotency-Replayed: true`.","schema":{"type":"string"}}],"responses":{"201":{"description":"The generated post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas/{id}/dismiss":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Ideas"],"summary":"Dismiss an idea","responses":{"200":{"description":"The dismissed idea.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdeaEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ideas/{id}/restore":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Ideas"],"summary":"Restore a dismissed idea","responses":{"200":{"description":"The restored idea.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdeaEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","responses":{"200":{"description":"The member's webhook endpoints.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook endpoint","description":"Register a URL to receive signed events. The `secret` is returned once on creation — store it, it is never shown again. Verify deliveries with `X-LPS-Signature: sha256=<hmac(secret, rawBody)>`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"},"description":"Events to subscribe to."}},"required":["url","events"]}}}},"responses":{"201":{"description":"The created endpoint (with one-time secret).","content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"$ref":"#/components/schemas/Webhook"},"secret":{"type":"string","description":"HMAC signing secret — shown only once."}},"required":["endpoint","secret"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Webhooks"],"summary":"Get a webhook endpoint","description":"Returns the endpoint (the signing secret is never included).","responses":{"200":{"description":"The endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook endpoint","responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}/deliveries":{"parameters":[{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Webhooks"],"summary":"List recent deliveries","description":"Recent delivery attempts for an endpoint (for debugging).","responses":{"200":{"description":"Recent delivery attempts.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Use your lps_... API key"}},"responses":{"Unauthorized":{"description":"Missing, invalid or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found, or not owned by the authenticated member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ValidationError":{"description":"Request body or query parameters failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded. See the X-RateLimit-* response headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"The request conflicts with the resource's current state (e.g. already published).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Uniform error envelope returned by every error response.","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable error code.","enum":["unauthorized","forbidden","not_found","validation_error","rate_limited","conflict","unprocessable","internal_error"]},"message":{"type":"string","description":"Human-readable explanation."},"details":{"type":"object","additionalProperties":true,"description":"Optional per-field details (validation errors)."}},"required":["code","message"]}},"required":["error"]},"PostStatus":{"type":"string","description":"The post's position in the lifecycle state machine.","enum":["draft","draft_saved","approved","generating_images","scheduled","published","rejected"]},"Post":{"type":"object","description":"A LinkedIn post.","properties":{"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/PostStatus"},"idea":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"image_url":{"type":"string","format":"uri","nullable":true},"scheduled_at":{"type":"string","format":"date-time","nullable":true},"published_at":{"type":"string","format":"date-time","nullable":true},"linkedin_post_urn":{"type":"string","nullable":true},"linkedin_url":{"type":"string","format":"uri","nullable":true},"format":{"type":"string","example":"standard"},"auto_generated":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}},"required":["id","status"]},"PostEnvelope":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}},"required":["post"]},"AsyncEnvelope":{"type":"object","description":"Returned by 202 responses for background jobs.","properties":{"post":{"$ref":"#/components/schemas/Post"},"status":{"$ref":"#/components/schemas/PostStatus"},"poll":{"type":"string","description":"Poll this URL until the job completes.","example":"/api/v1/posts/{id}"}},"required":["status","poll"]},"PaginatedPosts":{"type":"object","description":"A page of posts with cursor pagination metadata.","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Post"}},"page":{"type":"object","properties":{"next_cursor":{"type":"string","nullable":true,"description":"Pass as `?cursor=` to fetch the next page; null at end."},"has_more":{"type":"boolean"}},"required":["next_cursor","has_more"]}},"required":["data","page"]},"PostAnalytics":{"type":"object","description":"Per-post engagement metrics.","properties":{"post_id":{"type":"string","format":"uuid"},"impressions":{"type":"integer"},"likes":{"type":"integer"},"comments":{"type":"integer"},"shares":{"type":"integer"},"engagement_rate":{"type":"number"}}},"Analytics":{"type":"object","description":"Account-level analytics for the authenticated member.","properties":{"kpis":{"type":"object","additionalProperties":true,"description":"Aggregate KPIs (totals, averages)."},"top_posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}}},"Idea":{"type":"object","description":"A content idea.","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"angle":{"type":"string","nullable":true},"status":{"type":"string","enum":["new","used","dismissed"]},"source":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}},"required":["id","title","status"]},"IdeaEnvelope":{"type":"object","properties":{"idea":{"$ref":"#/components/schemas/Idea"}},"required":["idea"]},"Me":{"type":"object","description":"The member/profile the API key is bound to.","properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","nullable":true},"headline":{"type":"string","nullable":true},"linkedin_connected":{"type":"boolean"}},"required":["id","linkedin_connected"]},"WebhookEvent":{"type":"string","description":"An event a webhook endpoint can subscribe to.","enum":["post.published","post.publish_failed","post.images_ready","idea.created"]},"Webhook":{"type":"object","description":"A registered webhook endpoint (secret never included).","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}},"required":["id","url","events","is_active"]},"WebhookDelivery":{"type":"object","description":"A single delivery attempt for a webhook endpoint.","properties":{"id":{"type":"string","format":"uuid"},"event":{"$ref":"#/components/schemas/WebhookEvent"},"status":{"type":"string","enum":["pending","success","failed"]},"attempts":{"type":"integer"},"response_code":{"type":"integer","nullable":true},"last_error":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}},"required":["id","event","status"]}}}}