{"openapi":"3.0.0","info":{"title":"Yemert Management API","version":"1.0.0","description":"A comprehensive API for managing farmers, admin operations, USSD services, and market posts for agricultural insurance and farmer registration.\n\n**Interactive docs:** open `/api-docs` on the same host and port as the API (no `/api/v1` prefix). Example: `http://localhost:<PORT>/api-docs` locally, or `https://<your-api-host>/api-docs` in staging/production.\n**OpenAPI JSON:** `GET /api-docs.json` (same host; machine-readable spec for codegen or import into Postman).\n**Try it out:** most admin routes need `Authorization: Bearer <ADMIN_TOKEN>` plus a valid admin JWT cookie from `POST /admin/login`. Use **Authorize** in Swagger UI; `servers` selects the base URL including `/api/v1` — paths below are relative to that base.","contact":{"name":"Yemert API Support","email":"tech.yemert@gmail.com"},"license":{"name":"ISC","url":"https://opensource.org/licenses/ISC"}},"servers":[{"url":"https://staging.yemert.co/api/v1","description":"Staging server"},{"url":"https://api.yemert.co/api/v1","description":"Production server"}],"tags":[{"name":"Admin","description":"Admin management operations"},{"name":"RBAC Management","description":"Role-based access control and admin role assignment flows"},{"name":"Partner Integrations","description":"External partner management and B2B partner APIs"},{"name":"Farmers","description":"Farmer registration and management"},{"name":"Wallets","description":"Customer wallet operations (e.g. Monnify)"},{"name":"Insurance","description":"Insurance services and recommendations"},{"name":"Market","description":"Market posts management endpoints for YemertMarketSell functionality"},{"name":"USSD","description":"USSD service operations"},{"name":"Health","description":"API health and status checks"},{"name":"RBAC","description":"Fine-grained access control: **permissions** (string keys), **roles / groups** (`rbac_roles` + `rbac_role_permissions`), **features** (sidebar entries + required keys), and **per-admin** links (`rbac_admin_roles`) plus optional **direct grants** (`rbac_admin_permissions`).\n\n**Auth:** Every route needs `Authorization: Bearer <ADMIN_TOKEN>` (see `AdminAuth` in this spec). Most admin flows also require a valid JWT from `POST /admin/login` (cookie or `x-auth` as implemented by the server).\n\n**Who can mutate:** Writes that change catalog, roles, or assignments require effective permission **`rbac.manage`**, enforced by `RequirePermission` (so `ADMIN` with that key can manage RBAC, not only `SUPER_ADMIN`). **`POST /admin/rbac/seed-defaults`** is an exception: it still requires **`SUPER_ADMIN`** JWT (see route middleware).\n\n**Reads:** `GET /admin/rbac/me`, `GET .../permissions`, `GET .../features`, `GET .../roles`, `GET .../roles/{role}/permissions`, and `GET .../admins/{adminId}/permissions` are available to authenticated admins (no `rbac.manage` required unless noted on the operation).\n\n**Path prefix:** All paths below are under the server base URL that already includes `/api/v1` (see `servers` above).\n\n| Method | Path | Summary |\n|--------|------|--------|\n| GET | `/admin/rbac/me` | Current admin role, effective permission keys, visible features |\n| POST | `/admin/rbac/seed-defaults` | Re-run default catalog upsert (SUPER_ADMIN only) |\n| GET/POST | `/admin/rbac/permissions` | List / upsert a permission key |\n| GET/PATCH/DELETE | `/admin/rbac/permissions/{key}` | Read, update description, delete (built-in keys cannot be deleted) |\n| GET/POST | `/admin/rbac/features` | List / upsert a feature + its required permission keys |\n| GET/POST | `/admin/rbac/roles/{role}/permissions` | List / replace all keys for a role (group) |\n| GET/POST | `/admin/rbac/roles` | List roles / create-or-upsert role by name |\n| GET/DELETE | `/admin/rbac/roles/{role}` | Role metadata + counts / delete custom role |\n| POST | `/admin/rbac/admins/{adminId}/role` | Attach an extra RBAC role to an admin (login id) |\n| GET/DELETE | `/admin/rbac/admins/{adminId}/roles` | List attached roles / remove one |\n| GET/POST | `/admin/rbac/admins/{adminId}/permissions` | List / replace direct permission grants |\n"},{"name":"Partners","description":"Partner-facing and partner admin endpoints"},{"name":"Callbacks","description":"Payment/provider callback endpoints"},{"name":"Webhooks","description":"Inbound webhook endpoints"},{"name":"Tasks","description":"Operational maintenance endpoints"},{"name":"Telemetry","description":"Dashboard telemetry aggregates"},{"name":"Crop Catalog","description":"Admin crop catalog CRUD"},{"name":"Countries","description":"Country/region configuration for USSD and onboarding"},{"name":"Accounting","description":"Ledger, balances, and accounting views"},{"name":"Payments","description":"Manual payments, payouts and insurer config management"}],"components":{"securitySchemes":{"AdminAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for admin authentication"},"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authentication via Authorization header"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authentication via Authorization header (legacy)"},"CookieAuth":{"type":"apiKey","in":"cookie","name":"token","description":"JWT token stored in cookie"}},"responses":{"UnauthorizedError":{"description":"Authentication token is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Unauthorized access","error":"Invalid or missing authentication token"}}}},"ForbiddenError":{"description":"Access forbidden - insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Access forbidden","error":"Insufficient permissions to access this resource"}}}},"ValidationError":{"description":"Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"InternalServerError":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Internal server error","error":"An unexpected error occurred"}}}}},"schemas":{"Admin":{"type":"object","required":["email","password","role"],"properties":{"id":{"type":"integer","description":"Unique admin identifier (6-8 digits)","minimum":100000,"maximum":99999999,"example":123456},"email":{"type":"string","format":"email","description":"Admin email address","example":"admin@yemert.co"},"password":{"type":"string","minLength":6,"maxLength":16,"description":"Admin password (must contain uppercase, lowercase, and special characters)","example":"AdminPass123!"},"role":{"type":"string","enum":["SUPER_ADMIN","ADMIN","INVESTOR","AUDITOR","SUPPORT"],"description":"Admin role level","example":"ADMIN"}}},"AdminLogin":{"type":"object","required":["id","password"],"properties":{"id":{"type":"integer","description":"Admin ID for login","minimum":100000,"maximum":99999999,"example":123456},"password":{"type":"string","minLength":6,"description":"Admin password","example":"AdminPass123!"}}},"Crop":{"type":"object","required":["cropName"],"properties":{"cropName":{"type":"string","description":"Name of the crop grown","example":"Maize"}}},"FarmPhoto":{"type":"object","required":["photoUrl"],"properties":{"photoUrl":{"type":"string","format":"uri","description":"URL of the farm photo","example":"https://example.com/farm-photo.jpg"}}},"Farmer":{"type":"object","required":["fullName","gender","countyDistrict","country","farmLocation","farmSize","yearsFarmingExperience","crops"],"properties":{"timestamp":{"type":"string","format":"date-time","description":"Registration timestamp","nullable":true},"fullName":{"type":"string","description":"Full name of the farmer","example":"John Kibet Doe"},"gender":{"type":"string","description":"Gender of the farmer","example":"Male"},"ageRange":{"type":"string","description":"Age range of the farmer","example":"30-40","nullable":true},"nationalIdNumber":{"type":"string","description":"National ID number","example":"12345678","nullable":true},"email":{"type":"string","format":"email","description":"Email address","example":"john.doe@example.com","nullable":true},"phoneNumber":{"type":"string","description":"Primary phone number","example":"+254712345678","nullable":true},"mobileMoney":{"type":"string","description":"Mobile money number","example":"+254712345678","nullable":true},"whatsappNumber":{"type":"string","description":"WhatsApp number","example":"+254712345678","nullable":true},"homeAddress":{"type":"string","description":"Home address","example":"123 Main Street, Nakuru","nullable":true},"countyDistrict":{"type":"string","description":"County or district","example":"Nakuru County"},"country":{"type":"string","description":"Country","example":"Kenya"},"farmLocation":{"type":"string","description":"Farm location","example":"Nakuru, Kenya"},"farmSize":{"type":"string","description":"Size of the farm","example":"5 acres"},"landOwnershipStatus":{"type":"string","description":"Land ownership status","example":"Owned","nullable":true},"yearsFarmingExperience":{"type":"string","description":"Years of farming experience","example":"10 years"},"crops":{"type":"array","items":{"$ref":"#/components/schemas/Crop"},"description":"List of crops grown"},"averageAnnualYield":{"type":"string","description":"Average annual yield","example":"50 bags","nullable":true},"farmingPractices":{"type":"string","description":"Farming practices used","example":"Organic farming","nullable":true},"annualFarmingRevenue":{"type":"string","description":"Annual farming revenue","example":"KES 500,000","nullable":true},"accessToCredit":{"type":"string","description":"Access to credit","example":"Yes","nullable":true},"previousInsurance":{"type":"string","description":"Previous insurance experience","example":"No","nullable":true},"produceSaleLocation":{"type":"string","description":"Where produce is sold","example":"Local market","nullable":true},"financialChallenge":{"type":"string","description":"Main financial challenge","example":"Access to credit","nullable":true},"recentChallenges":{"type":"string","description":"Recent farming challenges","example":"Drought","nullable":true},"soilManagement":{"type":"string","description":"Soil management practices","example":"Crop rotation","nullable":true},"irrigationAccess":{"type":"string","description":"Access to irrigation","example":"Yes","nullable":true},"climateResilientProgram":{"type":"string","description":"Participation in climate resilient programs","example":"No","nullable":true},"sustainablePractices":{"type":"string","description":"Sustainable farming practices","example":"Composting","nullable":true},"carbonCreditProgram":{"type":"string","description":"Interest in carbon credit programs","example":"Yes","nullable":true},"cropInsuranceInterest":{"type":"string","description":"Interest in crop insurance","example":"Very interested","nullable":true},"paymentFrequency":{"type":"string","description":"Preferred payment frequency","example":"Monthly","nullable":true},"insuranceConcerns":{"type":"string","description":"Insurance concerns","example":"Cost","nullable":true},"recommendInsurance":{"type":"string","description":"Would recommend insurance to others","example":"Yes","nullable":true},"farmPhotos":{"type":"array","items":{"$ref":"#/components/schemas/FarmPhoto"},"description":"Farm photos"},"dataConsent":{"type":"boolean","description":"Data usage consent","example":true,"nullable":true},"isUssd":{"type":"boolean","description":"Registered via USSD","example":false,"nullable":true},"bankAccountNumber":{"type":"string","description":"Bank account number for refunds","example":"0123456789","nullable":true},"bankCode":{"type":"string","description":"Bank code for refunds","example":"044","nullable":true},"bankName":{"type":"string","description":"Bank name for refunds","example":"Access Bank","nullable":true},"refundAccount":{"$ref":"#/components/schemas/RefundAccount","nullable":true,"description":"Refund account details (mobile money or bank account)"}}},"RefundAccount":{"type":"object","description":"Refund account information - either mobile money or bank account","nullable":true,"oneOf":[{"type":"object","title":"MobileMoneyRefund","properties":{"type":{"type":"string","enum":["mobile_money"],"description":"Type of refund account","example":"mobile_money"},"momoNumber":{"type":"string","description":"Mobile money phone number","example":"08012345678"}},"required":["type","momoNumber"]},{"type":"object","title":"BankAccountRefund","properties":{"type":{"type":"string","enum":["bank_account"],"description":"Type of refund account","example":"bank_account"},"accountNumber":{"type":"string","description":"Bank account number","example":"0123456789"},"bankCode":{"type":"string","description":"Bank code","example":"044"},"bankName":{"type":"string","description":"Bank name","example":"Access Bank","nullable":true}},"required":["type","accountNumber","bankCode"]}],"example":{"type":"bank_account","accountNumber":"0123456789","bankCode":"044","bankName":"Access Bank"}},"USSDRequest":{"type":"object","required":["sessionId","serviceCode","phoneNumber","text"],"properties":{"sessionId":{"type":"string","description":"USSD session identifier","example":"ATUid_12345"},"serviceCode":{"type":"string","description":"USSD service code","example":"*384*96#"},"phoneNumber":{"type":"string","description":"User's phone number","example":"+254712345678"},"text":{"type":"string","description":"User input text","example":"1*John Doe*Male"}}},"InsuranceRequest":{"type":"object","required":["farmerId","cropType","farmSize","location"],"properties":{"farmerId":{"type":"string","description":"Farmer's Yemert ID","example":"12345"},"cropType":{"type":"string","description":"Type of crop to insure","example":"Maize"},"farmSize":{"type":"string","description":"Size of farm to insure","example":"5 acres"},"location":{"type":"string","description":"Farm location","example":"Nakuru, Kenya"},"coverageAmount":{"type":"number","description":"Desired coverage amount","example":100000}}},"InsuranceData":{"type":"object","properties":{"id":{"type":"integer","description":"Insurance record ID","example":1},"farmerId":{"type":"string","description":"Farmer's Yemert ID","example":"12345"},"cropType":{"type":"string","description":"Insured crop type","example":"Maize"},"farmSize":{"type":"string","description":"Insured farm size","example":"5 acres"},"location":{"type":"string","description":"Farm location","example":"Nakuru, Kenya"},"coverageAmount":{"type":"number","description":"Coverage amount","example":100000},"premium":{"type":"number","description":"Insurance premium","example":5000},"status":{"type":"string","description":"Insurance status","example":"Active"},"createdAt":{"type":"string","format":"date-time","description":"Creation timestamp","example":"2024-01-10T10:30:00Z"}}},"YemertMarketSell":{"type":"object","properties":{"id":{"type":"integer","description":"Unique identifier for the market post","example":123},"farmerId":{"type":"string","description":"Yemert ID of the farmer who created the post","example":"12345"},"cropType":{"type":"string","description":"Type of crop being sold","example":"Maize"},"quantity":{"type":"number","description":"Quantity of crop available (in kg)","example":500.5},"pricePerKg":{"type":"number","description":"Price per kilogram in local currency","example":25.75},"totalPrice":{"type":"number","description":"Total price for the entire quantity","example":12887.5},"harvestDate":{"type":"string","format":"date","description":"Date when the crop was harvested","example":"2024-01-15"},"expiryDate":{"type":"string","format":"date","description":"Expiry date of the crop","example":"2024-06-15"},"location":{"type":"string","description":"Location where the crop is available","example":"Nakuru County, Kenya"},"description":{"type":"string","description":"Additional description of the crop","example":"Fresh organic maize, well dried and stored properly"},"contactInfo":{"type":"string","description":"Contact information for the farmer","example":"+254712345678"},"isAvailable":{"type":"boolean","description":"Whether the crop is still available for sale","example":true},"qualityGrade":{"type":"string","description":"Quality grade of the crop","enum":["A","B","C"],"example":"A"},"organicCertified":{"type":"boolean","description":"Whether the crop is organically certified","example":true},"createdAt":{"type":"string","format":"date-time","description":"Timestamp when the market post was created","example":"2024-01-10T10:30:00Z"},"updatedAt":{"type":"string","format":"date-time","description":"Timestamp when the market post was last updated","example":"2024-01-12T14:20:00Z"},"farmer":{"type":"object","description":"Farmer information","properties":{"yemertId":{"type":"string","example":"12345"},"fullName":{"type":"string","example":"John Doe"},"phoneNumber":{"type":"string","example":"+254712345678"},"location":{"type":"string","example":"Nakuru County"}}}},"required":["farmerId","cropType","quantity","pricePerKg","totalPrice","harvestDate","location","contactInfo","isAvailable"]},"YemertMarketSellInput":{"type":"object","properties":{"farmerId":{"type":"string","description":"Yemert ID of the farmer creating the post","example":"12345"},"cropType":{"type":"string","description":"Type of crop being sold","example":"Maize"},"quantity":{"type":"number","minimum":0.1,"description":"Quantity of crop available (in kg)","example":500.5},"pricePerKg":{"type":"number","minimum":0.01,"description":"Price per kilogram in local currency","example":25.75},"harvestDate":{"type":"string","format":"date","description":"Date when the crop was harvested","example":"2024-01-15"},"expiryDate":{"type":"string","format":"date","description":"Expiry date of the crop (optional)","example":"2024-06-15"},"location":{"type":"string","description":"Location where the crop is available","example":"Nakuru County, Kenya"},"description":{"type":"string","description":"Additional description of the crop (optional)","example":"Fresh organic maize, well dried and stored properly"},"contactInfo":{"type":"string","description":"Contact information for the farmer","example":"+254712345678"},"qualityGrade":{"type":"string","description":"Quality grade of the crop (optional)","enum":["A","B","C"],"example":"A"},"organicCertified":{"type":"boolean","description":"Whether the crop is organically certified (optional)","example":true}},"required":["farmerId","cropType","quantity","pricePerKg","harvestDate","location","contactInfo"]},"YemertMarketSellUpdateInput":{"type":"object","properties":{"cropType":{"type":"string","description":"Type of crop being sold","example":"Maize"},"quantity":{"type":"number","minimum":0.1,"description":"Quantity of crop available (in kg)","example":500.5},"pricePerKg":{"type":"number","minimum":0.01,"description":"Price per kilogram in local currency","example":25.75},"harvestDate":{"type":"string","format":"date","description":"Date when the crop was harvested","example":"2024-01-15"},"expiryDate":{"type":"string","format":"date","description":"Expiry date of the crop","example":"2024-06-15"},"location":{"type":"string","description":"Location where the crop is available","example":"Nakuru County, Kenya"},"description":{"type":"string","description":"Additional description of the crop","example":"Fresh organic maize, well dried and stored properly"},"contactInfo":{"type":"string","description":"Contact information for the farmer","example":"+254712345678"},"isAvailable":{"type":"boolean","description":"Whether the crop is still available for sale","example":true},"qualityGrade":{"type":"string","description":"Quality grade of the crop","enum":["A","B","C"],"example":"A"},"organicCertified":{"type":"boolean","description":"Whether the crop is organically certified","example":true}}},"ValidationError":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Validation failed"},"errors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","example":"cropType"},"message":{"type":"string","example":"Crop type is required"}}}}}},"PingResponse":{"type":"object","properties":{"pong":{"type":"boolean","example":true,"description":"Indicates the API is responding"},"timestamp":{"type":"string","format":"date-time","description":"Current server time (ISO 8601)"},"uptime":{"type":"number","description":"Process uptime in seconds","example":3600}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Operation completed successfully"},"data":{"type":"object","description":"Response data"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"An error occurred"},"error":{"type":"string","description":"Error details","example":"Detailed error message"}}}}},"security":[],"paths":{"/admin/partners":{"post":{"summary":"Create partner integration","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","code","countries"],"properties":{"name":{"type":"string"},"code":{"type":"string"},"countries":{"type":"array","items":{"type":"string"}},"regions":{"type":"array","items":{"type":"string"}},"priority":{"type":"integer","minimum":0},"webhookUrl":{"type":"string","format":"uri"},"markupType":{"type":"string","enum":["PERCENT","FIXED"]},"markupValue":{"type":"number","minimum":0},"taxConfig":{"type":"object"},"isActive":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Partner created (includes one-time secrets)"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (SUPER_ADMIN required)"}}},"get":{"summary":"List partners and active plans","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Partners retrieved"},"401":{"description":"Unauthorized"}}}},"/admin/partners/{id}":{"patch":{"summary":"Update partner integration","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Partner updated"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (SUPER_ADMIN required)"}}}},"/admin/partners/{id}/rotate-api-key":{"post":{"summary":"Rotate partner API key","description":"Returns a newly generated API key once. Store securely.","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"API key rotated"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (SUPER_ADMIN required)"}}}},"/admin/partners/{id}/rotate-webhook-secret":{"post":{"summary":"Rotate partner webhook signing secret","description":"Returns a newly generated webhook secret once. Store securely.","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook secret rotated"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (SUPER_ADMIN required)"}}}},"/admin/partners/{partnerId}/plans":{"post":{"summary":"Create partner plan","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"partnerId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"priority":{"type":"integer","minimum":0},"isActive":{"type":"boolean"},"countries":{"type":"array","items":{"type":"string"}},"regions":{"type":"array","items":{"type":"string"}},"crops":{"type":"array","items":{"type":"string"}},"basePremiumConfig":{"type":"object"},"dataSchema":{"type":"object"}}}}}},"responses":{"201":{"description":"Plan created"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (SUPER_ADMIN required)"}}},"get":{"summary":"List partner plans","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"partnerId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Plans retrieved"},"401":{"description":"Unauthorized"}}}},"/admin/partner-plans/{id}":{"patch":{"summary":"Update partner plan","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Plan updated"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (SUPER_ADMIN required)"}}}},"/admin/partner-purchases":{"get":{"summary":"List partner purchases across partners","tags":["Partner Integrations"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"partnerId","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["PENDING","PAID","CANCELLED","FAILED"]}},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Purchases retrieved"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}}}},"/admin":{"post":{"summary":"Create a new admin user (SUPER_ADMIN only)","description":"Creates a new admin user with specified role and email. Only accessible by SUPER_ADMIN users.","tags":["RBAC Management"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","role"],"properties":{"email":{"type":"string","format":"email","description":"Email address for the new admin"},"role":{"type":"string","enum":["ADMIN","INVESTOR","AUDITOR","SUPPORT"],"description":"Role for the new admin (SUPER_ADMIN can only create ADMIN, INVESTOR, AUDITOR, or SUPPORT roles)"}}},"example":{"email":"newadmin@example.com","role":"ADMIN"}}}},"responses":{"201":{"description":"Admin created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"integer"},"adminId":{"type":"integer"},"email":{"type":"string"},"role":{"type":"string"},"initialPassword":{"type":"string","description":"Auto-generated initial password for the new admin"}}},"message":{"type":"string","example":"Admin created successfully. Please securely share the initial password with the new admin."}}}}}},"400":{"description":"Bad Request - Invalid input data"},"401":{"description":"Unauthorized - Authentication required"},"403":{"description":"Forbidden - User does not have SUPER_ADMIN role"},"409":{"description":"Conflict - An admin with this email already exists"}}}},"/admin/login":{"post":{"summary":"Admin user login","description":"Authenticates an admin user and returns a JWT token for subsequent API calls.","tags":["Admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLogin"},"example":{"id":123456,"password":"AdminPass123!"}}}},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer","example":123456},"email":{"type":"string","example":"admin@yemert.com"},"role":{"type":"string","example":"ADMIN"},"token":{"type":"string","description":"JWT authentication token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}}}}}]}}}},"400":{"description":"Invalid credentials or input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/logout":{"post":{"summary":"Logout admin user","description":"Logs out the current admin user by clearing the authentication cookie.","tags":["Admin"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Logged out successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","example":null},"message":{"type":"string","example":"Logged out successfully"}}}]}}}},"401":{"description":"Unauthorized - Not logged in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admins":{"get":{"summary":"Get all admin users","description":"Retrieves a list of all admin users. Protected endpoint that requires admin authentication.","tags":["RBAC Management"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Admins retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":123456},"adminId":{"type":"integer","example":123456},"email":{"type":"string","example":"admin@yemert.com"},"role":{"type":"string","description":"Admin role (SUPER_ADMIN, ADMIN, INVESTOR, AUDITOR, SUPPORT)","example":"ADMIN"},"access":{"type":"boolean","example":true},"dateJoined":{"type":"string","format":"date-time","example":"2023-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","example":"2023-01-01T00:00:00.000Z"}}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/profile":{"get":{"summary":"Get logged-in admin profile","tags":["RBAC Management"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Admin profile retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"id":{"type":"string"},"adminId":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"dateJoined":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Admin profile not found"},"500":{"description":"Internal server error"}}}},"/admin/profile/{identifier}":{"get":{"summary":"Get admin by ID or email (SUPER_ADMIN and ADMIN only)","tags":["RBAC Management"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"identifier","required":true,"schema":{"type":"string"},"description":"Admin ID or email"}],"responses":{"200":{"description":"Admin details retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"id":{"type":"string"},"adminId":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"dateJoined":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Access denied - insufficient permissions"},"404":{"description":"Admin not found"},"500":{"description":"Internal server error"}}}},"/admin/transactions":{"get":{"summary":"Search and list transactions with filtering and pagination","tags":["Admin"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"search","schema":{"type":"string"},"description":"Search term for reference, msisdn, or farmer details"},{"in":"query","name":"status","schema":{"type":"string","enum":["PENDING","SUCCESSFUL","FAILED"]},"description":"Filter by status"},{"in":"query","name":"provider","schema":{"type":"string","enum":["MTN","AIRTEL","NONE"]},"description":"Filter by provider"},{"in":"query","name":"startDate","schema":{"type":"string","format":"date"},"description":"Filter by start date (ISO)"},{"in":"query","name":"endDate","schema":{"type":"string","format":"date"},"description":"Filter by end date (ISO)"},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Number of items per page"}],"responses":{"200":{"description":"Transactions retrieved successfully"},"400":{"description":"Bad Request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/admin/accounting/overview":{"get":{"summary":"Accounting overview KPIs","tags":["Accounting"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"startDate","schema":{"type":"string","format":"date-time"},"description":"Optional range start (ISO)"},{"in":"query","name":"endDate","schema":{"type":"string","format":"date-time"},"description":"Optional range end (ISO)"}],"responses":{"200":{"description":"Overview metrics"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (requires accounting.overview.view)"},"500":{"description":"Internal server error"}}}},"/admin/accounting/accounts/balances":{"get":{"summary":"Account balances (ledger)","tags":["Accounting"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"accountType","schema":{"type":"string","enum":["ASSET","LIABILITY","EQUITY","REVENUE","EXPENSE"]}},{"in":"query","name":"currency","schema":{"type":"string"}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Paginated balances"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (requires accounting.balances.view)"},"500":{"description":"Internal server error"}}}},"/admin/accounting/entries":{"get":{"summary":"Ledger journal entries","tags":["Accounting"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"accountCode","schema":{"type":"string"}},{"in":"query","name":"sourceType","schema":{"type":"string"}},{"in":"query","name":"reference","schema":{"type":"string"}},{"in":"query","name":"startDate","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"endDate","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Paginated ledger lines"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (requires accounting.entries.view)"},"500":{"description":"Internal server error"}}}},"/admin/accounting/transactions":{"get":{"summary":"Financial transactions (accounting view)","description":"Filterable list of transactions for accounting; requires `transactions.view`.","tags":["Accounting"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["PENDING","SUCCESSFUL","FAILED"]}},{"in":"query","name":"provider","schema":{"type":"string","enum":["MTN","AIRTEL","MONNIFY","NONE"]}},{"in":"query","name":"type","schema":{"type":"string","enum":["REQUEST","SEND"]}},{"in":"query","name":"accountCode","schema":{"type":"string"}},{"in":"query","name":"startDate","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"endDate","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Paginated transactions"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}}}},"/admins/search":{"get":{"summary":"Search and list admins with filtering and pagination","tags":["RBAC Management"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"search","schema":{"type":"string"},"description":"Search term for admin ID, email, or role"},{"in":"query","name":"role","schema":{"type":"string","enum":["SUPER_ADMIN","ADMIN","INVESTOR","AUDITOR","SUPPORT"]},"description":"Filter by role"},{"in":"query","name":"sortBy","schema":{"type":"string","enum":["createdAt","email","role","adminId"],"default":"createdAt"},"description":"Field to sort by"},{"in":"query","name":"sortOrder","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sort order"},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"description":"Number of items per page"}],"responses":{"200":{"description":"Admins retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"adminId":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"dateJoined":{"type":"string","format":"date-time"}}}},"pagination":{"type":"object","properties":{"currentPage":{"type":"integer"},"totalPages":{"type":"integer"},"totalItems":{"type":"integer"},"itemsPerPage":{"type":"integer"},"hasNextPage":{"type":"boolean"},"hasPrevPage":{"type":"boolean"}}}}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/admin/telemetry/users":{"get":{"summary":"Get user telemetry data","description":"Returns total and active user counts","tags":["Telemetry"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"User telemetry retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"total":{"type":"integer","example":1250},"active":{"type":"integer","example":980}}}}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/admin/telemetry/policies":{"get":{"summary":"Get policy telemetry data","description":"Returns total and active policy counts","tags":["Telemetry"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Policy telemetry retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"total":{"type":"integer","example":450},"active":{"type":"integer","example":320}}}}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/admin/telemetry/revenue":{"get":{"summary":"Get revenue telemetry data","description":"Returns total revenue from successful credit transactions for the current year","tags":["Telemetry"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Revenue telemetry retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"total":{"type":"number","example":15750000.5},"currency":{"type":"string","example":"NGN"},"year":{"type":"integer","example":2026}}}}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/admin/crop-catalog":{"get":{"summary":"List crop catalog entries","description":"Returns a paginated list of crops in the catalog","tags":["Crop Catalog"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1},"description":"Page number"},{"in":"query","name":"limit","schema":{"type":"integer","default":20},"description":"Number of items per page"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Filter crops by name"},{"in":"query","name":"isActive","schema":{"type":"boolean"},"description":"Filter by active status"}],"responses":{"200":{"description":"Crop catalog retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CropCatalog"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}},"post":{"summary":"Create a crop catalog entry","description":"Adds a new crop to the catalog","tags":["Crop Catalog"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","category"],"properties":{"name":{"type":"string","example":"Maize"},"category":{"type":"string","example":"Cereal"},"description":{"type":"string","example":"A staple cereal grain"},"imageUrl":{"type":"string","format":"uri","example":"https://cdn.example.com/crops/maize.jpg"}}}}}},"responses":{"201":{"description":"Crop catalog entry created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/CropCatalog"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"409":{"description":"Crop with this name already exists"},"500":{"description":"Internal server error"}}}},"/admin/crop-catalog/{id}":{"patch":{"summary":"Update a crop catalog entry","description":"Updates the details of an existing crop in the catalog","tags":["Crop Catalog"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Crop catalog entry ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Maize (Updated)"},"category":{"type":"string","example":"Cereal"},"description":{"type":"string","example":"Updated description"},"imageUrl":{"type":"string","format":"uri","example":"https://cdn.example.com/crops/maize-updated.jpg"}}}}}},"responses":{"200":{"description":"Crop catalog entry updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/CropCatalog"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Crop catalog entry not found"},"500":{"description":"Internal server error"}}},"delete":{"summary":"Deactivate a crop catalog entry","description":"Soft-deletes a crop from the catalog by marking it as inactive","tags":["Crop Catalog"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Crop catalog entry ID"}],"responses":{"200":{"description":"Crop catalog entry deactivated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Crop catalog entry not found"},"500":{"description":"Internal server error"}}}},"/admin/countries":{"get":{"summary":"List all countries","description":"Returns a list of all countries with their support status, regions, and dial codes","tags":["Countries"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Countries retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/admin/countries/{country}":{"get":{"summary":"Get a country by code","description":"Returns details of a specific country including its regions and dial codes","tags":["Countries"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"country","required":true,"schema":{"type":"string"},"description":"ISO 3166-1 alpha-2 country code","example":"NG"}],"responses":{"200":{"description":"Country retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Country"}}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Country not found"},"500":{"description":"Internal server error"}}}},"/admin/countries/{country}/support":{"patch":{"summary":"Update country support status","description":"Enables or disables platform support for a specific country","tags":["Countries"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"country","required":true,"schema":{"type":"string"},"description":"ISO 3166-1 alpha-2 country code","example":"NG"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["isSupported"],"properties":{"isSupported":{"type":"boolean","example":true}}}}}},"responses":{"200":{"description":"Country support status updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Country"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Country not found"},"500":{"description":"Internal server error"}}}},"/admin/countries/{country}/regions":{"patch":{"summary":"Update country regions","description":"Replaces or appends the list of administrative regions for a country","tags":["Countries"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"country","required":true,"schema":{"type":"string"},"description":"ISO 3166-1 alpha-2 country code","example":"NG"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["regions"],"properties":{"regions":{"type":"array","items":{"type":"string"},"example":["Lagos","Abuja","Kano","Rivers"]}}}}}},"responses":{"200":{"description":"Country regions updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Country"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Country not found"},"500":{"description":"Internal server error"}}}},"/admin/countries/{country}/dial-codes":{"patch":{"summary":"Update country dial codes","description":"Replaces the list of phone dial codes associated with a country","tags":["Countries"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"country","required":true,"schema":{"type":"string"},"description":"ISO 3166-1 alpha-2 country code","example":"NG"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dialCodes"],"properties":{"dialCodes":{"type":"array","items":{"type":"string"},"example":["+234"]}}}}}},"responses":{"200":{"description":"Country dial codes updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Country"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Country not found"},"500":{"description":"Internal server error"}}}},"/admin/disbursements":{"get":{"summary":"Get all disbursements","tags":["Disbursements"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"List of disbursements","content":{"application/json":{"example":{"success":true,"message":"Disbursements fetched","data":[{"id":1,"status":"PENDING","amount":2000}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/admin/disbursements/pending":{"get":{"summary":"Get all pending disbursements","tags":["Disbursements"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"List of pending disbursements"}}}},"/admin/disbursements/payout":{"post":{"summary":"Initiate a payout","tags":["Disbursements"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","narration","destinationBankCode","destinationAccountNumber","sourceAccountNumber"]}}}},"responses":{"200":{"description":"Payout initiated"}}}},"/admin/disbursements/authorize-payout":{"post":{"summary":"Authorize a payout with OTP","tags":["Disbursements"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reference","authorizationCode"]}}}},"responses":{"200":{"description":"Payout authorized"}}}},"/admin/disbursements/bulk-payout":{"post":{"summary":"Initiate a bulk payout","tags":["Disbursements"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["narration","transactions"],"properties":{"title":{"type":"string","example":"Bulk Disbursement"},"narration":{"type":"string","example":"Farmer Payout Batch"},"transactions":{"type":"array","items":{"type":"object","required":["amount","destinationBankCode","destinationAccountNumber"],"properties":{"farmerId":{"type":"number","example":12},"amount":{"type":"number","example":1000},"narration":{"type":"string","example":"Farmer payout"},"destinationBankCode":{"type":"string","example":"058"},"destinationAccountNumber":{"type":"string","example":"0123456789"},"destinationAccountName":{"type":"string","example":"John Doe"},"reference":{"type":"string","example":"BULK-REF-001"}}}}}}}}},"responses":{"200":{"description":"Bulk payout initiated"}}}},"/admin/disbursements/authorize-bulk-payout":{"post":{"summary":"Authorize a bulk payout with OTP (batchReference)","tags":["Disbursements"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["batchReference","authorizationCode"],"properties":{"batchReference":{"type":"string","example":"batchreference--12934"},"authorizationCode":{"type":"string","example":"123456","description":"OTP sent to authorized email"}}}}}},"responses":{"200":{"description":"Bulk payout authorized"}}}},"/farmers":{"post":{"summary":"Register a new farmer","description":"Creates a new farmer record with comprehensive agricultural and personal information. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Farmer"},"example":{"fullName":"John Kibet Doe","gender":"Male","ageRange":"30-40","nationalIdNumber":"12345678","email":"john.doe@example.com","phoneNumber":"+254712345678","countyDistrict":"Uasin Gishu","country":"Kenya","farmLocation":"Eldoret Rural","farmSize":5.5,"yearsFarmingExperience":"10","crops":[{"cropName":"Maize"},{"cropName":"Beans"}],"farmingPractices":"Organic farming","accessToCredit":"Yes","previousInsurance":"No","produceSaleLocation":"Local market","irrigationAccess":false,"climateResilientProgram":false,"carbonCreditProgram":false,"cropInsuranceInterest":true,"farmPhotos":["https://example.com/farm1.jpg","https://example.com/farm2.jpg"],"dataConsent":true}}}},"responses":{"201":{"description":"Farmer created successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"createdAt":{"type":"string","format":"date-time"}}}}}]}}}},"400":{"description":"Invalid input data or validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Farmer with similar details already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Get all farmers","description":"Retrieves a list of all registered farmers with their basic information. Supports pagination and filtering.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"query","name":"all","schema":{"type":"boolean","default":false},"description":"Set to 'true' to retrieve all farmers without pagination"},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number for pagination (ignored if all=true)"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Number of farmers per page (ignored if all=true)"},{"in":"query","name":"country","schema":{"type":"string"},"description":"Filter by country"},{"in":"query","name":"countyDistrict","schema":{"type":"string"},"description":"Filter by county or district"}],"responses":{"200":{"description":"Farmers retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"gender":{"type":"string","example":"Male"},"phoneNumber":{"type":"string","example":"+254712345678"},"countyDistrict":{"type":"string","example":"Uasin Gishu"},"country":{"type":"string","example":"Kenya"},"farmSize":{"type":"number","example":5.5},"nationalIdNumber":{"type":"string","example":"12345678"},"createdAt":{"type":"string","format":"date-time"}}}},"pagination":{"type":"object","properties":{"total":{"type":"integer","example":150},"page":{"type":"integer","example":1},"limit":{"type":"integer","example":20},"totalPages":{"type":"integer","example":8}}}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"summary":"Delete all farmers","description":"Permanently deletes all farmer records from the database. This is a destructive operation that cannot be undone. Use with extreme caution.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"All farmers deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"deletedCount":{"type":"integer","description":"Number of farmers deleted","example":150},"message":{"type":"string","example":"All farmer records have been permanently deleted"}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error during deletion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/batch":{"post":{"summary":"Bulk register farmers from file upload","description":"Creates multiple farmer records from an uploaded Excel/CSV file. Processes and validates each farmer entry before registration. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"Excel or CSV file containing farmer data"}},"required":["file"]}}}},"responses":{"201":{"description":"Farmers created successfully from batch upload","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"totalProcessed":{"type":"integer","example":50},"successful":{"type":"integer","example":48},"failed":{"type":"integer","example":2},"farmers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"yemertId":{"type":"string"},"fullName":{"type":"string"}}}}}}}}]}}}},"400":{"description":"Invalid file format or data validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"File too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/farmerId/{id}":{"get":{"summary":"Get farmer by ID","description":"Retrieves detailed information about a specific farmer using their unique ID.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer","minimum":1},"description":"Unique farmer ID","example":1}],"responses":{"200":{"description":"Farmer details retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"gender":{"type":"string","example":"Male"},"phoneNumber":{"type":"string","example":"+254712345678"},"countyDistrict":{"type":"string","example":"Uasin Gishu"},"country":{"type":"string","example":"Kenya"},"farmLocation":{"type":"string","example":"Eldoret Rural"},"farmSize":{"type":"number","example":5.5},"crops":{"type":"array","items":{"type":"string"},"example":["Maize","Beans"]},"nationalIdNumber":{"type":"string","example":"12345678"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}]}}}},"400":{"description":"Invalid farmer ID format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/{yemertId}":{"delete":{"summary":"Delete a farmer by Yemert ID","description":"Permanently deletes a specific farmer record from the database. This is a destructive operation that cannot be undone. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The Yemert ID of the farmer to delete (with or without the YM- prefix)"}],"responses":{"200":{"description":"Farmer deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"yemertId":{"type":"string","example":"YM-123456"},"fullName":{"type":"string","example":"John Doe"},"createdAt":{"type":"string","format":"date-time"}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error during deletion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/payments/manual-payments/pending":{"get":{"tags":["Payments"],"summary":"Get all pending manual payments","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/schemas/SuccessResponse"}}}},"/payments/payouts/failed":{"get":{"tags":["Payments"],"summary":"Get failed payouts requiring manual intervention"}},"/payments/manual-payments/confirm":{"post":{"tags":["Payments"],"summary":"Confirm a manual payment (farmer paid manually)"}},"/payments/manual-payouts/confirm":{"post":{"tags":["Payments"],"summary":"Confirm a manual payout","description":"Marks an insurance payment split as completed after a manual payout has been performed outside the automated disbursement flow. Only records with status `needs_manual_payout` can be confirmed. Attaches the payout reference, optional notes, and a completion timestamp to the existing payout response.\n","security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["linkId","payoutRef"],"properties":{"linkId":{"type":"string","description":"Unique identifier of the insurance payment split record","example":"lnk_01J9XK3M5B8YQZN2P4WVFR7CT"},"payoutRef":{"type":"string","description":"External reference number from the manual payout (e.g. bank transfer ref)","example":"TRF-2025-00842"},"notes":{"type":"string","description":"Optional notes about the manual payout (reason, channel used, etc.)","example":"Paid via GTB transfer due to Monnify downtime"}}}}}},"responses":{"200":{"description":"Payout confirmed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Payout confirmed successfully"},"data":{"type":"object","properties":{"linkId":{"type":"string","example":"lnk_01J9XK3M5B8YQZN2P4WVFR7CT"},"insurerName":{"type":"string","nullable":true,"example":"Leadway Assurance"},"insurerAmount":{"type":"number","example":45000},"payoutRef":{"type":"string","example":"TRF-2025-00842"}}}}}}}},"400":{"description":"Validation error — missing fields or record is not in the correct status","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","examples":{"missing_fields":{"value":"linkId and payoutRef are required"},"wrong_status":{"value":"Cannot confirm payout with status: completed"}}}}}}}},"401":{"description":"Unauthenticated — missing or invalid token"},"403":{"description":"Forbidden — caller lacks required permission"},"404":{"description":"Payment record not found for the given linkId","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Payment record not found"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Failed to confirm payout"}}}}}}}}},"/payments/statistics":{"get":{"tags":["Payments"]}},"/payments/insurers":{"get":{"tags":["Payments"],"summary":"Get all insurer configurations","description":"Retrieves the list of insurer configurations.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of insurer configurations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Payments"],"summary":"Create or update an insurer configuration","description":"Upserts (creates or updates) an insurer configuration. Only accessible by SUPER_ADMIN.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","accountNumber","bankCode"],"properties":{"name":{"type":"string","example":"Insurer ABC"},"accountNumber":{"type":"string","example":"0123456789"},"accountName":{"type":"string","example":"Insurer ABC Ltd"},"bankCode":{"type":"string","example":"058"},"bankName":{"type":"string","example":"GTBank"},"walletProvider":{"type":"string","example":"Moniepoint"},"splitPercentage":{"type":"number","example":75,"description":"Split percentage between 0 and 100"},"isActive":{"type":"boolean","example":true},"metadata":{"type":"object","example":{"region":"West Africa"}}}}}}},"responses":{"200":{"description":"Insurer configuration saved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Validation error (missing required fields or invalid splitPercentage)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized or not SUPER_ADMIN","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/payments/insurers/{id}":{"patch":{"tags":["Payments"]}},"/payments/{linkId}":{"get":{"tags":["Payments"]}},"/payments/manual-payments/bulk-confirm":{"post":{"tags":["Payments"]}},"/payments/stats/weekly-payouts":{"post":{"tags":["Payments"]}},"/wallets/monnify/webhook":{"post":{"summary":"Receive Monnify Webhook","tags":["Wallets"],"parameters":[{"in":"header","name":"monnify-signature","required":true,"schema":{"type":"string"},"description":"HMAC-SHA512 signature for security"}],"responses":{"200":{"description":"Webhook received"}}}},"/wallets/monnify/{yemertId}/ensure":{"post":{"summary":"Create Monnify wallet for a farmer (idempotent)","tags":["Wallets"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"Yemert ID (e.g. 1234 or YM-1234)"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"walletName":{"type":"string"},"customerName":{"type":"string"},"customerEmail":{"type":"string","format":"email"},"nin":{"type":"string","example":"12345678901","description":"National Identification Number (11 digits)"}}}}}},"responses":{"200":{"description":"Wallet ensured"}}}},"/wallets/monnify/balance":{"get":{"summary":"Get Yemert Global Merchant Wallet Balance","tags":["Wallets"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Global wallet balance"}}}},"/wallets/monnify/payout":{"post":{"summary":"Initiate a single payout to a bank account","tags":["Wallets"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","narration","destinationBankCode","destinationAccountNumber","sourceAccountNumber"],"properties":{"amount":{"type":"number","example":1000},"narration":{"type":"string","example":"Farmer Payout"},"destinationBankCode":{"type":"string","example":"058"},"destinationAccountNumber":{"type":"string","example":"0123456789"},"sourceAccountNumber":{"type":"string","example":"7657167485"}}}}}},"responses":{"200":{"description":"Payout initiated"}}}},"/wallets/monnify/bulk-payout":{"post":{"summary":"Initiate a bulk payout to multiple bank accounts","tags":["Wallets"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","narration","sourceAccountNumber","transactions"],"properties":{"title":{"type":"string","example":"Weekly Bulk Payout"},"narration":{"type":"string","example":"Payment for harvest"},"sourceAccountNumber":{"type":"string"},"transactions":{"type":"array","items":{"type":"object","properties":{"amount":{"type":"number"},"destinationBankCode":{"type":"string"},"destinationAccountNumber":{"type":"string"},"narration":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Bulk payout initiated"}}}},"/wallets/monnify/authorize-payout":{"post":{"summary":"Authorize a pending payout with OTP","tags":["Wallets"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reference","authorizationCode"],"properties":{"reference":{"type":"string","example":"DISB-1737389000001-123","description":"The disbursement reference"},"authorizationCode":{"type":"string","example":"123456","description":"OTP sent to authorized email"}}}}}},"responses":{"200":{"description":"Payout authorized"}}}},"/wallets/monnify/banks":{"get":{"summary":"Get list of banks for disbursement","tags":["Wallets"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"List of banks"}}}},"/mtn_callback":{"post":{"summary":"Receive MTN callback","tags":["Callbacks"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Callback acknowledged"}}},"get":{"summary":"Receive MTN callback (query mode)","tags":["Callbacks"],"security":[],"responses":{"200":{"description":"Callback acknowledged"}}}},"/partners/me":{"get":{"summary":"Get authenticated partner profile","tags":["Partners"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Partner profile fetched successfully","content":{"application/json":{"example":{"success":true,"message":"Partner profile fetched","data":{"id":"ptnr_001","name":"Acme Insurance","slug":"acme-insurance"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/partners/purchases":{"get":{"summary":"List partner purchases","description":"Returns purchases belonging to the authenticated partner.","tags":["Partner Integrations"],"security":[{"BearerAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["PENDING","PAID","CANCELLED","FAILED"]}},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Purchases retrieved"},"401":{"description":"Missing/invalid API key"},"500":{"description":"Internal server error"}}}},"/partners/purchases/{id}":{"get":{"summary":"Get a single partner purchase","description":"Returns one purchase owned by the authenticated partner.","tags":["Partner Integrations"],"security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"example":"prc_001"}],"responses":{"200":{"description":"Partner purchase fetched successfully","content":{"application/json":{"example":{"success":true,"message":"Purchase fetched","data":{"id":"prc_001","status":"SUCCESSFUL","amount":1200,"currency":"NGN"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Purchase not found"}}}},"/partners/plans":{"get":{"summary":"List active plans for authenticated partner","tags":["Partner Integrations"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Partner plans fetched successfully","content":{"application/json":{"example":{"success":true,"message":"Plans fetched","data":[{"id":"plan_001","name":"Starter","amount":500}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/admin/rbac/seed-defaults":{"post":{"summary":"Seed RBAC defaults","description":"Idempotently upserts the default permission catalog, features, and built-in role→permission maps (`ensureDefaultCatalog`).\n**Requires `SUPER_ADMIN` JWT** (middleware `CheckSuperAdminRole`), not only `rbac.manage`.\n","tags":["RBAC"],"security":[{"AdminAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Force reseed of defaults if supported.","example":false}}}}}},"responses":{"200":{"description":"RBAC defaults seeded successfully."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/admin/rbac/me":{"get":{"summary":"Resolve RBAC for current admin","description":"Returns legacy `role` from the JWT, **effective** permission keys (legacy role + assigned `rbac_roles` + direct grants),\nand **visible** sidebar features derived from those keys. No `rbac.manage` required.\n","tags":["RBAC"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"RBAC context resolved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"RBAC resolved successfully"},"data":{"type":"object","properties":{"role":{"type":"string","example":"SUPER_ADMIN"},"permissions":{"type":"array","items":{"type":"string"},"example":["overview.view","farmers.view","rbac.manage"]},"features":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","nullable":true},"icon":{"type":"string","nullable":true}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/admin/rbac/permissions":{"get":{"summary":"List permissions","tags":["RBAC"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"Permission list fetched successfully."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"summary":"Create or update permission","description":"Upserts `rbac_permissions` by `key`. **Requires effective `rbac.manage`.**","tags":["RBAC"],"security":[{"AdminAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key","title"],"properties":{"key":{"type":"string","example":"accounting.entries.view"},"title":{"type":"string","example":"View accounting entries"},"description":{"type":"string","example":"Allows viewing accounting journal entries."}}}}}},"responses":{"201":{"description":"Permission created or updated."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/admin/rbac/permissions/{key}":{"get":{"summary":"Get one permission by key","description":"Returns `key`, `description`, timestamps. Path `key` is a single segment (e.g. `farmers.view`).","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"key","required":true,"schema":{"type":"string","example":"farmers.view"}}],"responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Permission key not found"}}},"patch":{"summary":"Update permission description","description":"Body must include at least one of `title` or `description` (stored on `description`). **Requires `rbac.manage`.**","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"If sent without description, used as the new description text."},"description":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Updated"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a custom permission key","description":"Removes the row and cascades join rows. **Built-in catalog keys** from the shipped default list **cannot** be deleted (403).\n**Requires `rbac.manage`.**\n","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Built-in permission"},"404":{"description":"Not found"}}}},"/admin/rbac/features":{"get":{"summary":"List features","tags":["RBAC"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"Feature list fetched successfully."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"summary":"Create or update feature","description":"Upserts `rbac_features` and replaces `rbac_feature_permissions`. **Requires `rbac.manage`.**","tags":["RBAC"],"security":[{"AdminAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key","title","requiredPermissionKeys"],"properties":{"key":{"type":"string","example":"accounting"},"title":{"type":"string","example":"Accounting"},"url":{"type":"string","nullable":true,"example":"/admin/accounting"},"icon":{"type":"string","nullable":true,"example":"calculator"},"parentKey":{"type":"string","nullable":true,"example":"dashboard"},"requiredPermissionKeys":{"type":"array","items":{"type":"string"},"example":["accounting.overview.view"]}}}}}},"responses":{"201":{"description":"Feature created or updated."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/admin/rbac/roles":{"get":{"summary":"List RBAC roles","description":"Returns all roles with counts of mapped permissions.","tags":["RBAC"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"Roles retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","example":"ADMIN"},"_count":{"type":"object","properties":{"rolePermissions":{"type":"integer","example":24}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"summary":"Create or upsert RBAC role","description":"Creates a new named role row if missing; does not attach permissions (use `.../roles/{role}/permissions`). **Requires `rbac.manage`.**","tags":["RBAC"],"security":[{"AdminAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"CUSTOM_OPS","description":"Unique role name (uppercase recommended)"}}}}}},"responses":{"201":{"description":"Role created or updated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"name":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/admin/rbac/roles/{role}":{"get":{"summary":"Get one RBAC role (group)","description":"Returns name, timestamps, and counts of mapped permissions and admin assignments.","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"role","required":true,"schema":{"type":"string","example":"FIELD_OPS"}}],"responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Role not found"}}},"delete":{"summary":"Delete a custom RBAC role","description":"Deletes the `rbac_roles` row (cascades role-permission links and `rbac_admin_roles` links).\nBuilt-ins `SUPER_ADMIN`, `ADMIN`, `INVESTOR`, `AUDITOR`, `SUPPORT` **cannot** be deleted (403).\n**Requires `rbac.manage`.**\n","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"role","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Built-in role"},"404":{"description":"Not found"}}}},"/admin/rbac/admins/{adminId}/role":{"post":{"summary":"Assign additional RBAC role to admin","description":"Links the admin (by login `adminId`) to an existing `rbac_roles` row. Duplicate links are ignored. **Requires `rbac.manage`.**","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"adminId","required":true,"schema":{"type":"integer","minimum":1},"description":"Admin login ID (`admins.adminId`), not internal DB id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["role"],"properties":{"role":{"type":"string","example":"SUPPORT","description":"Name of an existing RBAC role row"}}}}}},"responses":{"200":{"description":"Role assigned (or already linked)"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/admin/rbac/admins/{adminId}/roles":{"get":{"summary":"List RBAC groups attached to an admin","description":"Returns `{ name, roleId, assignedAt }[]` for `rbac_admin_roles` for this admin.\n`adminId` is the **login** id (`admins.adminId`), not the internal primary key.\n**Requires `rbac.manage`.**\n","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"adminId","required":true,"schema":{"type":"integer","example":123456}}],"responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Admin not found"}}}},"/admin/rbac/admins/{adminId}/roles/{role}":{"delete":{"summary":"Remove one RBAC group from an admin","description":"Deletes the `rbac_admin_roles` link. **Requires `rbac.manage`.** Returns 404 if the link did not exist.","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"adminId","required":true,"schema":{"type":"integer"}},{"in":"path","name":"role","required":true,"schema":{"type":"string","example":"FIELD_OPS"}}],"responses":{"200":{"description":"Removed"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Admin","role":null,"or assignment not found":null}}}},"/admin/rbac/admins/{adminId}/permissions":{"get":{"summary":"Get direct permissions for an admin","description":"Returns only keys granted via `rbac_admin_permissions` (not merged with legacy role or assigned RBAC roles).","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"adminId","required":true,"schema":{"type":"integer","minimum":1},"description":"Admin login ID (`admins.adminId`)"}],"responses":{"200":{"description":"List of permission keys","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"string"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Admin not found"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"summary":"Set direct permissions for an admin","description":"Replaces all `rbac_admin_permissions` rows for this admin with the given keys (must exist in `rbac_permissions`). **Requires `rbac.manage`.**","tags":["RBAC"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"adminId","required":true,"schema":{"type":"integer","minimum":1},"description":"Admin login ID (`admins.adminId`)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["permissionKeys"],"properties":{"permissionKeys":{"type":"array","items":{"type":"string"},"description":"Full replacement list (may be empty to clear direct grants)"}}}}}},"responses":{"200":{"description":"Permissions updated"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/tasks/refresh-mtn-momo-token":{"get":{"summary":"Refresh MTN MoMo access token","tags":["Tasks"],"security":[{"AdminAuth":[]}],"responses":{"200":{"description":"MTN MoMo token refreshed successfully","content":{"application/json":{"example":{"success":true,"message":"MTN MoMo token refreshed","data":null}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/ussd_event_callback":{"post":{"summary":"Receive USSD event callback","tags":["Callbacks"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{"sessionId":"sess_123","phoneNumber":"+2348012345678"}}}},"responses":{"200":{"description":"Callback processed successfully"},"500":{"description":"Failed to process callback"}}},"get":{"summary":"Receive USSD event callback (query mode)","tags":["Callbacks"],"security":[],"responses":{"200":{"description":"Callback processed successfully"}}}},"/ussd":{"post":{"summary":"Africa's Talking USSD callback","description":"Callback URL for Africa's Talking USSD webhooks. Configure this URL in your AT dashboard for your USSD shortcode.\nProcesses session requests (cumulative `text` input), registration, and menu flows. Response is plain text starting with CON or END.\nSee docs/USSD_AFRICAS_TALKING.md for request/response format.\n","tags":["USSD"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/USSDRequest"},"example":{"sessionId":"ATUid_12345","serviceCode":"*384*96#","phoneNumber":"+254712345678","text":"1","networkCode":"63902"}}}},"responses":{"200":{"description":"USSD session processed successfully","content":{"text/plain":{"schema":{"type":"string","description":"Plain text USSD payload beginning with CON or END","example":"CON Welcome to Yemert!\n1. Yemert Secure (Insurance)\n2. Yemert Market (Sell & Buy)\n3. Yemert Credits (Carbon Credits)\n4. Support & Help"}}}},"400":{"description":"Invalid USSD request data or unsupported region","content":{"text/plain":{"schema":{"type":"string","example":"Service not available in your region"}}}},"500":{"description":"Internal server error during USSD processing","content":{"text/plain":{"schema":{"type":"string","example":"An unknown error occurred"}}}}}}},"/validate-yemert-id":{"post":{"summary":"Validate a Yemert farmer ID","description":"Checks whether a given Yemert ID corresponds to an active farmer","tags":["Validation"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["yemert_id"],"properties":{"yemert_id":{"type":"string","description":"Yemert farmer ID, with or without the YM- prefix","example":"YM-1042"}}}}}},"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"status":{"type":"string","example":"active"}}}}}},"500":{"description":"Internal server error"}}}},"/support-ticket":{"post":{"summary":"Create a support ticket","description":"Submits a new support ticket from a farmer via the WhatsApp bot","tags":["Support Tickets"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["whatsappNumber","yemertId","subject","paymentProvider","issueDescription"],"properties":{"whatsappNumber":{"type":"string","description":"Farmer's WhatsApp number (raw from whatsapp-web.js, e.g. 2348012345678@c.us)","example":"2348012345678@c.us"},"yemertId":{"type":"string","description":"Farmer's numeric Yemert ID","example":"1042"},"subject":{"type":"string","example":"Payment not received"},"paymentProvider":{"type":"string","example":"MONNIFY"},"issueDescription":{"type":"string","example":"I made a payment 3 days ago and have not received my funds."}}}}}},"responses":{"201":{"description":"Support ticket created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"ticketId":{"type":"string","example":"cmmw580mr0001i5xq9cljm7mc"}}}}}}}},"400":{"description":"Missing or invalid fields"},"500":{"description":"Internal server error"}}},"get":{"summary":"List all support tickets","description":"Returns paginated support tickets ordered by creation date descending, with optional status filter","tags":["Support Tickets"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1},"description":"Page number"},{"in":"query","name":"limit","schema":{"type":"integer","default":20},"description":"Number of tickets per page"},{"in":"query","name":"status","schema":{"type":"string","enum":["OPEN","IN_PROGRESS","RESOLVED","CLOSED"]},"description":"Filter tickets by status"}],"responses":{"200":{"description":"Tickets retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"ticketId":{"type":"string","example":"cmmw580mr0001i5xq9cljm7mc"},"farmerPhoneNumber":{"type":"string","nullable":true,"example":"2348012345678"},"farmerFullName":{"type":"string","nullable":true,"example":"Emeka Okafor"},"subject":{"type":"string","example":"Payment not received"},"paymentMethod":{"type":"string","nullable":true,"example":"PAYSTACK"},"issueDescription":{"type":"string","example":"I made a payment 3 days ago and it has not been confirmed"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","RESOLVED","CLOSED"],"example":"OPEN"},"createdAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time","nullable":true}}}},"total":{"type":"integer","example":84},"page":{"type":"integer","example":1},"limit":{"type":"integer","example":20}}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/support-ticket/webhook":{"post":{"summary":"Receive a chat message for a ticket","description":"Webhook called by the WhatsApp bot to register an incoming farmer message, or by the admin dashboard to register an outgoing agent message. Admin messages are also forwarded to the farmer via the bot.\n","tags":["Support Tickets"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event","phoneNumber","message","ticketId","timestamp"],"properties":{"event":{"type":"string","enum":["farmer_message","admin_message"],"example":"farmer_message"},"phoneNumber":{"type":"string","example":"2348012345678"},"message":{"type":"string","example":"My payment has still not been processed."},"ticketId":{"type":"string","example":"cmmw580mr0001i5xq9cljm7mc"},"timestamp":{"type":"number","description":"Unix timestamp in milliseconds","example":1710768000000},"senderId":{"type":"string","description":"Required for admin_message — the admin's identifier","example":"admin_007"}}}}}},"responses":{"201":{"description":"Message registered successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"Message received"}}}}}},"400":{"description":"Missing fields or invalid event type"},"404":{"description":"Ticket not found"},"500":{"description":"Internal server error"}}}},"/support-ticket/{ticketId}/status":{"post":{"summary":"Update ticket status","description":"Updates the status of a support ticket. Triggers bot hold when set to IN_PROGRESS, and bot release when set to RESOLVED or CLOSED.\n","tags":["Support Tickets"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"ticketId","required":true,"schema":{"type":"string"},"description":"The ticket's cuid","example":"cmmw580mr0001i5xq9cljm7mc"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["OPEN","IN_PROGRESS","RESOLVED","CLOSED"],"example":"IN_PROGRESS"}}}}}},"responses":{"200":{"description":"Ticket status updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"description":"Missing or invalid fields"},"404":{"description":"Ticket not found"},"500":{"description":"Internal server error"}}}},"/support-ticket/{ticketId}":{"get":{"summary":"Get ticket details with chat history","description":"Returns full ticket details including farmer info and all chat messages ordered by time","tags":["Support Tickets"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"ticketId","required":true,"schema":{"type":"string"},"description":"The ticket's cuid","example":"cmmw580mr0001i5xq9cljm7mc"}],"responses":{"200":{"description":"Ticket retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"ticketId":{"type":"string"},"farmerPhoneNumber":{"type":"string","nullable":true},"farmerFullName":{"type":"string","nullable":true},"subject":{"type":"string"},"paymentMethod":{"type":"string","nullable":true},"issueDescription":{"type":"string"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","RESOLVED","CLOSED"]},"createdAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"chats":{"type":"array","items":{"type":"object","properties":{"senderType":{"type":"string","enum":["FARMER","ADMIN"]},"senderId":{"type":"string"},"message":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}}}},"404":{"description":"Ticket not found"},"500":{"description":"Internal server error"}}}},"/transaction-status/{transactionId}":{"get":{"summary":"Get transaction status","description":"Returns the current status of a payment transaction by its external ID","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"transactionId","required":true,"schema":{"type":"string"},"description":"External transaction ID from the payment provider","example":"TXN-20260318-00421"}],"responses":{"200":{"description":"Transaction status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"SUCCESS"}}}}}},"404":{"description":"Transaction not found"},"500":{"description":"Internal server error"}}}},"/location":{"post":{"summary":"Submit farm GPS location and start boundary detection","description":"Accepts a farmer's GPS coordinates from the WhatsApp bot (or any other trusted client) and enqueues a Satellite boundary-detection job. Same data path as USSD stage 540 — writes the seed to `farm:seed:<phone>` and queues `BoundaryDetection`.\n","tags":["Farm Onboarding"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["whatsappNumber","latitude","longitude"],"properties":{"whatsappNumber":{"type":"string","description":"Farmer's WhatsApp number (raw `2348012345678@c.us` or bare digits)","example":"2348012345678@c.us"},"yemertId":{"type":"string","description":"Farmer's numeric Yemert ID (with or without YM- prefix). Recommended.","example":"1042"},"latitude":{"type":"number","example":5.0569},"longitude":{"type":"number","example":7.9089},"accuracyMeters":{"type":"number","description":"Device-reported GPS accuracy. Anything > 100 m gets an accuracyWarning flag.","example":12},"declaredAreaHectares":{"type":"number","example":2.5},"cropType":{"type":"string","example":"maize"},"source":{"type":"string","enum":["whatsapp_gps","whatsapp_text","web_app"],"default":"whatsapp_gps"},"sessionId":{"type":"string","description":"Caller-supplied stable id for deduping retries (e.g. WhatsApp message id).","example":"wa_3EB0C1234567890ABCDEF"}}}}}},"responses":{"202":{"description":"Boundary detection enqueued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"jobId":{"type":"string","example":"boundary-2348012345678-wa_3EB0C..."},"phoneNumber":{"type":"string","example":"2348012345678"},"farmerId":{"type":"string","nullable":true},"coordsAccepted":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"}}},"accuracyWarning":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"description":"Validation error (missing fields, out-of-bounds coords, invalid Yemert ID)"},"409":{"description":"A boundary detection is already in progress for this farmer"},"500":{"description":"Internal server error"}}}},"/location/status":{"get":{"summary":"Get the latest farm onboarding / boundary-detection status","description":"Returns the most recent satellite-onboarding state for a farmer, keyed by their WhatsApp number. Used by the WhatsApp bot's `farm status` reply path. States: no_record | queued | running | succeeded | partial_success | failed.\n","tags":["Farm Onboarding"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"whatsappNumber","required":true,"schema":{"type":"string"},"description":"Farmer's WhatsApp number (raw `2348012345678@c.us` or bare digits)","example":"2348012345678@c.us"}],"responses":{"200":{"description":"Status retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["no_record","queued","running","succeeded","partial_success","failed"]},"phoneNumber":{"type":"string"},"satelliteJobId":{"type":"string","nullable":true},"farmId":{"type":"string","nullable":true},"registered":{"type":"boolean","nullable":true},"areaHectares":{"type":"number","nullable":true},"confidenceScore":{"type":"number","nullable":true},"suggestedAction":{"type":"string","nullable":true,"enum":["AUTO_APPROVE","FLAG_FOR_REVIEW","FALLBACK_NEEDED","UNSPECIFIED"]},"startedAt":{"type":"string","format":"date-time","nullable":true},"finishedAt":{"type":"string","format":"date-time","nullable":true},"errorMessage":{"type":"string","nullable":true},"message":{"type":"string"}}}}}},"400":{"description":"Missing whatsappNumber"},"500":{"description":"Internal server error"}}}},"/webhooks/woocommerce":{"post":{"summary":"Receive WooCommerce webhook event","tags":["Webhooks"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Webhook accepted","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/yemert/secure/insurance":{"get":{"summary":"Get insurance information","description":"Retrieves insurance-related information and recommendations for farmers. This endpoint provides personalized insurance options based on farmer profiles and agricultural data.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Insurance information retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer","example":1},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"farmSize":{"type":"number","example":5.5}}},"insuranceOptions":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","example":"Crop Insurance"},"coverage":{"type":"string","example":"Weather-related crop losses"},"premium":{"type":"string","example":"KES 15,000 annually"},"benefits":{"type":"array","items":{"type":"string"},"example":["Drought protection","Flood coverage","Pest damage"]}}}},"recommendations":{"type":"object","properties":{"recommended":{"type":"string","example":"Comprehensive Crop Insurance"},"reason":{"type":"string","example":"Based on your farm size and crop types, this provides optimal coverage"}}}}}}}]}}}},"400":{"description":"Invalid request data or missing farmer information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"summary":"Create a new insurance record","description":"Creates a new insurance record for a farmer. This endpoint allows administrators to create insurance policies for farmers.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["farmerId","cropName","acresPlots","plan"],"properties":{"farmerId":{"type":"integer","description":"The ID of the farmer","example":123},"cropName":{"type":"string","description":"Name of the crop to be insured","example":"Maize"},"acresPlots":{"type":"string","description":"Number of acres or plots to be covered","example":"5 acres"},"plan":{"type":"string","enum":["monthly","quarterly","biannual","annual"],"description":"Insurance plan duration","example":"annual"},"mobileMoney":{"type":"boolean","description":"Whether payment is via mobile money","example":false},"txId":{"type":"string","description":"Transaction ID for payment","example":"TXN123456789"}}}}}},"responses":{"201":{"description":"Insurance created successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"farmerId":{"type":"integer","example":123},"cropName":{"type":"string","example":"Maize"},"acresPlots":{"type":"string","example":"5 acres"},"plan":{"type":"string","example":"annual"},"mobileMoney":{"type":"boolean","example":false},"txId":{"type":"string","example":"TXN123456789"},"startDate":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"endDate":{"type":"string","format":"date-time","example":"2024-07-15T10:30:00Z"},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"updatedAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"}}}}}]}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/yemert/secure/insurance/{yemertId}":{"get":{"summary":"Get insurance records for a specific farmer","description":"Retrieves all insurance records for a specific farmer using their Yemert ID. This endpoint provides detailed insurance information including policy details, coverage, and farmer information.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The Yemert ID of the farmer (can be numeric or with YM- prefix)","example":"123456"}],"responses":{"200":{"description":"Insurance records retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer","example":123},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}},"insurance":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"farmerId":{"type":"integer","example":123},"plan":{"type":"string","example":"Basic Coverage"},"premium":{"type":"number","example":5000},"coverage":{"type":"number","example":100000},"startDate":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"endDate":{"type":"string","format":"date-time","example":"2024-07-15T10:30:00Z"},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"updatedAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"farmer":{"type":"object","properties":{"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}}}}},"totalInsuranceRecords":{"type":"integer","example":3}}}}}]}}}},"400":{"description":"Invalid Yemert ID format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Invalid Yemert ID format","error":"The provided Yemert ID is not in a valid format"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Farmer not found","error":"No farmer found with the provided Yemert ID"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"summary":"Update farmer's insurance information","description":"Updates insurance details for a specific farmer using their Yemert ID. This endpoint allows partial updates - you can update one or more fields without affecting others. If no specific insurance ID is provided, it will update the farmer's latest active insurance record. When the plan is updated, the start date and end date are automatically recalculated based on the new plan duration.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The farmer's Yemert ID (accepts both \"123456\" and \"YM-123456\" formats)","example":"YM-123456"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cropName":{"type":"string","description":"Name of the crop to be insured","example":"Maize"},"acresPlots":{"type":"string","description":"Number of acres or plots to be covered","example":"5 acres"},"plan":{"type":"string","enum":["monthly","quarterly","biannual","annual"],"description":"Insurance plan duration (when updated, start and end dates are automatically recalculated)","example":"annual"},"isActive":{"type":"boolean","description":"Whether the insurance is active","example":true},"insuranceId":{"type":"integer","description":"Specific insurance record ID to update (optional - if not provided, updates latest active insurance)","example":1}},"minProperties":1},"examples":{"updateCropAndPlan":{"summary":"Update crop name and plan","value":{"cropName":"Coffee","plan":"quarterly"}},"updateStatus":{"summary":"Deactivate insurance","value":{"isActive":false}},"updateSpecificInsurance":{"summary":"Update specific insurance record","value":{"insuranceId":1,"cropName":"Tea","acresPlots":"10 acres","plan":"annual","isActive":true}}}}}},"responses":{"200":{"description":"Insurance updated successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer","example":123},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}},"insurance":{"type":"object","properties":{"id":{"type":"integer","example":1},"farmerId":{"type":"integer","example":123},"cropName":{"type":"string","example":"Coffee"},"acresPlots":{"type":"string","example":"5 acres"},"plan":{"type":"string","example":"quarterly"},"mobileMoney":{"type":"boolean","example":false},"txId":{"type":"string","example":"TXN123456789"},"startDate":{"type":"string","example":"2023-07-15T10:30:00Z"},"endDate":{"type":"string","example":"2024-01-15T10:30:00Z"},"isActive":{"type":"boolean","example":true},"farmer":{"type":"object","properties":{"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}}}},"message":{"type":"string","example":"Insurance updated successfully"}}}}}]},"examples":{"successfulUpdate":{"summary":"Successful insurance update","value":{"success":true,"message":"Insurance updated successfully","data":{"farmer":{"id":123,"yemertId":"YMT123456","fullName":"John Kibet Doe","phoneNumber":"+254712345678"},"insurance":{"id":1,"farmerId":123,"cropName":"Coffee","acresPlots":"5 acres","plan":"quarterly","mobileMoney":false,"txId":"TXN123456789","startDate":"2023-07-15T10:30:00Z","endDate":"2024-01-15T10:30:00Z","isActive":true,"farmer":{"yemertId":"YMT123456","fullName":"John Kibet Doe","phoneNumber":"+254712345678"}},"message":"Insurance updated successfully"}}}}}}},"400":{"description":"Invalid request data or validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"validationError":{"summary":"Validation error","value":{"success":false,"message":"At least one field must be provided for update (cropName, acresPlots, plan, isActive, or insuranceId)"}},"invalidPlan":{"summary":"Invalid plan value","value":{"success":false,"message":"Invalid plan. Must be one of: monthly, quarterly, biannual, annual"}},"invalidYemertId":{"summary":"Invalid Yemert ID format","value":{"success":false,"message":"Invalid Yemert ID format"}}}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Unauthorized access"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Insufficient permissions to update insurance"}}}},"404":{"description":"Farmer or insurance not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"farmerNotFound":{"summary":"Farmer not found","value":{"success":false,"message":"Farmer not found"}},"insuranceNotFound":{"summary":"Insurance not found","value":{"success":false,"message":"No active insurance found for this farmer"}},"specificInsuranceNotFound":{"summary":"Specific insurance record not found","value":{"success":false,"message":"Insurance record not found for this farmer"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Internal server error occurred while updating insurance"}}}}}}},"/yemert/secure/insurance/all":{"delete":{"summary":"Delete all insurance records","description":"Delete all insurance records from the database. This is a destructive operation that cannot be undone.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"All insurance records deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"deletedCount":{"type":"integer","example":150}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/yemert/secure/insurance/farmer/{yemertId}":{"delete":{"summary":"Delete all insurance records for a specific farmer","description":"Delete all insurance records associated with a specific farmer by their Yemert ID.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The farmer's Yemert ID (can be numeric or with YM- prefix)","example":"YM-123456"}],"responses":{"200":{"description":"Farmer's insurance records deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer","example":123},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}},"deletedCount":{"type":"integer","example":3}}}}}]}}}},"400":{"description":"Invalid Yemert ID format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/yemert/secure/insurance/{insuranceId}":{"delete":{"summary":"Delete a specific insurance record","description":"Delete a specific insurance record by its ID. Optionally validate that the record belongs to a specific farmer.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"insuranceId","required":true,"schema":{"type":"string"},"description":"The insurance record ID","example":"123"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"yemertId":{"type":"string","description":"Optional farmer's Yemert ID for additional validation","example":"YM-123456"}}}}}},"responses":{"200":{"description":"Insurance record deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"insurance":{"type":"object","properties":{"id":{"type":"integer","example":123},"farmerId":{"type":"integer","example":1},"cropName":{"type":"string","example":"Maize"},"acresPlots":{"type":"string","example":"5 acres"},"plan":{"type":"string","example":"annual"},"startDate":{"type":"string","example":"2023-07-15T10:30:00Z"},"endDate":{"type":"string","example":"2024-07-15T10:30:00Z"},"isActive":{"type":"boolean","example":true},"farmer":{"type":"object","properties":{"id":{"type":"integer","example":1},"yemertId":{"type":"string","example":"YMT123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}}}}}}}}]}}}},"400":{"description":"Invalid insurance ID format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - insurance doesn't belong to farmer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Insurance record not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/yemert/secure/claims":{"get":{"summary":"Get insurance claims information","description":"Retrieves all insurance claims submitted by farmers. This endpoint provides details about claim types, status, and related farmer information.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Claims information retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"farmerId":{"type":"integer","example":123},"farmer":{"type":"object","properties":{"yemertId":{"type":"string","example":"YMT123456"}}},"type":{"type":"string","example":"Drought"},"whatsapp":{"type":"boolean","example":true},"number":{"type":"string","example":"+254712345678"},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"updatedAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"}}}}}}]}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"summary":"Create a new insurance claim","description":"Creates a new insurance claim for a farmer. This endpoint allows administrators to submit claims on behalf of farmers.","tags":["Insurance"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["farmerId","type"],"properties":{"farmerId":{"type":"integer","description":"The ID of the farmer submitting the claim","example":123},"type":{"type":"string","description":"The type of claim (e.g., Drought, Flood, Pest)","example":"Drought"},"whatsapp":{"type":"boolean","description":"Whether to send claim updates via WhatsApp","example":true},"number":{"type":"string","description":"Contact number for claim updates (if different from farmer's number)","example":"+254712345678"}}}}}},"responses":{"201":{"description":"Claim created successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"farmerId":{"type":"integer","example":123},"type":{"type":"string","example":"Drought"},"whatsapp":{"type":"boolean","example":true},"number":{"type":"string","example":"+254712345678"},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"},"updatedAt":{"type":"string","format":"date-time","example":"2023-07-15T10:30:00Z"}}}}}]}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/claims/{yemertId}":{"patch":{"summary":"Update farmer's claim","description":"Update a farmer's claim record. If claimId is provided, updates that specific claim; otherwise updates the latest active claim. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The Yemert ID of the farmer","example":"YM-12345"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Type of claim","example":"crop_damage"},"whatsapp":{"type":"string","description":"WhatsApp number for claim","example":"+254712345678"},"number":{"type":"string","description":"Claim reference number","example":"CLM-2024-001"},"isActive":{"type":"boolean","description":"Whether the claim is active","example":true},"claimId":{"type":"string","description":"Optional specific claim ID to update","example":"claim_123"}}},"examples":{"updateClaim":{"summary":"Update claim details","value":{"type":"crop_damage","whatsapp":"+254712345678","number":"CLM-2024-001","isActive":true}}}}}},"responses":{"200":{"description":"Claim updated successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer"},"yemertId":{"type":"integer"},"fullName":{"type":"string"},"phoneNumber":{"type":"string"}}},"claim":{"type":"object","properties":{"id":{"type":"integer"},"farmerId":{"type":"integer"},"type":{"type":"string"},"whatsapp":{"type":"string"},"number":{"type":"string"},"isActive":{"type":"boolean"}}}}}}}]}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer or claim not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Get all claims for a farmer","description":"Retrieve all claim records for a specific farmer by their Yemert ID. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The Yemert ID of the farmer","example":"YM-12345"}],"responses":{"200":{"description":"Farmer claims retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer"},"yemertId":{"type":"integer"},"fullName":{"type":"string"},"phoneNumber":{"type":"string"}}},"claims":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"farmerId":{"type":"integer"},"type":{"type":"string"},"whatsapp":{"type":"string"},"number":{"type":"string"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}}},"totalClaims":{"type":"integer","example":3}}}}}]}}}},"400":{"description":"Bad request - Invalid Yemert ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/claims/all":{"delete":{"summary":"Delete all claim records","description":"Delete all claim records from the system. This is a destructive operation that cannot be undone. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"All claim records deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"deletedCount":{"type":"integer","example":25}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/claims/farmer/{yemertId}":{"delete":{"summary":"Delete all claim records for a specific farmer","description":"Delete all claim records associated with a specific farmer by their Yemert ID. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The Yemert ID of the farmer","example":"YM-12345"}],"responses":{"200":{"description":"All claim records for the farmer deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer"},"yemertId":{"type":"integer"},"fullName":{"type":"string"},"phoneNumber":{"type":"string"}}},"deletedCount":{"type":"integer","example":3}}}}}]}}}},"400":{"description":"Bad request - Invalid Yemert ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/farmers/claims/{claimId}":{"delete":{"summary":"Delete a specific claim record","description":"Delete a specific claim record by its ID. Optionally validate that the claim belongs to a specific farmer. Requires SUPER_ADMIN or ADMIN role.","tags":["Farmers"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"claimId","required":true,"schema":{"type":"string"},"description":"The ID of the claim record to delete","example":"claim_123"}],"requestBody":{"description":"Optional farmer validation","content":{"application/json":{"schema":{"type":"object","properties":{"yemertId":{"type":"string","description":"Optional Yemert ID to validate that the claim belongs to this farmer","example":"YM-12345"}}},"examples":{"withValidation":{"summary":"Delete with farmer validation","value":{"yemertId":"YM-12345"}},"withoutValidation":{"summary":"Delete without farmer validation","value":{}}}}}},"responses":{"200":{"description":"Claim record deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"integer"},"farmerId":{"type":"integer"},"type":{"type":"string"},"whatsapp":{"type":"string"},"number":{"type":"string"},"isActive":{"type":"boolean"},"farmer":{"type":"object","properties":{"id":{"type":"integer"},"yemertId":{"type":"integer"},"fullName":{"type":"string"},"phoneNumber":{"type":"string"}}}}}}}}}]}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Claim record not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/yemert/secure/market":{"get":{"summary":"Get all market posts","description":"Retrieves all market posts from the YemertMarketSell system. This endpoint provides a comprehensive list of all market posts with farmer details.","tags":["Market"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Market posts retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/YemertMarketSell"}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}},"post":{"summary":"Create a new market post","description":"Creates a new market post for a farmer in the YemertMarketSell system. Requires SUPER_ADMIN or ADMIN role.","tags":["Market"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/YemertMarketSellInput"},"example":{"yemertId":"YM-123456","cropName":"Maize","pricePerKG":45.5,"postNow":true}}}},"responses":{"201":{"description":"Market post created successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"market":{"$ref":"#/components/schemas/YemertMarketSell"}}}}}]}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/yemert/secure/market/{farmerId}":{"patch":{"summary":"Update a market post","description":"Updates an existing market post for a specific farmer. Requires SUPER_ADMIN or ADMIN role.","tags":["Market"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"farmerId","required":true,"schema":{"type":"string"},"description":"The farmer's Yemert ID","example":"YM-123456"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/YemertMarketSellUpdateInput"},"example":{"marketId":"market_123","cropName":"Coffee","pricePerKG":120,"isActive":true}}}},"responses":{"200":{"description":"Market post updated successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"market":{"$ref":"#/components/schemas/YemertMarketSell"}}}}}]}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Market post or farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/yemert/secure/market/{yemertId}":{"get":{"summary":"Get market posts for a specific farmer","description":"Retrieves all market posts for a specific farmer using their Yemert ID.","tags":["Market"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The farmer's Yemert ID","example":"YM-123456"}],"responses":{"200":{"description":"Farmer market posts retrieved successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer","example":123},"yemertId":{"type":"string","example":"YM-123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}},"marketPosts":{"type":"array","items":{"$ref":"#/components/schemas/YemertMarketSell"}},"totalPosts":{"type":"integer","example":5}}}}}]}}}},"400":{"description":"Invalid Yemert ID format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/yemert/secure/market/all":{"delete":{"summary":"Delete all market posts","description":"Deletes all market posts from the system. This is a destructive operation that requires SUPER_ADMIN or ADMIN role. Use with extreme caution.","tags":["Market"],"security":[{"bearerAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"All market posts deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"deletedCount":{"type":"integer","example":25}}}}}]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/yemert/secure/market/farmer/{yemertId}":{"delete":{"summary":"Delete all market posts for a specific farmer","description":"Deletes all market posts for a specific farmer using their Yemert ID. Requires SUPER_ADMIN or ADMIN role.","tags":["Market"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"yemertId","required":true,"schema":{"type":"string"},"description":"The farmer's Yemert ID","example":"YM-123456"}],"responses":{"200":{"description":"Farmer market posts deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"farmer":{"type":"object","properties":{"id":{"type":"integer","example":123},"yemertId":{"type":"string","example":"YM-123456"},"fullName":{"type":"string","example":"John Kibet Doe"},"phoneNumber":{"type":"string","example":"+254712345678"}}},"deletedCount":{"type":"integer","example":3}}}}}]}}}},"400":{"description":"Invalid Yemert ID format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Farmer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/yemert/secure/market/{postId}":{"delete":{"summary":"Delete a specific market post","description":"Deletes a specific market post by its ID. Requires SUPER_ADMIN or ADMIN role.","tags":["Market"],"security":[{"AdminAuth":[]}],"parameters":[{"in":"path","name":"postId","required":true,"schema":{"type":"string"},"description":"The ID of the market post to delete","example":"market_123"}],"responses":{"200":{"description":"Market post deleted successfully","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"market":{"$ref":"#/components/schemas/YemertMarketSell"}}}}}]}}}},"400":{"description":"Invalid market post ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedError"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Market post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/":{"get":{"summary":"API root endpoint","description":"Returns the main API landing page with basic information about the Yemert API.","tags":["Health"],"responses":{"200":{"description":"API landing page","content":{"text/html":{"schema":{"type":"string","description":"HTML page with API information"}}}}}}},"/api":{"get":{"summary":"API information endpoint","description":"Returns the main API landing page with basic information about the Yemert API.","tags":["Health"],"responses":{"200":{"description":"API landing page","content":{"text/html":{"schema":{"type":"string","description":"HTML page with API information"}}}}}}},"/ping":{"get":{"summary":"Health check (root)","description":"Same payload as `/api/v1/ping`. Use the `/api/v1/ping` path when calling behind the same prefix as other API routes.","tags":["Health"],"security":[],"responses":{"200":{"description":"API is healthy and responsive","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingResponse"}}}}}}},"/api/v1/ping":{"get":{"summary":"Health check (under API prefix)","description":"Preferred health URL when `servers` in this spec use a base URL ending in `/api/v1`.","tags":["Health"],"security":[],"responses":{"200":{"description":"API is healthy and responsive","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingResponse"}}}}}}}}}