{"openapi":"3.1.0","info":{"title":"号外 API","version":"1.0.0","description":"号外 is a public WeChat article feed service with an authenticated ingestion webhook.","license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://haowai.thesignalwise.com","description":"Current public deployment"}],"tags":[{"name":"Public","description":"Public health and RSS endpoints that require no credentials."},{"name":"Webhook","description":"Signed ingestion endpoint for configured monitoring clients."}],"paths":{"/healthz":{"get":{"tags":["Public"],"summary":"Check service liveness","operationId":"getHealth","security":[],"responses":{"200":{"description":"Service process is responding","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","const":"ok"}}}}}},"4XX":{"description":"Invalid request"}}}},"/rss.xml":{"get":{"tags":["Public"],"summary":"Read the global RSS feed","operationId":"getGlobalFeed","security":[],"responses":{"200":{"description":"RSS 2.0 document","headers":{"ETag":{"schema":{"type":"string"}}},"content":{"application/rss+xml":{"schema":{"type":"string"}}}},"304":{"description":"Feed has not changed"},"4XX":{"description":"Invalid request"}}}},"/feeds/accounts/{account_id}.xml":{"get":{"tags":["Public"],"summary":"Read one public account's RSS feed","operationId":"getAccountFeed","security":[],"parameters":[{"name":"account_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255}}],"responses":{"200":{"description":"RSS 2.0 document, possibly with no items","content":{"application/rss+xml":{"schema":{"type":"string"}}}},"304":{"description":"Feed has not changed"},"4XX":{"description":"Invalid account identifier or request"}}}},"/api/v1/webhooks/articles":{"post":{"tags":["Webhook"],"summary":"Ingest discovered WeChat article metadata","operationId":"ingestArticles","security":[{"WebhookKeyId":[],"WebhookTimestamp":[],"WebhookNonce":[],"WebhookSignature":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestEvent"}}}},"responses":{"200":{"description":"Previously accepted event result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestResult"}}}},"201":{"description":"Event accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"description":"Request exceeds the application body-size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"415":{"description":"Content type must be application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"securitySchemes":{"WebhookKeyId":{"type":"apiKey","in":"header","name":"X-Webhook-Key-Id"},"WebhookTimestamp":{"type":"apiKey","in":"header","name":"X-Webhook-Timestamp"},"WebhookNonce":{"type":"apiKey","in":"header","name":"X-Webhook-Nonce"},"WebhookSignature":{"type":"apiKey","in":"header","name":"X-Webhook-Signature","description":"v1= followed by a lowercase hexadecimal HMAC-SHA256 signature."}},"responses":{"BadRequest":{"description":"Malformed or invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Missing or invalid webhook authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"Replayed nonce or conflicting article identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"schemas":{"IngestEvent":{"type":"object","additionalProperties":false,"required":["schema_version","event_id","source","sent_at","articles"],"properties":{"schema_version":{"type":"string","const":"1.0"},"event_id":{"type":"string","format":"uuid"},"source":{"type":"string","minLength":1,"maxLength":100},"sent_at":{"type":"string","format":"date-time"},"articles":{"type":"array","minItems":1,"maxItems":100,"items":{"$ref":"#/components/schemas/ArticleInput"}},"extra":{"$ref":"#/components/schemas/ExtensionObject"}}},"ArticleInput":{"type":"object","additionalProperties":false,"required":["title","url","account","discovered_at"],"properties":{"external_id":{"type":"string","minLength":1,"maxLength":255},"title":{"type":"string","minLength":1,"maxLength":500},"url":{"type":"string","format":"uri","maxLength":4096,"pattern":"^https://"},"description":{"type":"string","maxLength":4000},"author":{"$ref":"#/components/schemas/NamedIdentity"},"account":{"allOf":[{"$ref":"#/components/schemas/NamedIdentity"},{"type":"object","required":["id","name"]}]},"published_at":{"type":"string","format":"date-time"},"discovered_at":{"type":"string","format":"date-time"},"cover_url":{"type":"string","format":"uri","maxLength":4096,"pattern":"^https://"},"language":{"type":"string","minLength":2,"maxLength":35},"extra":{"$ref":"#/components/schemas/ExtensionObject"}}},"NamedIdentity":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"id":{"type":"string","minLength":1,"maxLength":255},"name":{"type":"string","minLength":1,"maxLength":200}}},"ExtensionObject":{"type":"object","description":"Bounded source-specific extension fields. Serialized size is limited separately.","additionalProperties":true},"IngestResult":{"type":"object","additionalProperties":false,"required":["event_id","status","counts","request_id"],"properties":{"event_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["accepted","already_accepted"]},"counts":{"type":"object","additionalProperties":false,"required":["received","created","updated","duplicate"],"properties":{"received":{"type":"integer","minimum":1},"created":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0},"duplicate":{"type":"integer","minimum":0}}},"request_id":{"type":"string"}}},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message","request_id"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"}}}}}}}}