2026-05-28 23:37:31 +00:00
|
|
|
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
|
2026-06-05 17:05:27 +00:00
|
|
|
description: EHSAN Closed Donation Loop API
|
2026-05-28 23:37:31 +00:00
|
|
|
servers:
|
|
|
|
|
- url: /api
|
|
|
|
|
description: Base API path
|
|
|
|
|
tags:
|
|
|
|
|
- name: health
|
|
|
|
|
description: Health operations
|
2026-06-05 17:05:27 +00:00
|
|
|
- name: requests
|
|
|
|
|
description: Donation requests (beneficiary cases)
|
|
|
|
|
- name: donors
|
|
|
|
|
description: Donor records
|
|
|
|
|
- name: stats
|
|
|
|
|
description: Dashboard statistics
|
|
|
|
|
- name: whatsapp
|
|
|
|
|
description: WhatsApp message log
|
|
|
|
|
|
2026-05-28 23:37:31 +00:00
|
|
|
paths:
|
|
|
|
|
/healthz:
|
|
|
|
|
get:
|
|
|
|
|
operationId: healthCheck
|
|
|
|
|
tags: [health]
|
|
|
|
|
summary: Health check
|
|
|
|
|
responses:
|
|
|
|
|
"200":
|
|
|
|
|
description: Healthy
|
|
|
|
|
content:
|
|
|
|
|
application/json:
|
|
|
|
|
schema:
|
|
|
|
|
$ref: "#/components/schemas/HealthStatus"
|
2026-06-05 17:05:27 +00:00
|
|
|
|
|
|
|
|
/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"
|
|
|
|
|
|
2026-05-28 23:37:31 +00:00
|
|
|
components:
|
|
|
|
|
schemas:
|
|
|
|
|
HealthStatus:
|
|
|
|
|
type: object
|
|
|
|
|
properties:
|
|
|
|
|
status:
|
|
|
|
|
type: string
|
|
|
|
|
required:
|
|
|
|
|
- status
|
|
|
|
|
|
2026-06-05 17:05:27 +00:00
|
|
|
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
|