openapi: 3.1.0 info: # Do not change the title, if the title changes, the import paths will be broken title: Api version: 0.1.0 description: EHSAN Closed Donation Loop API servers: - url: /api description: Base API path tags: - name: health description: Health operations - name: requests description: Donation requests (beneficiary cases) - name: donors description: Donor records - name: stats description: Dashboard statistics - name: whatsapp description: WhatsApp message log paths: /healthz: get: operationId: healthCheck tags: [health] summary: Health check responses: "200": description: Healthy content: application/json: schema: $ref: "#/components/schemas/HealthStatus" /requests: get: operationId: listRequests tags: [requests] summary: List all donation requests parameters: - in: query name: status schema: type: string - in: query name: needType schema: type: string responses: "200": description: List of requests content: application/json: schema: type: array items: $ref: "#/components/schemas/DonationRequest" post: operationId: createRequest tags: [requests] summary: Submit a new beneficiary request requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DonationRequestInput" responses: "201": description: Created content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/new: get: operationId: listNewRequests tags: [requests] summary: List new (unreviewed) requests responses: "200": description: List of new requests content: application/json: schema: type: array items: $ref: "#/components/schemas/DonationRequest" /requests/published: get: operationId: listPublishedRequests tags: [requests] summary: List published donation opportunities (public) responses: "200": description: Published opportunities content: application/json: schema: type: array items: $ref: "#/components/schemas/DonationRequest" /requests/{id}: get: operationId: getRequest tags: [requests] summary: Get a single request by ID parameters: - in: path name: id required: true schema: type: string responses: "200": description: Request detail content: application/json: schema: $ref: "#/components/schemas/DonationRequest" "404": description: Not found /requests/{id}/verify: post: operationId: verifyRequest tags: [requests] summary: Verify a request (admin) parameters: - in: path name: id required: true schema: type: string responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/publish: post: operationId: publishRequest tags: [requests] summary: Publish a verified request as a donation opportunity parameters: - in: path name: id required: true schema: type: string responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/donate: post: operationId: donateToRequest tags: [requests] summary: Simulate a donation to a published request parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DonationInput" responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/deliver: post: operationId: deliverSupport tags: [requests] summary: Mark support as delivered parameters: - in: path name: id required: true schema: type: string responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/confirm-receipt: post: operationId: confirmReceipt tags: [requests] summary: Confirm beneficiary received support parameters: - in: path name: id required: true schema: type: string responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/thank-you: post: operationId: submitThankYou tags: [requests] summary: Submit beneficiary thank-you message parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ThankYouInput" responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/send-whatsapp: post: operationId: sendWhatsapp tags: [requests] summary: Send thank-you WhatsApp to donor via OpenClaw parameters: - in: path name: id required: true schema: type: string responses: "200": description: WhatsApp send result content: application/json: schema: $ref: "#/components/schemas/WhatsappResult" /requests/{id}/close: post: operationId: closeRequest tags: [requests] summary: Close the case parameters: - in: path name: id required: true schema: type: string responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /requests/{id}/reject: post: operationId: rejectRequest tags: [requests] summary: Reject a request parameters: - in: path name: id required: true schema: type: string requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/RejectInput" responses: "200": description: Updated request content: application/json: schema: $ref: "#/components/schemas/DonationRequest" /donors: get: operationId: listDonors tags: [donors] summary: List all donors responses: "200": description: List of donors content: application/json: schema: type: array items: $ref: "#/components/schemas/Donor" /stats: get: operationId: getStats tags: [stats] summary: Dashboard statistics summary responses: "200": description: Statistics content: application/json: schema: $ref: "#/components/schemas/Stats" /whatsapp-log: get: operationId: listWhatsappLog tags: [whatsapp] summary: List all WhatsApp message log entries responses: "200": description: WhatsApp log entries content: application/json: schema: type: array items: $ref: "#/components/schemas/WhatsappLogEntry" components: schemas: HealthStatus: type: object properties: status: type: string required: - status DonationRequest: type: object required: [id, caseId, beneficiaryName, nationalId, phone, source, sourceName, needType, requestedAmount, collectedAmount, description, status, currentStep, createdAt, updatedAt] properties: id: type: string caseId: type: string beneficiaryName: type: string nationalId: type: string phone: type: string source: type: string enum: [beneficiary, charity, official] sourceName: type: string needType: type: string enum: [electricity, water, food, health, housing, refrigerator, air_conditioner, court_order] requestedAmount: type: number collectedAmount: type: number description: type: string status: type: string enum: [new, pending_review, verified, published, donated, delivered, receipt_confirmed, thank_you_submitted, whatsapp_sent, closed, rejected] currentStep: type: integer donorId: type: ["string", "null"] donorName: type: ["string", "null"] thankYouMessage: type: ["string", "null"] whatsappStatus: type: ["string", "null"] enum: ["pending", "sent", "failed", null] whatsappSentAt: type: ["string", "null"] rejectionReason: type: ["string", "null"] createdAt: type: string updatedAt: type: string DonationRequestInput: type: object required: [beneficiaryName, nationalId, phone, source, sourceName, needType, requestedAmount, description] properties: beneficiaryName: type: string nationalId: type: string phone: type: string source: type: string enum: [beneficiary, charity, official] sourceName: type: string needType: type: string enum: [electricity, water, food, health, housing, refrigerator, air_conditioner, court_order] requestedAmount: type: number description: type: string DonationInput: type: object required: [donorName, donorPhone, amount] properties: donorName: type: string donorPhone: type: string donorEmail: type: ["string", "null"] amount: type: number ThankYouInput: type: object required: [beneficiaryName, message] properties: beneficiaryName: type: string message: type: string RejectInput: type: object properties: reason: type: string WhatsappResult: type: object required: [success, message, simulated] properties: success: type: boolean message: type: string simulated: type: boolean sentAt: type: ["string", "null"] Donor: type: object required: [id, name, phone, totalDonated, donationCount] properties: id: type: string name: type: string phone: type: string email: type: ["string", "null"] totalDonated: type: number donationCount: type: integer Stats: type: object required: [totalRequests, totalDonated, totalCollected, totalClosed, byStatus, byNeedType] properties: totalRequests: type: integer totalDonated: type: integer totalCollected: type: number totalClosed: type: integer pendingVerification: type: integer activeOpportunities: type: integer byStatus: type: array items: $ref: "#/components/schemas/StatusCount" byNeedType: type: array items: $ref: "#/components/schemas/NeedTypeCount" StatusCount: type: object required: [status, count] properties: status: type: string count: type: integer NeedTypeCount: type: object required: [needType, count, totalAmount] properties: needType: type: string count: type: integer totalAmount: type: number WhatsappLogEntry: type: object required: [id, caseId, donorName, donorPhone, beneficiaryMessage, whatsappMessage, status, createdAt] properties: id: type: string caseId: type: string donorName: type: string donorPhone: type: string beneficiaryMessage: type: string whatsappMessage: type: string status: type: string enum: [pending, sent, failed] sentAt: type: ["string", "null"] createdAt: type: string