openapi: 3.0.3 info: title: Fashionistar API version: 1.0.0 description: |- Nigeria's Premier AI-Powered Fashion E-Commerce Platform API. **v1 (DRF/Sync):** Standard REST endpoints, WSGI-safe, Celery-backed. **v1 (Ninja/Async):** High-concurrency async endpoints, ASGI-native. **Authentication:** Bearer JWT (SimpleJWT). Get tokens via `/api/v1/auth/login/`. **Register first:** `POST /api/v1/auth/register/` → verify OTP → login. paths: /api/v1/admin_backend/auth/users/{user_id}/: get: operationId: v1_admin_backend_auth_users_retrieve parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body put: operationId: v1_admin_backend_auth_users_update parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/auth/users/{user_id}/force-password-reset/: post: operationId: v1_admin_backend_auth_users_force_password_reset_create parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/auth/users/{user_id}/reactivate/: post: operationId: v1_admin_backend_auth_users_reactivate_create parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/auth/users/{user_id}/suspend/: post: operationId: v1_admin_backend_auth_users_suspend_create parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/auth/users/{user_id}/update-role/: post: operationId: v1_admin_backend_auth_users_update_role_create parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/auth/users/{user_id}/verify/: post: operationId: v1_admin_backend_auth_users_verify_create parameters: - in: path name: user_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/blog/{post_id}/archive/: post: operationId: v1_admin_backend_catalog_blog_archive_create parameters: - in: path name: post_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/blog/{post_id}/update/: patch: operationId: v1_admin_backend_catalog_blog_update_partial_update parameters: - in: path name: post_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/blog/create/: post: operationId: v1_admin_backend_catalog_blog_create_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/brands/{brand_id}/archive/: post: operationId: v1_admin_backend_catalog_brands_archive_create parameters: - in: path name: brand_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/brands/{brand_id}/update/: patch: operationId: v1_admin_backend_catalog_brands_update_partial_update parameters: - in: path name: brand_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/brands/create/: post: operationId: v1_admin_backend_catalog_brands_create_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/categories/{category_id}/archive/: post: operationId: v1_admin_backend_catalog_categories_archive_create parameters: - in: path name: category_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/categories/{category_id}/update/: patch: operationId: v1_admin_backend_catalog_categories_update_partial_update parameters: - in: path name: category_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/categories/create/: post: operationId: v1_admin_backend_catalog_categories_create_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/collections/{collection_id}/archive/: post: operationId: v1_admin_backend_catalog_collections_archive_create parameters: - in: path name: collection_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/collections/{collection_id}/update/: patch: operationId: v1_admin_backend_catalog_collections_update_partial_update parameters: - in: path name: collection_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/catalog/collections/create/: post: operationId: v1_admin_backend_catalog_collections_create_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/chat/escalations/{escalation_id}/resolve/: post: operationId: v1_admin_backend_chat_escalations_resolve_create parameters: - in: path name: escalation_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/client/profiles/{profile_id}/: put: operationId: v1_admin_backend_client_profiles_update parameters: - in: path name: profile_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_admin_backend_client_profiles_partial_update parameters: - in: path name: profile_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/delivery/{order_id}/update/: post: operationId: v1_admin_backend_delivery_update_create description: Updates delivery status for legacy orders while apps/order migration is pending. summary: Update Delivery Status parameters: - in: path name: order_id schema: type: string required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/DeliveryStatusUpdateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/DeliveryStatusUpdateRequest' multipart/form-data: schema: $ref: '#/components/schemas/DeliveryStatusUpdateRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/DeliveryStatusUpdate' description: '' /api/v1/admin_backend/measurements/{profile_id}/verify/: post: operationId: v1_admin_backend_measurements_verify_create parameters: - in: path name: profile_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/notification/broadcast/: post: operationId: v1_admin_backend_notification_broadcast_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/order/{id}/cancel/: post: operationId: v1_admin_backend_order_cancel_create parameters: - in: path name: id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/order/{id}/release-escrow/: post: operationId: v1_admin_backend_order_release_escrow_create parameters: - in: path name: id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/order/{id}/transition/: post: operationId: v1_admin_backend_order_transition_create parameters: - in: path name: id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/payment/{payment_intent_id}/refund/: post: operationId: v1_admin_backend_payment_refund_create parameters: - in: path name: payment_intent_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/providers/cloudinary/update/: post: operationId: v1_admin_backend_providers_cloudinary_update_create description: POST /api/admin/providers/cloudinary/update/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/providers/email/update/: post: operationId: v1_admin_backend_providers_email_update_create description: POST /api/admin/providers/email/update/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/providers/kyc/update/: post: operationId: v1_admin_backend_providers_kyc_update_create description: POST /api/admin/providers/kyc/update/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/providers/sms/update/: post: operationId: v1_admin_backend_providers_sms_update_create description: POST /api/admin/providers/sms/update/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/settings/update/: post: operationId: v1_admin_backend_settings_update_create description: POST /api/admin/settings/update/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/support/{ticket_id}/assign/: post: operationId: v1_admin_backend_support_assign_create parameters: - in: path name: ticket_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/support/{ticket_id}/resolve/: post: operationId: v1_admin_backend_support_resolve_create parameters: - in: path name: ticket_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/vendor/{vendor_id}/approve/: post: operationId: v1_admin_backend_vendor_approve_create description: POST /api/admin/vendor/{vendor_id}/approve/ parameters: - in: path name: vendor_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/vendor/{vendor_id}/commission/: patch: operationId: v1_admin_backend_vendor_commission_partial_update description: PATCH /api/admin/vendor/{vendor_id}/commission/ parameters: - in: path name: vendor_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/vendor/{vendor_id}/featured/: patch: operationId: v1_admin_backend_vendor_featured_partial_update description: PATCH /api/admin/vendor/{vendor_id}/featured/ parameters: - in: path name: vendor_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/vendor/{vendor_id}/reactivate/: post: operationId: v1_admin_backend_vendor_reactivate_create description: POST /api/admin/vendor/{vendor_id}/reactivate/ parameters: - in: path name: vendor_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/vendor/{vendor_id}/reject/: post: operationId: v1_admin_backend_vendor_reject_create description: POST /api/admin/vendor/{vendor_id}/reject/ parameters: - in: path name: vendor_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/admin_backend/vendor/{vendor_id}/suspend/: post: operationId: v1_admin_backend_vendor_suspend_create description: POST /api/admin/vendor/{vendor_id}/suspend/ parameters: - in: path name: vendor_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/analytics/alert-rules/: get: operationId: v1_analytics_alert_rules_list description: ViewSet for managing alert rules (admin only). parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedAlertRuleList' description: '' post: operationId: v1_analytics_alert_rules_create description: ViewSet for managing alert rules (admin only). tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AlertRuleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AlertRuleRequest' multipart/form-data: schema: $ref: '#/components/schemas/AlertRuleRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/AlertRule' description: '' /api/v1/analytics/alert-rules/{id}/: get: operationId: v1_analytics_alert_rules_retrieve description: ViewSet for managing alert rules (admin only). parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Alert Rule. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AlertRule' description: '' put: operationId: v1_analytics_alert_rules_update description: ViewSet for managing alert rules (admin only). parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Alert Rule. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AlertRuleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AlertRuleRequest' multipart/form-data: schema: $ref: '#/components/schemas/AlertRuleRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AlertRule' description: '' patch: operationId: v1_analytics_alert_rules_partial_update description: ViewSet for managing alert rules (admin only). parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Alert Rule. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedAlertRuleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedAlertRuleRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedAlertRuleRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AlertRule' description: '' delete: operationId: v1_analytics_alert_rules_destroy description: ViewSet for managing alert rules (admin only). parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Alert Rule. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/analytics/alerts/: get: operationId: v1_analytics_alerts_list description: ViewSet for viewing fired alerts. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedAlertList' description: '' /api/v1/analytics/alerts/{id}/: get: operationId: v1_analytics_alerts_retrieve description: ViewSet for viewing fired alerts. parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Alert. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Alert' description: '' /api/v1/analytics/alerts/resolve_all/: post: operationId: v1_analytics_alerts_resolve_all_create description: Resolve all currently firing alerts. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AlertRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AlertRequest' multipart/form-data: schema: $ref: '#/components/schemas/AlertRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Alert' description: '' /api/v1/analytics/business-metrics/: get: operationId: v1_analytics_business_metrics_list description: ViewSet for viewing business aggregates (admin only). parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedBusinessMetricList' description: '' /api/v1/analytics/business-metrics/{id}/: get: operationId: v1_analytics_business_metrics_retrieve description: ViewSet for viewing business aggregates (admin only). parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Business Metric. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/BusinessMetric' description: '' /api/v1/analytics/calculate-business-metrics/: post: operationId: v1_analytics_calculate_business_metrics_create description: Calculate e-commerce aggregates. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/analytics/check-alerts/: post: operationId: v1_analytics_check_alerts_create description: Evaluate alert rules. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/analytics/metrics/: get: operationId: v1_analytics_metrics_list description: ViewSet for viewing system telemetry metrics. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedMetricList' description: '' /api/v1/analytics/metrics/{id}/: get: operationId: v1_analytics_metrics_retrieve description: ViewSet for viewing system telemetry metrics. parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Metric. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Metric' description: '' /api/v1/analytics/performance-analytics/: get: operationId: v1_analytics_performance_analytics_retrieve description: Retrieve API latency analytics. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/analytics/performance-metrics/: get: operationId: v1_analytics_performance_metrics_list description: ViewSet for checking API latencies. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedPerformanceMetricList' description: '' /api/v1/analytics/performance-metrics/{id}/: get: operationId: v1_analytics_performance_metrics_retrieve description: ViewSet for checking API latencies. parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this Performance Metric. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PerformanceMetric' description: '' /api/v1/analytics/record-metric/: post: operationId: v1_analytics_record_metric_create description: Record a new telemetry metric. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/analytics/system-overview/: get: operationId: v1_analytics_system_overview_retrieve description: Retrieve a system-wide overview of active indicators. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/analytics/user-activities/: get: operationId: v1_analytics_user_activities_list description: ViewSet for auditing user activities. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedUserActivityList' description: '' /api/v1/analytics/user-activities/{id}/: get: operationId: v1_analytics_user_activities_retrieve description: ViewSet for auditing user activities. parameters: - in: path name: id schema: type: integer description: A unique integer value identifying this User Activity. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/UserActivity' description: '' /api/v1/analytics/user-analytics/: get: operationId: v1_analytics_user_analytics_retrieve description: Retrieve user activity statistics. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/auth/google/: post: operationId: v1_auth_google_create description: |- Authenticate a user via Google OAuth2 ID Token. Flow: 1. Verify the provided 'id_token' with Google's public keys. 2. Identify or register the user based on email (is_new flag returned). 3. Provision defaults for new client users asynchronously. 4. Record UserSession and LoginEvent for audit tracking. 5. Issue JWT tokens and profile state for frontend routing. Status Codes: - 201 Created: New user registered. - 200 OK: Returning user logged in. - 401 Unauthorized: Invalid or expired token. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthGoogleAuthRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthGoogleAuthRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthGoogleAuthRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '201': content: application/json: schema: $ref: '#/components/schemas/AuthGoogleAuth' description: '' /api/v1/auth/login/: post: operationId: v1_auth_login_create description: |- POST /api/v1/auth/login/ Synchronous Login — email/phone + password → JWT tokens. Success Response 200: { "access": "", "refresh": "", "user_id": "...", "role": "..." } Cookie: fashionistar_rt (HttpOnly) → refresh token Status Codes: - 200 OK: Authentication successful. - 401 Unauthorized: Invalid credentials. - 403 Forbidden: Account unverified or deactivated. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthLoginRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthLoginRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthLoginRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/auth/login-events/: get: operationId: v1_auth_login_events_list description: Return recent login-event audit entries for the authenticated user. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedLoginEventList' description: '' /api/v1/auth/logout/: post: operationId: v1_auth_logout_create description: |- POST /api/v1/auth/logout/ Terminate the user session and blacklist the refresh token. Flow: 1. Accept current refresh token. 2. Blacklist the token in the database to prevent reuse. 3. Clear the HttpOnly session cookie. 4. Dispatch log_logout() audit event on commit (compliance). Status Codes: - 200 OK: Logout successful. - 400 Bad Request: Token already invalid. - 401 Unauthorized: Not authenticated. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthLogoutRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthLogoutRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthLogoutRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthLogout' description: '' /api/v1/auth/me/: get: operationId: v1_auth_me_retrieve description: |- GET /api/v1/auth/me/ Returns the authenticated user's full profile via MeSerializer. Used by useAuthHydration() to rehydrate Zustand on page refresh. Authorization: Bearer Error 401: Not authenticated / token expired. Response shape (stable contract with frontend): { "user_id": "uuid-string", "identifying_info": "email@example.com" | "+2348012345678", "member_id": "FASTAR000001" | null, "email": "email@example.com" | null, "phone": "+2348012345678" | null, "first_name": "John" | "", "last_name": "Doe" | "", "role": "client" | "vendor" | "staff" | ..., "auth_provider": "email" | "phone" | "google", "is_verified": true | false, "is_active": true | false, "is_staff": true | false, "avatar": "https://res.cloudinary.com/..." | null, "bio": "..." | "", "country": "Nigeria" | "", "state": "Lagos" | "", "city": "Ikeja" | "", "address": "..." | "", "date_joined": "2024-01-15T10:30:00+00:00" | null, "last_login": "2024-01-15T10:30:00+00:00" | null } tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthMe' description: '' /api/v1/auth/register/: post: operationId: v1_auth_register_create description: |- POST /api/v1/auth/register/ Synchronous user registration. Accepts email OR phone + password + role, creates the user inside an atomic transaction, generates a 6-digit OTP, and dispatches it via Email (if email provided) or SMS (if phone only). Mirrors legacy: ``userauths.views.RegisterViewCelery`` Request Body: email (str, optional) : User email address. phone (str, optional) : Phone in E.164 format (+234...). password (str, required) : Min 8 chars. password2 (str, required) : Must match password. role (str, required) : 'vendor' or 'client'. Success Response 201: { "message": "...", "user_id": "", "email": "...", "phone": null } Error Responses: 400 — Validation error 500 — Unexpected server error (transaction rolled back) tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthUserRegistrationRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthUserRegistrationRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthUserRegistrationRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '201': content: application/json: schema: $ref: '#/components/schemas/AuthUserRegistration' description: '' /api/v1/auth/resend-otp/: post: operationId: v1_auth_resend_otp_create description: |- POST /api/v1/auth/resend-otp/ Regenerate and resend a 6-digit OTP code. Flow: 1. Validate user existence by email or phone. 2. Regenerate a new secure OTP code. 3. Dispatch via the primary communication channel. Status Codes: - 200 OK: OTP resent successfully. - 400 Bad Request: Validation or throttled request. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthResendOTPRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthResendOTPRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthResendOTPRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/auth/sessions/: get: operationId: v1_auth_sessions_list description: List active sessions for the authenticated user. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedUserSessionList' description: '' /api/v1/auth/sessions/{session_id}/: delete: operationId: v1_auth_sessions_destroy description: Revoke a specific active session owned by the authenticated user. parameters: - in: path name: session_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/auth/sessions/revoke-others/: post: operationId: v1_auth_sessions_revoke_others_create description: Terminates every active session on the account except the current request's session. summary: Revoke all other sessions tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/auth/token/refresh/: post: operationId: v1_auth_token_refresh_create description: |- POST /api/v1/auth/token/refresh/ Refresh JWT access tokens using the stored refresh token. Flow: 1. Extract refresh token from request body (or HttpOnly cookie). 2. Verify refresh token validity via SimpleJWT. 3. Issue new short-lived access token. Status Codes: - 200 OK: Access token refreshed. - 401 Unauthorized: Invalid or expired refresh token. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthTokenRefreshRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthTokenRefreshRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthTokenRefreshRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthTokenRefresh' description: '' /api/v1/auth/verify-otp/: post: operationId: v1_auth_verify_otp_create description: |- POST /api/v1/auth/verify-otp/ Verify the 6-digit OTP code and activate the user account. Flow: 1. Accept OTP code (O(1) Redis lookup by hash). 2. Identify the user ID associated with the OTP. 3. Activate the user (is_verified=True, is_active=True). 4. Auto-issue JWT session tokens on successful verification. Security: One-time use. OTP is deleted from Redis immediately upon verification. Issues JWT tokens immediately on success so the user is logged in. Status Codes: - 200 OK: Verification successful, account activated. - 400 Bad Request: Invalid or expired OTP. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthOTPRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthOTPRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthOTPRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthOTP' description: '' /api/v1/catalog/blog/: post: operationId: v1_catalog_blog_create description: Create a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogBlogPostRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogBlogPostRequest' application/json: schema: $ref: '#/components/schemas/CatalogBlogPostRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogBlogPost' multipart/form-data: schema: $ref: '#/components/schemas/CatalogBlogPost' text/html: schema: $ref: '#/components/schemas/CatalogBlogPost' description: '' /api/v1/catalog/blog/{slug}/: put: operationId: v1_catalog_blog_update description: Replace a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogBlogPostRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogBlogPostRequest' application/json: schema: $ref: '#/components/schemas/CatalogBlogPostRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogBlogPost' multipart/form-data: schema: $ref: '#/components/schemas/CatalogBlogPost' text/html: schema: $ref: '#/components/schemas/CatalogBlogPost' description: '' patch: operationId: v1_catalog_blog_partial_update description: Partially update a catalog resource through the configured service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/PatchedCatalogBlogPostRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedCatalogBlogPostRequest' application/json: schema: $ref: '#/components/schemas/PatchedCatalogBlogPostRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogBlogPost' multipart/form-data: schema: $ref: '#/components/schemas/CatalogBlogPost' text/html: schema: $ref: '#/components/schemas/CatalogBlogPost' description: '' delete: operationId: v1_catalog_blog_destroy description: Archive a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/catalog/brands/: post: operationId: v1_catalog_brands_create description: Create a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogBrandRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogBrandRequest' application/json: schema: $ref: '#/components/schemas/CatalogBrandRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogBrand' multipart/form-data: schema: $ref: '#/components/schemas/CatalogBrand' text/html: schema: $ref: '#/components/schemas/CatalogBrand' description: '' /api/v1/catalog/brands/{slug}/: put: operationId: v1_catalog_brands_update description: Replace a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogBrandRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogBrandRequest' application/json: schema: $ref: '#/components/schemas/CatalogBrandRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogBrand' multipart/form-data: schema: $ref: '#/components/schemas/CatalogBrand' text/html: schema: $ref: '#/components/schemas/CatalogBrand' description: '' patch: operationId: v1_catalog_brands_partial_update description: Partially update a catalog resource through the configured service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/PatchedCatalogBrandRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedCatalogBrandRequest' application/json: schema: $ref: '#/components/schemas/PatchedCatalogBrandRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogBrand' multipart/form-data: schema: $ref: '#/components/schemas/CatalogBrand' text/html: schema: $ref: '#/components/schemas/CatalogBrand' description: '' delete: operationId: v1_catalog_brands_destroy description: Archive a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/catalog/categories/: post: operationId: v1_catalog_categories_create description: Create a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogCategoryRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogCategoryRequest' application/json: schema: $ref: '#/components/schemas/CatalogCategoryRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogCategory' multipart/form-data: schema: $ref: '#/components/schemas/CatalogCategory' text/html: schema: $ref: '#/components/schemas/CatalogCategory' description: '' /api/v1/catalog/categories/{slug}/: put: operationId: v1_catalog_categories_update description: Replace a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogCategoryRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogCategoryRequest' application/json: schema: $ref: '#/components/schemas/CatalogCategoryRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogCategory' multipart/form-data: schema: $ref: '#/components/schemas/CatalogCategory' text/html: schema: $ref: '#/components/schemas/CatalogCategory' description: '' patch: operationId: v1_catalog_categories_partial_update description: Partially update a catalog resource through the configured service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/PatchedCatalogCategoryRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedCatalogCategoryRequest' application/json: schema: $ref: '#/components/schemas/PatchedCatalogCategoryRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogCategory' multipart/form-data: schema: $ref: '#/components/schemas/CatalogCategory' text/html: schema: $ref: '#/components/schemas/CatalogCategory' description: '' delete: operationId: v1_catalog_categories_destroy description: Archive a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/catalog/collections/: post: operationId: v1_catalog_collections_create description: Create a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogCollectionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogCollectionRequest' application/json: schema: $ref: '#/components/schemas/CatalogCollectionRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogCollection' multipart/form-data: schema: $ref: '#/components/schemas/CatalogCollection' text/html: schema: $ref: '#/components/schemas/CatalogCollection' description: '' /api/v1/catalog/collections/{slug}/: put: operationId: v1_catalog_collections_update description: Replace a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/CatalogCollectionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CatalogCollectionRequest' application/json: schema: $ref: '#/components/schemas/CatalogCollectionRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogCollection' multipart/form-data: schema: $ref: '#/components/schemas/CatalogCollection' text/html: schema: $ref: '#/components/schemas/CatalogCollection' description: '' patch: operationId: v1_catalog_collections_partial_update description: Partially update a catalog resource through the configured service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 requestBody: content: multipart/form-data: schema: $ref: '#/components/schemas/PatchedCatalogCollectionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedCatalogCollectionRequest' application/json: schema: $ref: '#/components/schemas/PatchedCatalogCollectionRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CatalogCollection' multipart/form-data: schema: $ref: '#/components/schemas/CatalogCollection' text/html: schema: $ref: '#/components/schemas/CatalogCollection' description: '' delete: operationId: v1_catalog_collections_destroy description: Archive a catalog resource through the configured domain service. parameters: - in: query name: format schema: type: string enum: - html - json - multipart - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/chat/conversations/: get: operationId: v1_chat_conversations_retrieve description: |- GET /api/v1/chat/conversations/ Returns all conversations for the authenticated user. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/conversations/{conversation_id}/: get: operationId: v1_chat_conversations_retrieve_2 description: |- GET /api/v1/chat/conversations// GET messages for a conversation (paginated, newest-first). Also marks all messages as read for the requesting participant. parameters: - in: path name: conversation_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/conversations/{conversation_id}/flag/: post: operationId: v1_chat_conversations_flag_create description: |- POST /api/v1/chat/conversations//flag/ File a moderation report for a conversation. parameters: - in: path name: conversation_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/conversations/{conversation_id}/messages/: post: operationId: v1_chat_conversations_messages_create description: |- POST /api/v1/chat/conversations//messages/ Send a text message in a conversation. parameters: - in: path name: conversation_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/conversations/{conversation_id}/offers/: post: operationId: v1_chat_conversations_offers_create description: |- POST /api/v1/chat/conversations//offers/ Vendor creates a price offer for the buyer. parameters: - in: path name: conversation_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/conversations/{conversation_id}/read/: post: operationId: v1_chat_conversations_read_create description: |- POST /api/v1/chat/conversations//read/ Mark all messages in a conversation as read for the requesting participant. parameters: - in: path name: conversation_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/conversations/start/: post: operationId: v1_chat_conversations_start_create description: |- POST /api/v1/chat/conversations/start/ Buyer starts a new conversation with a vendor. Idempotent — returns existing active thread if one exists. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chat/offers/{offer_id}/{action}/: post: operationId: v1_chat_offers_create description: |- POST /api/v1/chat/offers//accept/ POST /api/v1/chat/offers//decline/ Buyer accepts or declines an offer. parameters: - in: path name: action schema: type: string required: true - in: path name: offer_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chatbot/api/client/end-session/: post: operationId: v1_chatbot_api_client_end_session_create description: |- پایان جلسهٔ فعال چت‌بات برای کاربر جاری. این اکشن، جلسهٔ فعال چت‌بات مرتبط با کاربر احراز هویت‌شده را از طریق سرویس چت‌بات (get_chatbot_service) خاتمه می‌دهد. فراخوانی سرویس معمولاً شامل عملیات‌های زیر است: - علامت‌گذاری جلسه به‌عنوان "پایان‌یافته" در پایگاه‌داده. - ذخیره/همگام‌سازی وضعیت نهایی جلسه و گفتگوها. - انجام پاک‌سازی زمینه‌های مرتبط در حافظه یا صف‌های پردازشی که ممکن است برای نگهداری کانتکست مکالمه استفاده شده باشند. - در صورت وجود وظایف پس‌زمینه (مثل انتها دادن به پردازش‌های هوش‌مصنوعی یا آزادسازی منابع مدل)، راه‌اندازی یا برنامه‌ریزی آن‌ها. پاسخ: - موفقیت: JSON با کلید `message` و مقدار متنی تایید (HTTP 200). - خطا: در صورت بروز استثنا، JSON با کلید `error` و پیام خطا بازگردانده شده و کد وضعیت HTTP 500 برگردانده می‌شود. توجه: پیاده‌سازی دقیق رفتارهای دخیل در سرویس چت‌بات (ذخیره‌سازی، همگام‌سازی مدل/وظایف پس‌زمینه و ...) در لایهٔ سرویس قرار دارد و این اکشن صرفاً درگاه فراخوانی و مدیریت پاسخ/خطا برای آن سرویس است. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/chatbot/api/client/request-consultation/: post: operationId: v1_chatbot_api_client_request_consultation_create description: Initiate request for custom tailoring consultation summary: Request bespoke consultation tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/BespokeConsultationRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/BespokeConsultationRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/BespokeConsultationRequestRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/chatbot/api/client/send-message/: post: operationId: v1_chatbot_api_client_send_message_create description: Send client message and get chatbot response summary: Send message to chatbot tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/SendMessageRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/SendMessageRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/SendMessageRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/SendMessageResponse' description: '' /api/v1/chatbot/api/client/start-session/: post: operationId: v1_chatbot_api_client_start_session_create description: Initialize or get active chatbot session for client summary: Start client chatbot session tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/StartSessionResponse' description: '' /api/v1/chatbot/api/client/style-assessment/: post: operationId: v1_chatbot_api_client_style_assessment_create description: Initialize style assessment questionnaire for the client summary: Start style assessment tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/chatbot/api/client/submit-assessment/: post: operationId: v1_chatbot_api_client_submit_assessment_create description: Submit style preferences and get outfits recommendations summary: Submit style assessment responses tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/StyleAssessmentRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/StyleAssessmentRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/StyleAssessmentRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/chatbot/api/conversations/: get: operationId: v1_chatbot_api_conversations_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedConversationList' description: '' post: operationId: v1_chatbot_api_conversations_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ConversationRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ConversationRequest' multipart/form-data: schema: $ref: '#/components/schemas/ConversationRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/Conversation' description: '' /api/v1/chatbot/api/conversations/{id}/: get: operationId: v1_chatbot_api_conversations_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Conversation. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Conversation' description: '' put: operationId: v1_chatbot_api_conversations_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Conversation. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ConversationRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ConversationRequest' multipart/form-data: schema: $ref: '#/components/schemas/ConversationRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Conversation' description: '' patch: operationId: v1_chatbot_api_conversations_partial_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Conversation. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedConversationRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedConversationRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedConversationRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Conversation' description: '' delete: operationId: v1_chatbot_api_conversations_destroy parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Conversation. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/chatbot/api/conversations/{id}/history/: get: operationId: v1_chatbot_api_conversations_history_retrieve description: |- بازگرداندن تاریخچه یک مکالمه مشخص. این اکشن تاریخچه پیام‌های یک گفت‌وگو را برمی‌گرداند: ابتدا شیء conversation با self.get_object() واکشی می‌شود، سپس پیام‌ها بر اساس `created_at` نزولی مرتب و تا تعداد `limit` برش داده می‌شوند. پاسخ JSON شامل نسخه‌ی سریالایز شده‌ی گفت‌وگو، لیست پیام‌ها (جدیدترین ابتدا)، تعداد کل پیام‌ها و یک فِلَگ `has_more` برای نشان دادن وجود پیام‌های بیش‌تر است. پارامترهای کوئری: limit (int, اختیاری): حداکثر تعداد پیام‌هایی که برگردانده می‌شوند. مقدار پیش‌فرض 50 است. مقدار بازگشتی: rest_framework.response.Response: بدنه‌ی JSON با کلیدهای: - conversation: داده‌های سریالایز شدهٔ گفت‌وگو (ConversationListSerializer). - messages: فهرست پیام‌های سریالایز شده (MessageSerializer) مرتب‌شده به صورت نزولی بر اساس `created_at`. - total_messages: تعداد کل پیام‌های موجود در آن گفت‌وگو. - has_more: بولین که نشان می‌دهد آیا پیام‌های بیشتری نسبت به `limit` وجود دارد یا خیر. parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Conversation. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Conversation' description: '' /api/v1/chatbot/api/messages/: get: operationId: v1_chatbot_api_messages_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedMessageList' description: '' post: operationId: v1_chatbot_api_messages_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/MessageRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/MessageRequest' multipart/form-data: schema: $ref: '#/components/schemas/MessageRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/Message' description: '' /api/v1/chatbot/api/messages/{id}/: get: operationId: v1_chatbot_api_messages_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Message. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Message' description: '' put: operationId: v1_chatbot_api_messages_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Message. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/MessageRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/MessageRequest' multipart/form-data: schema: $ref: '#/components/schemas/MessageRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Message' description: '' patch: operationId: v1_chatbot_api_messages_partial_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Message. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedMessageRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedMessageRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedMessageRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Message' description: '' delete: operationId: v1_chatbot_api_messages_destroy parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Message. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/chatbot/api/sessions/: get: operationId: v1_chatbot_api_sessions_list description: مدیریت جلسات چت‌بات parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedChatbotSessionList' description: '' post: operationId: v1_chatbot_api_sessions_create description: مدیریت جلسات چت‌بات tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ChatbotSessionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ChatbotSessionRequest' multipart/form-data: schema: $ref: '#/components/schemas/ChatbotSessionRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/ChatbotSession' description: '' /api/v1/chatbot/api/sessions/{id}/: get: operationId: v1_chatbot_api_sessions_retrieve description: مدیریت جلسات چت‌بات parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Chatbot Session. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ChatbotSession' description: '' put: operationId: v1_chatbot_api_sessions_update description: مدیریت جلسات چت‌بات parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Chatbot Session. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ChatbotSessionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ChatbotSessionRequest' multipart/form-data: schema: $ref: '#/components/schemas/ChatbotSessionRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ChatbotSession' description: '' patch: operationId: v1_chatbot_api_sessions_partial_update description: مدیریت جلسات چت‌بات parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Chatbot Session. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedChatbotSessionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedChatbotSessionRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedChatbotSessionRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ChatbotSession' description: '' delete: operationId: v1_chatbot_api_sessions_destroy description: مدیریت جلسات چت‌بات parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Chatbot Session. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/chatbot/api/vendor/catalog-support/: post: operationId: v1_chatbot_api_vendor_catalog_support_create description: Get recommendation and categorization for new products summary: Request product catalog support tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/SizeRecommendationRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/SizeRecommendationRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/SizeRecommendationRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/chatbot/api/vendor/product-info/: post: operationId: v1_chatbot_api_vendor_product_info_create description: Get fabric, pricing and packaging details summary: Request product specifications tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ProductInquiryRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ProductInquiryRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/ProductInquiryRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/chatbot/api/vendor/search-references/: get: operationId: v1_chatbot_api_vendor_search_references_retrieve description: Search design ideas, trends and fabric references summary: Search fashion references parameters: - in: query name: query schema: type: string description: Search Query - in: query name: specialty schema: type: string description: Specialty Niche tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/chatbot/api/vendor/send-message/: post: operationId: v1_chatbot_api_vendor_send_message_create description: Send vendor message and get chatbot response summary: Send message to chatbot tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/SendMessageRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/SendMessageRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/SendMessageRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/SendMessageResponse' description: '' /api/v1/chatbot/api/vendor/start-session/: post: operationId: v1_chatbot_api_vendor_start_session_create description: Initialize or get active chatbot session for vendor summary: Start vendor chatbot session tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/StartSessionResponse' description: '' /api/v1/chatbot/api/vendor/tailoring-guideline/: get: operationId: v1_chatbot_api_vendor_tailoring_guideline_retrieve description: Fetch custom tailoring assembly and pattern details summary: Get tailoring guideline parameters: - in: query name: condition schema: type: string description: Garment Type - in: query name: severity schema: type: string default: moderate description: Complexity tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/client/addresses/: get: operationId: v1_client_addresses_list description: |- GET /api/v1/client/addresses/ — list saved addresses POST /api/v1/client/addresses/ — add new address parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedClientAddressList' description: '' post: operationId: v1_client_addresses_create description: |- GET /api/v1/client/addresses/ — list saved addresses POST /api/v1/client/addresses/ — add new address tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AddressCreateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AddressCreateRequest' multipart/form-data: schema: $ref: '#/components/schemas/AddressCreateRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/AddressCreate' description: '' /api/v1/client/addresses/{address_id}/: delete: operationId: v1_client_addresses_destroy description: DELETE /api/v1/client/addresses/{id}/ — soft-delete address parameters: - in: path name: address_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/client/addresses/{address_id}/set-default/: post: operationId: v1_client_addresses_set_default_create description: |- POST /api/v1/client/addresses/{id}/set-default/ Set a specific address as the default shipping address. parameters: - in: path name: address_id schema: type: string format: uuid required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ClientAddressRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ClientAddressRequest' multipart/form-data: schema: $ref: '#/components/schemas/ClientAddressRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ClientAddress' description: '' /api/v1/client/orders/: get: operationId: v1_client_orders_list description: |- GET /api/v1/client/orders/ Return all paid orders for the authenticated client. Prefetches orderitems to avoid N+1 on order detail pages. Returns a list of all successful orders placed by the client. Validation Logic: - Filter: Only returns orders where payment_status is 'paid'. - Ordering: Date-descending (most recent first). Security: - Requires IsAuthenticated + IsClient. Status Codes: 200 OK: List of orders returned. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedClientCartOrderList' description: '' /api/v1/client/orders/{oid}/: get: operationId: v1_client_orders_retrieve description: |- GET /api/v1/client/orders// Return detail for a single paid order scoped to this client. Uses oid (order identifier) — not PK — for public safety. Status Codes: 200 OK: Order details returned. 404 Not Found: Order missing or unauthorized. parameters: - in: path name: oid schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ClientCartOrder' description: '' /api/v1/client/profile/: get: operationId: v1_client_profile_retrieve description: |- GET /api/v1/client/profile/ — retrieve profile PATCH /api/v1/client/profile/ — update profile tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ClientProfileOutput' description: '' put: operationId: v1_client_profile_update description: |- GET /api/v1/client/profile/ — retrieve profile PATCH /api/v1/client/profile/ — update profile tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ClientProfileUpdateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ClientProfileUpdateRequest' multipart/form-data: schema: $ref: '#/components/schemas/ClientProfileUpdateRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ClientProfileUpdate' description: '' patch: operationId: v1_client_profile_partial_update description: |- GET /api/v1/client/profile/ — retrieve profile PATCH /api/v1/client/profile/ — update profile tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedClientProfileUpdateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedClientProfileUpdateRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedClientProfileUpdateRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ClientProfileUpdate' description: '' /api/v1/client/reviews/create/: post: operationId: v1_client_reviews_create_create description: |- POST /api/v1/client/reviews/create/ Submits a new rating and review for a product. Validation Logic: - Payload: Validates product_id presence and rating (1–5 scale). - Duplication: Enforced at serializer / model level. Security: - Requires IsAuthenticated + IsClient. Status Codes: 201 Created: Review successfully recorded. 400 Bad Request: Missing product_id or invalid rating. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/ClientReviewRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ClientReviewRequest' multipart/form-data: schema: $ref: '#/components/schemas/ClientReviewRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/ClientReview' description: '' /api/v1/client/wallet/balance/: get: operationId: v1_client_wallet_balance_retrieve description: |- GET /api/v1/client/wallet/balance/ Retrieves the authenticated client's current Fashionistar wallet balance. Auto-provisions a wallet via WalletProvisioningService if none exists. Security: IsAuthenticated + IsClient Status: 200 OK — balance data returned. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Wallet' description: '' /api/v1/client/wallet/topup/initiate/: post: operationId: v1_client_wallet_topup_initiate_create description: |- POST /api/v1/client/wallet/topup/initiate/ Initiates a Paystack wallet top-up payment intent. Returns a payment_url the client redirects to for card payment. Body: { "amount": 5000, // NGN amount (number) "payment_method": "card", // card | bank_transfer "callback_url": "https://.../verify" // optional redirect URL } Response (200): { "status": "pending", "payment_url": "https://paystack.com/...", "reference": "..." } tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/client/wallet/transfer/: post: operationId: v1_client_wallet_transfer_create description: |- POST /api/v1/client/wallet/transfer/ Executes an atomic wallet-to-wallet transfer to another Fashionistar user. Body: { "receiver_id": "", "amount": "500.00", "transaction_password": "1234" } Security: - Verifies the 4-digit Transaction PIN via WalletBalanceService.transfer(). - KYC gate enforced in the service (sender must be KYC-approved). - Idempotency-Key header is forwarded to prevent duplicate transactions. Status: 200 OK: Transfer completed. 400 Bad Request: Insufficient funds, invalid PIN, or validation error. 404 Not Found: Receiver not found. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WalletTransferRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WalletTransferRequest' multipart/form-data: schema: $ref: '#/components/schemas/WalletTransferRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WalletTransfer' description: '' /api/v1/client/wallet/withdraw/: post: operationId: v1_client_wallet_withdraw_create description: |- POST /api/v1/client/wallet/withdraw/ Create a KYC-gated, PIN-protected bank withdrawal request. This is the correct financial-exit endpoint for the WithdrawalForm UI. It uses WalletWithdrawalService.request_withdrawal() which: - Asserts the user has an approved KYC submission. - Verifies the 4-digit transaction PIN. - Moves funds from available_balance → pending_balance (atomic DB txn). - Creates an immutable PAYOUT ledger entry (CBN compliance). - Writes a compliance audit trail (CBN/GDPR permanent retention). - Supports idempotency via Idempotency-Key header. Body: { "amount": "5000.00", // min ₦1,000 enforced in Zod (frontend) "pin": "1234", // 4-digit wallet PIN "bank_code": "057", // Nigerian bank code (e.g. Zenith = "057") "account_number": "0123456789", // 10-digit NUBAN "account_name": "Jane Doe" // beneficiary name } Response (200): { "transaction_id": "", "reference": "wallet-withdrawal:...", "status": "processing", "amount": "5000.00", "available_balance": "15000.00", "pending_balance": "5000.00" } Error Codes: 400 — Invalid PIN / insufficient balance / validation errors. 403 — KYC not approved (assert_kyc_approved gate). 422 — Idempotent duplicate detected (returns existing transaction). Security: - IsAuthenticated + IsClient - KYC approved (enforced by WalletWithdrawalService) - PIN verified (bcrypt check via wallet.verify_pin()) - Idempotency-Key prevents double-submission on network retry CBN Compliance: - Funds remain in pending_balance until the payment provider confirms the bank transfer (async execution by Celery payout task). - The immutable PAYOUT ledger row is created before this response returns. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/client/wishlist/: get: operationId: v1_client_wishlist_retrieve tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ClientWishlist' description: '' /api/v1/client/wishlist/toggle/: post: operationId: v1_client_wishlist_toggle_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WishlistToggleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WishlistToggleRequest' multipart/form-data: schema: $ref: '#/components/schemas/WishlistToggleRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WishlistToggle' description: '' /api/v1/common/reference/banks/: get: operationId: v1_common_reference_banks_list description: Returns banks for the specified country. Nigeria defaults to Paystack-backed bank metadata. summary: List banks parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedReferenceBankList' description: '' /api/v1/common/reference/countries/: get: operationId: v1_common_reference_countries_list description: Returns static supported country metadata for web, admin, and mobile clients. summary: List supported countries parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedReferenceCountryList' description: '' /api/v1/common/reference/countries/{country_code}/cities/: get: operationId: v1_common_reference_countries_cities_list description: Returns cities for the selected country, optionally filtered by state and LGA. summary: List cities for a country parameters: - in: path name: country_code schema: type: string required: true - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedReferenceCityList' description: '' /api/v1/common/reference/countries/{country_code}/states/: get: operationId: v1_common_reference_countries_states_list description: Returns states configured for the selected country. summary: List states for a country parameters: - in: path name: country_code schema: type: string required: true - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedReferenceStateList' description: '' /api/v1/common/reference/countries/{country_code}/states/{state_code}/lgas/: get: operationId: v1_common_reference_countries_states_lgas_list description: Returns local government areas for the selected country and state. summary: List LGAs for a state parameters: - in: path name: country_code schema: type: string required: true - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer - in: path name: state_code schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedReferenceLgaList' description: '' /api/v1/common/reference/countries/{country_code}/states/{state_code}/lgas/{lga_code}/cities/: get: operationId: v1_common_reference_countries_states_lgas_cities_list description: Returns cities for the selected country, state, and LGA. summary: List cities in an LGA parameters: - in: path name: country_code schema: type: string required: true - in: path name: lga_code schema: type: string required: true - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer - in: path name: state_code schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedReferenceCityList' description: '' /api/v1/integrations/ai/generate/: post: operationId: v1_integrations_ai_generate_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/integrations/credentials/: get: operationId: v1_integrations_credentials_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedIntegrationCredentialList' description: '' post: operationId: v1_integrations_credentials_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' multipart/form-data: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/IntegrationCredential' description: '' /api/v1/integrations/credentials/{id}/: get: operationId: v1_integrations_credentials_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Integration Credential. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationCredential' description: '' put: operationId: v1_integrations_credentials_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Integration Credential. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' multipart/form-data: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationCredential' description: '' patch: operationId: v1_integrations_credentials_partial_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Integration Credential. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedIntegrationCredentialRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedIntegrationCredentialRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedIntegrationCredentialRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationCredential' description: '' delete: operationId: v1_integrations_credentials_destroy parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Integration Credential. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/integrations/credentials/{id}/rotate/: post: operationId: v1_integrations_credentials_rotate_create parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Integration Credential. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' multipart/form-data: schema: $ref: '#/components/schemas/IntegrationCredentialRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationCredential' description: '' /api/v1/integrations/logs/: get: operationId: v1_integrations_logs_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedIntegrationLogList' description: '' /api/v1/integrations/logs/{id}/: get: operationId: v1_integrations_logs_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Integration Log. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationLog' description: '' /api/v1/integrations/providers/: get: operationId: v1_integrations_providers_list description: ViewSet for managing external Integration Providers. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedIntegrationProviderList' description: '' post: operationId: v1_integrations_providers_create description: ViewSet for managing external Integration Providers. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/IntegrationProviderRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/IntegrationProviderRequest' multipart/form-data: schema: $ref: '#/components/schemas/IntegrationProviderRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/IntegrationProvider' description: '' /api/v1/integrations/providers/{slug}/: get: operationId: v1_integrations_providers_retrieve description: ViewSet for managing external Integration Providers. parameters: - in: path name: slug schema: type: string title: Unique Slug required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationProvider' description: '' put: operationId: v1_integrations_providers_update description: ViewSet for managing external Integration Providers. parameters: - in: path name: slug schema: type: string title: Unique Slug required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/IntegrationProviderRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/IntegrationProviderRequest' multipart/form-data: schema: $ref: '#/components/schemas/IntegrationProviderRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationProvider' description: '' patch: operationId: v1_integrations_providers_partial_update description: ViewSet for managing external Integration Providers. parameters: - in: path name: slug schema: type: string title: Unique Slug required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedIntegrationProviderRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedIntegrationProviderRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedIntegrationProviderRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationProvider' description: '' delete: operationId: v1_integrations_providers_destroy description: ViewSet for managing external Integration Providers. parameters: - in: path name: slug schema: type: string title: Unique Slug required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/integrations/providers/{slug}/health_check/: get: operationId: v1_integrations_providers_health_check_retrieve description: ViewSet for managing external Integration Providers. parameters: - in: path name: slug schema: type: string title: Unique Slug required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationProvider' description: '' /api/v1/integrations/providers/{slug}/statistics/: get: operationId: v1_integrations_providers_statistics_retrieve description: ViewSet for managing external Integration Providers. parameters: - in: path name: slug schema: type: string title: Unique Slug required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/IntegrationProvider' description: '' /api/v1/integrations/rate-limits/: get: operationId: v1_integrations_rate_limits_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedRateLimitRuleList' description: '' post: operationId: v1_integrations_rate_limits_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/RateLimitRuleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/RateLimitRuleRequest' multipart/form-data: schema: $ref: '#/components/schemas/RateLimitRuleRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/RateLimitRule' description: '' /api/v1/integrations/rate-limits/{id}/: get: operationId: v1_integrations_rate_limits_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Rate Limit Rule. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/RateLimitRule' description: '' put: operationId: v1_integrations_rate_limits_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Rate Limit Rule. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/RateLimitRuleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/RateLimitRuleRequest' multipart/form-data: schema: $ref: '#/components/schemas/RateLimitRuleRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/RateLimitRule' description: '' patch: operationId: v1_integrations_rate_limits_partial_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Rate Limit Rule. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedRateLimitRuleRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedRateLimitRuleRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedRateLimitRuleRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/RateLimitRule' description: '' delete: operationId: v1_integrations_rate_limits_destroy parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Rate Limit Rule. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/integrations/sms/send/: post: operationId: v1_integrations_sms_send_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/integrations/webhook-events/: get: operationId: v1_integrations_webhook_events_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedWebhookEventList' description: '' /api/v1/integrations/webhook-events/{id}/: get: operationId: v1_integrations_webhook_events_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Event. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WebhookEvent' description: '' /api/v1/integrations/webhook-events/{id}/retry/: post: operationId: v1_integrations_webhook_events_retry_create parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Event. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WebhookEventRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WebhookEventRequest' multipart/form-data: schema: $ref: '#/components/schemas/WebhookEventRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WebhookEvent' description: '' /api/v1/integrations/webhook/{endpoint_url}/: post: operationId: v1_integrations_webhook_create parameters: - in: path name: endpoint_url schema: type: string required: true tags: - v1 security: - BearerAuth: [] responses: '200': description: No response body /api/v1/integrations/webhooks/: get: operationId: v1_integrations_webhooks_list parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedWebhookEndpointList' description: '' post: operationId: v1_integrations_webhooks_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WebhookEndpointRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WebhookEndpointRequest' multipart/form-data: schema: $ref: '#/components/schemas/WebhookEndpointRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '201': content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' description: '' /api/v1/integrations/webhooks/{id}/: get: operationId: v1_integrations_webhooks_retrieve parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Endpoint. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' description: '' put: operationId: v1_integrations_webhooks_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Endpoint. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WebhookEndpointRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WebhookEndpointRequest' multipart/form-data: schema: $ref: '#/components/schemas/WebhookEndpointRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' description: '' patch: operationId: v1_integrations_webhooks_partial_update parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Endpoint. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedWebhookEndpointRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedWebhookEndpointRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedWebhookEndpointRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' description: '' delete: operationId: v1_integrations_webhooks_destroy parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Endpoint. required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/integrations/webhooks/{id}/test/: post: operationId: v1_integrations_webhooks_test_create parameters: - in: path name: id schema: type: string format: uuid description: A UUID string identifying this Webhook Endpoint. required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WebhookEndpointRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WebhookEndpointRequest' multipart/form-data: schema: $ref: '#/components/schemas/WebhookEndpointRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' description: '' /api/v1/kyc/admin/{submission_id}/approve/: post: operationId: v1_kyc_admin_approve_create description: |- POST /api/v1/kyc/admin//approve/ Staff action: approve a KYC submission. Side effects: - Sets submission.status = APPROVED. - Sets VendorSetupState.id_verified = True (if user is a vendor). - Sends approval notification to the user. Body (optional): { "provider_reference": "smile_identity_job_123" } parameters: - in: path name: submission_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/kyc/admin/{submission_id}/reject/: post: operationId: v1_kyc_admin_reject_create description: |- POST /api/v1/kyc/admin//reject/ Staff action: reject a KYC submission with review notes. Body: { "review_notes": "NIN document is blurry. Please resubmit a clearer photo.", "allow_resubmit": true } parameters: - in: path name: submission_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/kyc/admin/submissions/: get: operationId: v1_kyc_admin_submissions_list description: |- GET /api/v1/kyc/admin/submissions/ Staff-only endpoint to list all KYC submissions with users and documents. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedKycSubmissionList' description: '' /api/v1/kyc/documents/upload/: post: operationId: v1_kyc_documents_upload_create description: |- POST /api/v1/kyc/documents/upload/ Record a KYC document Cloudinary upload against the user's active submission. Documents must be uploaded client-side to Cloudinary first using a presigned token from GET /api/v1/common/cloudinary/presign/?preset=kyc_docs. This endpoint records the resulting Cloudinary asset reference. Body: { "document_type": "nin_card", "document_number": "12345678901", "secure_url": "https://res.cloudinary.com/.../...", "public_id": "fashionistar/kyc//..." } Idempotent per (submission, document_type): re-uploading the same document type updates the existing record. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/kyc/status/: get: operationId: v1_kyc_status_retrieve description: |- GET /api/v1/kyc/status/ Returns the authenticated user's KYC submission with all documents. Delegates to get_kyc_submission_for_user selector (prefetch_related). Returns 200 with status='not_started' if no submission exists. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/kyc/submit/: post: operationId: v1_kyc_submit_create description: |- POST /api/v1/kyc/submit/ Initiate or reopen a KYC submission. - If no submission exists → creates PENDING submission. - If submission is REJECTED / RESUBMIT → resets to PENDING. - If submission is APPROVED / PENDING / IN_REVIEW → returns current state (idempotent). Body (optional): { "nin": "12345678901", "bvn": "12345678901" } tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/kyc/webhook/{provider_slug}/: post: operationId: v1_kyc_webhook_create description: |- Receive and process inbound KYC provider webhook callbacks. Workflow: 1. Extract provider_slug from URL. 2. Load KYCProviderConfig from cache. 3. Validate HMAC signature using provider's signing secret. 4. Dispatch to KycService.reconcile_webhook() for idempotent reconciliation. 5. Audit-log the outcome (compliance=True, 7-year retention). 6. Return HTTP 200 immediately (provider expects fast acknowledgement). parameters: - in: path name: provider_slug schema: type: string required: true tags: - v1 security: - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/measurements/: get: operationId: v1_measurements_retrieve description: |- GET /api/v1/measurements/ — List all profiles for the authenticated user. POST /api/v1/measurements/ — Create a new measurement profile. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_measurements_create description: |- GET /api/v1/measurements/ — List all profiles for the authenticated user. POST /api/v1/measurements/ — Create a new measurement profile. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/measurements/{profile_id}/: get: operationId: v1_measurements_retrieve_2 description: |- GET /api/v1/measurements// PUT /api/v1/measurements// PATCH /api/v1/measurements// DELETE /api/v1/measurements// parameters: - in: path name: profile_id schema: type: integer required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body put: operationId: v1_measurements_update description: |- GET /api/v1/measurements// PUT /api/v1/measurements// PATCH /api/v1/measurements// DELETE /api/v1/measurements// parameters: - in: path name: profile_id schema: type: integer required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_measurements_partial_update description: |- GET /api/v1/measurements// PUT /api/v1/measurements// PATCH /api/v1/measurements// DELETE /api/v1/measurements// parameters: - in: path name: profile_id schema: type: integer required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body delete: operationId: v1_measurements_destroy description: |- GET /api/v1/measurements// PUT /api/v1/measurements// PATCH /api/v1/measurements// DELETE /api/v1/measurements// parameters: - in: path name: profile_id schema: type: integer required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/measurements/{profile_id}/set-default/: post: operationId: v1_measurements_set_default_create description: POST /api/v1/measurements//set-default/ parameters: - in: path name: profile_id schema: type: integer required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/measurements/scan/{session_id}/submit-landmarks/: post: operationId: v1_measurements_scan_submit_landmarks_create description: |- POST /api/v1/measurements/scan//submit-landmarks/ Accepts MediaPipe world-coordinate landmarks from the browser. Fires the process_body_scan Celery task and returns immediately. Frontend should poll: GET /api/v1/ninja/measurements/scan//status/ until status = 'completed' or 'failed'. Expected body: { "user_height_cm": 175.5, "user_weight_kg": 70.0, // optional "landmarks": [<33 landmark objects>] } Success response (202 Accepted): { "session_id": "...", "status": "processing", "message": "Scan submitted. Processing in progress..." } parameters: - in: path name: session_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/measurements/scan/initiate/: post: operationId: v1_measurements_scan_initiate_create description: |- POST /api/v1/measurements/scan/initiate/ Creates a BodyScanSession with status=PENDING. Returns session_id — the frontend uses this to: 1. Display a "session ready" indicator to the user 2. Submit landmark data via SubmitLandmarksView 3. Poll Ninja API for processing status No body required. Optionally accepts: { "device_type": "web" | "ios" | "android" } tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/notifications/: get: operationId: v1_notifications_retrieve description: |- GET /api/v1/notifications/ Returns the authenticated user's in-app notification feed. Supports ?unread_only=true to filter unread. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/notifications/{notification_id}/: get: operationId: v1_notifications_retrieve_2 description: |- GET /api/v1/notifications// Returns a single notification without mutating read state. parameters: - in: path name: notification_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/notifications/mark-all-read/: post: operationId: v1_notifications_mark_all_read_create description: POST /api/v1/notifications/mark-all-read/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/notifications/mark-read/{notification_id}/: post: operationId: v1_notifications_mark_read_create description: POST /api/v1/notifications/mark-read// parameters: - in: path name: notification_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/notifications/preferences/: get: operationId: v1_notifications_preferences_retrieve description: |- GET /api/v1/notifications/preferences/ — List current preferences POST /api/v1/notifications/preferences/ — Set/update a preference tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_notifications_preferences_create description: |- GET /api/v1/notifications/preferences/ — List current preferences POST /api/v1/notifications/preferences/ — Set/update a preference tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/notifications/unread-count/: get: operationId: v1_notifications_unread_count_retrieve description: GET /api/v1/notifications/unread-count/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/: get: operationId: v1_orders_retrieve tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/{order_id}/: get: operationId: v1_orders_retrieve_2 parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/{order_id}/cancel/: post: operationId: v1_orders_cancel_create parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/{order_id}/confirm-delivery/: post: operationId: v1_orders_confirm_delivery_create description: Client confirms delivery → releases escrow. parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/admin/{order_id}/delivery-status/: patch: operationId: v1_orders_admin_delivery_status_partial_update description: |- Admin/staff delivery-status update endpoint. This is a DRF sync mutation because it changes order state and may trigger later escrow/provider reconciliation. The service performs the row lock; the view only validates input, checks high-trust staff access, and returns the serialized order. parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/place/: post: operationId: v1_orders_place_create tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/vendor/: get: operationId: v1_orders_vendor_retrieve tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/vendor/{order_id}/: get: operationId: v1_orders_vendor_retrieve_2 parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/vendor/{order_id}/production-status/: post: operationId: v1_orders_vendor_production_status_create parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_orders_vendor_production_status_partial_update description: PATCH alias used by the frontend production-status mutation. parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/vendor/{order_id}/transition/: post: operationId: v1_orders_vendor_transition_create parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_orders_vendor_transition_partial_update description: PATCH alias used by the frontend production-status mutation. parameters: - in: path name: order_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/orders/verify-pickup/: put: operationId: v1_orders_verify_pickup_update description: Verify order pickup token, release escrow, and transition to Completed status. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/password/change/: post: operationId: v1_password_change_create description: |- Authenticates current password and updates to a new one. Args: request (Request): The DRF request with old and new passwords. Returns: Response: Success confirmation or detailed error. tags: - Authentication requestBody: content: application/json: schema: $ref: '#/components/schemas/PasswordChangeRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PasswordChangeRequest' multipart/form-data: schema: $ref: '#/components/schemas/PasswordChangeRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/password/reset-confirm/{uidb64}/{token}/: post: operationId: v1_password_reset_confirm_create description: |- Updates the user's password if the token and uidb64 are valid. Args: request (Request): The DRF request containing the new password. uidb64 (str): Base64 encoded user ID from the URL. token (str): One-time use token from the URL. Returns: Response: Success confirmation or a 400 Bad Request if validation fails. parameters: - in: path name: token schema: type: string required: true - in: path name: uidb64 schema: type: string required: true tags: - Authentication requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmEmailRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmEmailRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmEmailRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/password/reset-phone-confirm/: post: operationId: v1_password_reset_phone_confirm_create description: |- Verifies the OTP and updates the user's password. Args: request (Request): The DRF request containing OTP and new password. Returns: Response: Success confirmation or a 400 Bad Request if verification fails. tags: - Authentication requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmPhoneRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmPhoneRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmPhoneRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthPasswordResetConfirmPhone' description: '' /api/v1/password/reset-request/: post: operationId: v1_password_reset_request_create description: |- Processes the reset request and triggers background notification. Args: request (Request): The incoming DRF request object. Returns: Response: A standardized success response, regardless of account existence. tags: - Authentication requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthPasswordResetRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthPasswordResetRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthPasswordResetRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/payment/banks/: get: operationId: v1_payment_banks_retrieve description: |- Retrieves the list of supported Nigerian banks for transfers. Flow: 1. Query Paystack Banks list endpoint. 2. Filter or format as needed. 3. Return to frontend for bank selection in withdrawal flows. Status Codes: 200 OK: Returns list of banks. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaystackBanksResponse' description: '' /api/v1/payment/cash/confirm/: post: operationId: v1_payment_cash_confirm_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CashConfirmationConfirmRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CashConfirmationConfirmRequest' multipart/form-data: schema: $ref: '#/components/schemas/CashConfirmationConfirmRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CashConfirmationConfirm' description: '' /api/v1/payment/cash/create/: post: operationId: v1_payment_cash_create_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CashConfirmationCreateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CashConfirmationCreateRequest' multipart/form-data: schema: $ref: '#/components/schemas/CashConfirmationCreateRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CashConfirmationCreate' description: '' /api/v1/payment/cash/resend-token/: post: operationId: v1_payment_cash_resend_token_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CashConfirmationResendRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CashConfirmationResendRequest' multipart/form-data: schema: $ref: '#/components/schemas/CashConfirmationResendRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CashConfirmationResend' description: '' /api/v1/payment/paystack/initialize/: post: operationId: v1_payment_paystack_initialize_create description: |- Initializes a Paystack transaction and creates a PaymentIntent record. Flow: 1. Receive amount and metadata from frontend. 2. Check idempotency to prevent double-charging. 3. Call Paystack API to get an authorization URL. 4. Store the reference and link it to the current User. Status Codes: 201 Created: Initialization successful, returns Paystack URL. 400 Bad Request: Invalid payload or Paystack provider error. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PaystackInitializeRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PaystackInitializeRequest' multipart/form-data: schema: $ref: '#/components/schemas/PaystackInitializeRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaystackInitialize' description: '' /api/v1/payment/paystack/verify/{reference}/: get: operationId: v1_payment_paystack_verify_retrieve description: |- Verifies the status of a specific Paystack transaction reference. Flow: 1. Frontend provides the reference after user payment. 2. Backend queries Paystack Verify API. 3. If success, updates PaymentIntent and associated Wallet/Order. 4. Returns final state to the frontend. Status Codes: 200 OK: Payment confirmed and processed. 400 Bad Request: Payment failed or reference not found. parameters: - in: path name: reference schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaystackVerify' description: '' /api/v1/payment/paystack/webhook/: post: operationId: v1_payment_paystack_webhook_create description: |- Asynchronous handler for Paystack webhook notifications. Flow: 1. Paystack sends a signed POST request. 2. Verify signature using environment secret. 3. Process the event (charge.success, transfer.success, etc.). 4. Ensure idempotency via reference tracking. Status Codes: 200 OK: Webhook accepted. 401 Unauthorized: Invalid signature. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PaystackWebhookRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PaystackWebhookRequest' multipart/form-data: schema: $ref: '#/components/schemas/PaystackWebhookRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaystackWebhook' description: '' /api/v1/payment/transfer-recipient/: post: operationId: v1_payment_transfer_recipient_create description: |- Creates a Transfer Recipient on Paystack for withdrawals. Flow: 1. User provides bank code and account number. 2. Backend calls Paystack to create a recipient. 3. Store the recipient code for future transfer operations. Status Codes: 201 Created: Recipient successfully registered. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/TransferRecipientCreateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/TransferRecipientCreateRequest' multipart/form-data: schema: $ref: '#/components/schemas/TransferRecipientCreateRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/TransferRecipientCreate' description: '' /api/v1/payment/wallet/fund/: post: operationId: v1_payment_wallet_fund_create description: Shared order-payment and wallet-topup entrypoint. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WalletFundPaymentRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WalletFundPaymentRequest' multipart/form-data: schema: $ref: '#/components/schemas/WalletFundPaymentRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WalletFundPayment' description: '' /api/v1/platform/settings/public/: get: operationId: v1_platform_settings_public_retrieve description: |- GET /api/v1/platform/settings/public/ Returns public-safe platform configuration values for frontend use. Does NOT require authentication — these are public limits and branding. Response is backed by Redis (60s TTL) so it is cheap to call on every payout modal open. Response schema: { "platform_name": "Fashionistar", "min_withdrawal_ngn": "1000.00", "max_withdrawal_ngn": "2000000.00", "max_daily_withdrawal_ngn": "5000000.00", "min_wallet_topup_ngn": "500.00", "max_wallet_topup_ngn": "5000000.00", "support_email": "support@fashionistar.net", "support_phone": "+234 913 7654 300", "terms_url": "https://fashionistar.net/terms", "privacy_url": "https://fashionistar.net/privacy" } tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/: get: operationId: v1_products_retrieve description: |- GET /api/v1/products/ Public. Query params: q, category, brand, vendor, min_price, max_price, in_stock, featured, ordering, page, page_size tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/{product_slug}/reviews/: get: operationId: v1_products_reviews_retrieve description: |- GET /api/v1/products//reviews/ — Public list (paginated). POST /api/v1/products//reviews/ — Authenticated client submission. parameters: - in: path name: product_slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body post: operationId: v1_products_reviews_create description: |- GET /api/v1/products//reviews/ — Public list (paginated). POST /api/v1/products//reviews/ — Authenticated client submission. parameters: - in: path name: product_slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/{slug}/: get: operationId: v1_products_retrieve_2 description: GET /api/v1/products// — Public. Includes ETag cache headers. parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/{slug}/wishlist/toggle/: post: operationId: v1_products_wishlist_toggle_create_2 description: POST /api/v1/products/wishlist//toggle/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/admin/{slug}/approve/: post: operationId: v1_products_admin_approve_create description: POST /api/v1/admin/products//approve/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/admin/{slug}/reject/: post: operationId: v1_products_admin_reject_create description: POST /api/v1/admin/products//reject/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/category/{category_id}/: get: operationId: v1_products_category_retrieve description: GET /api/v1/products/category// — Public. parameters: - in: path name: category_id schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/commission-snapshots/: get: operationId: v1_products_commission_snapshots_retrieve description: |- Return commission snapshot list with optional filters. Query params: product_id (str): Filter by product. vendor_id (str): Filter by vendor (via product). Args: request: DRF request. Returns: 200 success_response with list of snapshot dicts. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_commission_snapshots_create description: |- Create a new commission snapshot for a product. Commission snapshots are append-only. To change a rate, create a new snapshot with the updated commission_rate and a new effective_from date. Args: request: DRF request with JSON body containing: product_id (str, required): Product UUID. commission_rate (str/Decimal, required): Rate as decimal (e.g. "12.50"). effective_from (str, required): ISO 8601 datetime string. effective_to (str, optional): ISO 8601 end date. note (str, optional): Reason / notes for this rate change. Returns: 201 success_response with snapshot id. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/commission-snapshots/{id}/: get: operationId: v1_products_commission_snapshots_retrieve_2 description: Return a single commission snapshot row. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_products_commission_snapshots_partial_update description: |- Update mutable fields: note and effective_to only. Commission rate changes must create a new snapshot row (append-only policy). Args: request: DRF request with partial JSON body. pk: Snapshot PK string. Returns: 200 success_response or error. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/coupons/: get: operationId: v1_products_coupons_retrieve description: |- GET /api/v1/products/coupons/ POST /api/v1/products/coupons/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_coupons_create description: |- GET /api/v1/products/coupons/ POST /api/v1/products/coupons/ tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/coupons/{coupon_id}/: delete: operationId: v1_products_coupons_destroy description: DELETE /api/v1/products/coupons// parameters: - in: path name: coupon_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/products/featured/: get: operationId: v1_products_featured_retrieve description: GET /api/v1/products/featured/ — Public. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/shipping-profiles/: get: operationId: v1_products_shipping_profiles_retrieve description: |- Return shipping profile list scoped by caller role. Args: request: DRF request. Returns: 200 success_response with list of profile dicts. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_shipping_profiles_create description: |- Create a new shipping profile for the calling vendor. Args: request: DRF request with JSON body. Returns: 201 success_response with created profile id. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/shipping-profiles/{id}/: get: operationId: v1_products_shipping_profiles_retrieve_2 description: Return a single shipping profile. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_products_shipping_profiles_partial_update description: Partially update a shipping profile. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/size-guides/: get: operationId: v1_products_size_guides_retrieve description: |- Return size guide list scoped by role. Args: request: DRF request with authenticated user. Returns: 200 success_response with list of guide dicts. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_size_guides_create description: |- Create a new size guide template. Args: request: DRF request with JSON body. Returns: 201 success_response with created guide id. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/size-guides/{id}/: get: operationId: v1_products_size_guides_retrieve_2 description: Return a single size guide row. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_products_size_guides_partial_update description: Partially update a size guide template. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body delete: operationId: v1_products_size_guides_destroy description: Soft-delete a size guide template. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/products/vendor/: get: operationId: v1_products_vendor_retrieve description: |- GET /api/v1/products/vendor/ — List vendor's own products (paginated). POST /api/v1/products/vendor/ — Create product (idempotency key supported). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_vendor_create description: |- GET /api/v1/products/vendor/ — List vendor's own products (paginated). POST /api/v1/products/vendor/ — Create product (idempotency key supported). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/vendor/{slug}/: get: operationId: v1_products_vendor_retrieve_2 description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_products_vendor_partial_update description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body delete: operationId: v1_products_vendor_destroy description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/products/vendor/{slug}/inventory/: get: operationId: v1_products_vendor_inventory_retrieve description: |- GET /api/v1/products/vendor//inventory/ POST /api/v1/products/vendor//inventory/ — Manual stock adjustment Best-practice #5: dedicated inventory log endpoint. parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_vendor_inventory_create description: |- GET /api/v1/products/vendor//inventory/ POST /api/v1/products/vendor//inventory/ — Manual stock adjustment Best-practice #5: dedicated inventory log endpoint. parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/vendor/{slug}/media/: get: operationId: v1_products_vendor_media_retrieve description: |- GET /api/v1/products/vendor//media/ POST /api/v1/products/vendor//media/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_products_vendor_media_create description: |- GET /api/v1/products/vendor//media/ POST /api/v1/products/vendor//media/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/vendor/{slug}/media/{gid}/: delete: operationId: v1_products_vendor_media_destroy description: DELETE /api/v1/products/vendor//media// parameters: - in: path name: gid schema: type: string format: uuid required: true - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/products/vendor/{slug}/publish/: post: operationId: v1_products_vendor_publish_create description: POST /api/v1/products/vendor//publish/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/vendor/reviews/{review_id}/reply/: post: operationId: v1_products_vendor_reviews_reply_create description: POST /api/v1/products/vendor/reviews//reply/ parameters: - in: path name: review_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/products/wishlist/: get: operationId: v1_products_wishlist_retrieve description: GET /api/v1/products/wishlist/ — Full wishlist with embedded products. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/wishlist/{slug}/toggle/: post: operationId: v1_products_wishlist_toggle_create description: POST /api/v1/products/wishlist//toggle/ parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/products/wishlist/merge/: post: operationId: v1_products_wishlist_merge_create description: |- POST /api/v1/products/wishlist/merge/ Promotes anonymous wishlist rows into the authenticated account after login and before checkout. The view only resolves request identity; all merge behavior lives in the product service layer. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/profile/me/: get: operationId: v1_profile_me_retrieve description: |- GET /api/v1/profile/me/ — Return authenticated user's full profile. PATCH /api/v1/profile/me/ — Partial update of authenticated user profile. GET uses: UserProfileSerializer (all readable fields) PATCH uses: update_user_profile() service (guarded, validated writes) tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthUserProfile' description: '' put: operationId: v1_profile_me_update description: |- GET /api/v1/profile/me/ — Return authenticated user's full profile. PATCH /api/v1/profile/me/ — Partial update of authenticated user profile. GET uses: UserProfileSerializer (all readable fields) PATCH uses: update_user_profile() service (guarded, validated writes) tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/AuthUserProfileRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AuthUserProfileRequest' multipart/form-data: schema: $ref: '#/components/schemas/AuthUserProfileRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthUserProfile' description: '' patch: operationId: v1_profile_me_partial_update description: |- GET /api/v1/profile/me/ — Return authenticated user's full profile. PATCH /api/v1/profile/me/ — Partial update of authenticated user profile. GET uses: UserProfileSerializer (all readable fields) PATCH uses: update_user_profile() service (guarded, validated writes) tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedAuthUserProfileRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedAuthUserProfileRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedAuthUserProfileRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/AuthUserProfile' description: '' /api/v1/profile/users/: get: operationId: v1_profile_users_list description: |- GET /api/v1/profile/users/ — Admin-only list of all registered users. Returns ProtectedUserSerializer shape — no sensitive fields exposed. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedAuthProtectedUserList' description: '' /api/v1/public/contact/: post: operationId: v1_public_contact_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CommonContactSubmissionRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CommonContactSubmissionRequest' multipart/form-data: schema: $ref: '#/components/schemas/CommonContactSubmissionRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/CommonContactSubmission' description: '' /api/v1/public/newsletter/: post: operationId: v1_public_newsletter_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CommonNewsletterSignupRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CommonNewsletterSignupRequest' multipart/form-data: schema: $ref: '#/components/schemas/CommonNewsletterSignupRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/CommonNewsletterSignup' description: '' /api/v1/public/waitlist/: post: operationId: v1_public_waitlist_create tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CommonWaitlistSignupRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CommonWaitlistSignupRequest' multipart/form-data: schema: $ref: '#/components/schemas/CommonWaitlistSignupRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/CommonWaitlistSignup' description: '' /api/v1/support/admin/queue/: get: operationId: v1_support_admin_queue_retrieve description: |- GET /api/v1/support/admin/queue/ Staff-only: full ticket queue (all open tickets, any user). Supports ?status=&priority= filters. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/support/tickets/: get: operationId: v1_support_tickets_retrieve description: |- GET /api/v1/support/tickets/ — Return authenticated user's ticket feed. POST /api/v1/support/tickets/ — Open a new ticket (idempotent per order_id). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_support_tickets_create description: |- GET /api/v1/support/tickets/ — Return authenticated user's ticket feed. POST /api/v1/support/tickets/ — Open a new ticket (idempotent per order_id). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/support/tickets/{ticket_id}/: get: operationId: v1_support_tickets_retrieve_2 description: |- GET /api/v1/support/tickets// Returns full ticket detail including message thread and escalation. Scoped to the authenticated user (staff sees all via admin queue). parameters: - in: path name: ticket_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/support/tickets/{ticket_id}/escalate/: post: operationId: v1_support_tickets_escalate_create description: |- POST /api/v1/support/tickets//escalate/ Staff-only endpoint: create or return a TicketEscalation. Idempotent — safe to call twice. parameters: - in: path name: ticket_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/support/tickets/{ticket_id}/messages/: post: operationId: v1_support_tickets_messages_create description: |- POST /api/v1/support/tickets//messages/ Add a threaded reply to a ticket. Staff replies are differentiated via is_staff_reply flag. parameters: - in: path name: ticket_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/support/tickets/{ticket_id}/status/: patch: operationId: v1_support_tickets_status_partial_update description: |- PATCH /api/v1/support/tickets//status/ Staff-only endpoint: transition ticket status with optional notes. parameters: - in: path name: ticket_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/transactions/: get: operationId: v1_transactions_list description: |- Retrieves a paginated list of transactions for the authenticated user. Flow: 1. Filter transactions where user is either the initiator or recipient. 2. Order by most recent first. 3. Return standardized transaction objects. Status Codes: 200 OK: Returns transaction list. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedTransactionList' description: '' /api/v1/transactions/{transaction_id}/: get: operationId: v1_transactions_retrieve description: |- GET /api/v1/transactions// Retrieve details of a specific transaction. Retrieves granular details of a specific transaction ID. Security: - Enforces ownership check (user must be party to the transaction). Status Codes: 200 OK: Returns transaction details. 404 Not Found: Transaction doesn't exist or user lacks access. parameters: - in: path name: transaction_id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Transaction' description: '' /api/v1/transactions/{transaction_id}/dispute/: post: operationId: v1_transactions_dispute_create description: |- Opens a formal dispute case for a specific transaction. POST /api/v1/transactions//refund/ Initiate a refund for a transaction on escrow hold. Flow: 1. Client submits reason and disputed amount. 2. Backend freezes related escrow funds if applicable. 3. Notify admin/vendor of the open dispute. Status Codes: 201 Created: Dispute case opened. parameters: - in: path name: transaction_id schema: type: string format: uuid required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/DisputeCreateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/DisputeCreateRequest' multipart/form-data: schema: $ref: '#/components/schemas/DisputeCreateRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/DisputeCreate' description: '' /api/v1/transactions/{transaction_id}/refund/: post: operationId: v1_transactions_refund_create description: |- Initiates a manual refund for an escrowed payment. POST /api/v1/transactions//refund/ Initiate a refund for a transaction on escrow hold. Flow: 1. Verify the transaction is currently held in Escrow. 2. Reverse the hold back to the client's available balance. 3. Log the refund event in the transaction history. Status Codes: 200 OK: Refund successfully processed. 400 Bad Request: Transaction not eligible for refund. parameters: - in: path name: transaction_id schema: type: string format: uuid required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/RefundRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/RefundRequest' multipart/form-data: schema: $ref: '#/components/schemas/RefundRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Refund' description: '' /api/v1/transactions/summary/: get: operationId: v1_transactions_summary_retrieve description: |- Aggregates financial performance statistics for the user's wallet. GET /api/v1/transactions/summary/ Get a summary of transactions (inflow, outflow, count). Flow: 1. Sum all credits (inflow). 2. Sum all debits (outflow). 3. Count total volume of transactions. Status Codes: 200 OK: Returns summary statistics. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/TransactionSummary' description: '' /api/v1/upload/presign/: post: operationId: v1_upload_presign_create description: |- POST /api/v1/upload/presign/ Generate a time-limited, HMAC-SHA256–signed Cloudinary upload token. The frontend uses this to POST a file DIRECTLY to Cloudinary without routing the upload data through the Django server. Authentication: Bearer JWT (IsAuthenticated). Request body (validated by PresignRequestSerializer): { "asset_type": "avatar" | "product_image" | "product_video" | "measurement" } Response 200: { "success": true, "cloud_name": "your_cloud", "api_key": "...", "signature": "hex-sha256", "timestamp": 1712345678, "folder": "fashionistar/users/avatars/user_UUID", "upload_preset": "fashionistar_avatars", "resource_type": "image", "eager": [...], "eager_async": true } Response 400 — invalid asset_type (serializer validation error). Response 500 — signature generation failed. parameters: - in: query name: format schema: type: string enum: - html - json - multipart tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/CommonPresignRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/CommonPresignRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/CommonPresignRequestRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/CommonPresignRequest' multipart/form-data: schema: $ref: '#/components/schemas/CommonPresignRequest' text/html: schema: $ref: '#/components/schemas/CommonPresignRequest' description: '' /api/v1/vendor/bank-accounts/: get: operationId: v1_vendor_bank_accounts_retrieve description: |- GET /api/v1/vendor/bank-accounts/ — list saved bank accounts POST /api/v1/vendor/bank-accounts/ — create a new bank account tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/BankAccountOutput' description: '' post: operationId: v1_vendor_bank_accounts_create description: |- GET /api/v1/vendor/bank-accounts/ — list saved bank accounts POST /api/v1/vendor/bank-accounts/ — create a new bank account tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/BankAccountCreateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/BankAccountCreateRequest' multipart/form-data: schema: $ref: '#/components/schemas/BankAccountCreateRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/BankAccountCreate' description: '' /api/v1/vendor/bank-accounts/{id}/: delete: operationId: v1_vendor_bank_accounts_destroy description: |- DELETE /api/v1/vendor/bank-accounts// Soft-delete the bank account and clean up the Paystack recipient. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/vendor/bank-accounts/{id}/default/: patch: operationId: v1_vendor_bank_accounts_default_partial_update description: |- PATCH /api/v1/vendor/bank-accounts//default/ Set the specified bank account as the vendor's default payout account. parameters: - in: path name: id schema: type: string format: uuid required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/vendor/bank-accounts/resolve/: post: operationId: v1_vendor_bank_accounts_resolve_create description: |- POST /api/v1/vendor/bank-accounts/resolve/ Proxy Paystack /bank/resolve to retrieve the account holder name. This endpoint is called by the frontend "Resolve Name" button in the Add Bank Account modal. Request body: account_number (str): 10-digit NUBAN bank_code (str): Paystack bank code (e.g. "044") Response (200): { account_name: str, account_number: str } tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/BankAccountResolveRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/BankAccountResolveRequest' multipart/form-data: schema: $ref: '#/components/schemas/BankAccountResolveRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/BankAccountResolve' description: '' /api/v1/vendor/orders/{order_id}/status/: put: operationId: v1_vendor_orders_status_update description: |- PATCH /api/v1/vendor/orders//status/ Update order_status for a vendor's own order. Allowed values: Pending, Processing, Shipped, Fulfilled, Cancelled. Payment status (paid/unpaid) is immutable here — managed by payment gateway. parameters: - in: path name: order_id schema: type: integer required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/VendorOrderStatusRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/VendorOrderStatusRequest' multipart/form-data: schema: $ref: '#/components/schemas/VendorOrderStatusRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorOrderStatus' description: '' patch: operationId: v1_vendor_orders_status_partial_update description: |- PATCH /api/v1/vendor/orders//status/ Update order_status for a vendor's own order. Allowed values: Pending, Processing, Shipped, Fulfilled, Cancelled. Payment status (paid/unpaid) is immutable here — managed by payment gateway. parameters: - in: path name: order_id schema: type: integer required: true tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedVendorOrderStatusRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedVendorOrderStatusRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedVendorOrderStatusRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorOrderStatus' description: '' /api/v1/vendor/payout/: post: operationId: v1_vendor_payout_create description: POST /api/v1/vendor/payout/ — save bank / payout account details tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/VendorPayoutDetailsRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/VendorPayoutDetailsRequest' multipart/form-data: schema: $ref: '#/components/schemas/VendorPayoutDetailsRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorPayoutDetails' description: '' /api/v1/vendor/payout/request/: post: operationId: v1_vendor_payout_request_create description: |- POST /api/v1/vendor/payout/request/ Initiate a bank transfer payout from the vendor's Fashionistar wallet to one of their saved bank accounts. Request body: bank_account_id (UUID): The VendorBankAccount UUID to pay into. amount (Decimal): Amount in NGN (min ₦1,000). narration (str, optional): Bank transfer description. Response (200): { "status": "success", "reference": "PAYOUT-XXXXXXXX-XXXXXXXXXXXXXXXXXXXX", "transfer_code": "TRF_xxxxx", "amount": "5000.00", "currency": "NGN", "message": "Payout initiated successfully. Funds will arrive within 1–2 business days." } tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PayoutRequestRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PayoutRequestRequest' multipart/form-data: schema: $ref: '#/components/schemas/PayoutRequestRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PayoutRequest' description: '' /api/v1/vendor/pin/set/: post: operationId: v1_vendor_pin_set_create description: POST /api/v1/vendor/pin/set/ — set 4-digit payout confirmation PIN tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/VendorTransactionPinRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/VendorTransactionPinRequest' multipart/form-data: schema: $ref: '#/components/schemas/VendorTransactionPinRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorTransactionPin' description: '' /api/v1/vendor/pin/verify/: post: operationId: v1_vendor_pin_verify_create description: POST /api/v1/vendor/pin/verify/ — verify payout PIN before withdrawal tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/VendorTransactionPinRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/VendorTransactionPinRequest' multipart/form-data: schema: $ref: '#/components/schemas/VendorTransactionPinRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorTransactionPin' description: '' /api/v1/vendor/products/{slug}/delete/: get: operationId: v1_vendor_products_delete_retrieve description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_vendor_products_delete_partial_update description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body delete: operationId: v1_vendor_products_delete_destroy description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/vendor/products/{slug}/edit/: get: operationId: v1_vendor_products_edit_retrieve description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body patch: operationId: v1_vendor_products_edit_partial_update description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body delete: operationId: v1_vendor_products_edit_destroy description: |- GET /api/v1/products/vendor// PATCH /api/v1/products/vendor// DELETE /api/v1/products/vendor// parameters: - in: path name: slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '204': description: No response body /api/v1/vendor/products/create/: get: operationId: v1_vendor_products_create_retrieve description: |- GET /api/v1/products/vendor/ — List vendor's own products (paginated). POST /api/v1/products/vendor/ — Create product (idempotency key supported). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_vendor_products_create_create description: |- GET /api/v1/products/vendor/ — List vendor's own products (paginated). POST /api/v1/products/vendor/ — Create product (idempotency key supported). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/vendor/products/filter/: get: operationId: v1_vendor_products_filter_retrieve description: |- GET /api/v1/products/vendor/ — List vendor's own products (paginated). POST /api/v1/products/vendor/ — Create product (idempotency key supported). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body post: operationId: v1_vendor_products_filter_create description: |- GET /api/v1/products/vendor/ — List vendor's own products (paginated). POST /api/v1/products/vendor/ — Create product (idempotency key supported). tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': description: No response body /api/v1/vendor/profile/: get: operationId: v1_vendor_profile_retrieve description: |- GET /api/v1/vendor/profile/ — retrieve vendor store profile PATCH /api/v1/vendor/profile/ — update store profile tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorProfileOutput' description: '' patch: operationId: v1_vendor_profile_partial_update description: |- GET /api/v1/vendor/profile/ — retrieve vendor store profile PATCH /api/v1/vendor/profile/ — update store profile tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchedVendorProfileUpdateRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/PatchedVendorProfileUpdateRequest' multipart/form-data: schema: $ref: '#/components/schemas/PatchedVendorProfileUpdateRequest' security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorProfileUpdate' description: '' /api/v1/vendor/public/: get: operationId: v1_vendor_public_retrieve description: |- GET /api/v1/vendor/public/ Public listing of active vendors for the home/vendors marketplace page. Permissions: AllowAny (no auth required — publicly browsable). Filters (query params): ?is_featured=true — featured vendors only ?city=Lagos — filter by city ?search=bespoke — search store_name / tagline ?limit=24 — page size (default 24, max 100) ?offset=0 — pagination offset Response: { status, count, data: [VendorCard...] } tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/vendor/public/{store_slug}/: get: operationId: v1_vendor_public_retrieve_2 description: |- GET /api/v1/vendor/public/{store_slug}/ Public vendor profile detail for the /vendors/[slug] page. Permissions: AllowAny. Returns full vendor profile plus top 12 products. parameters: - in: path name: store_slug schema: type: string required: true tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] - {} responses: '200': description: No response body /api/v1/vendor/setup/: get: operationId: v1_vendor_setup_retrieve description: |- GET /api/v1/vendor/setup/ — retrieve onboarding setup state POST /api/v1/vendor/setup/ — create/update the first vendor setup record tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorSetupState' description: '' post: operationId: v1_vendor_setup_create description: |- GET /api/v1/vendor/setup/ — retrieve onboarding setup state POST /api/v1/vendor/setup/ — create/update the first vendor setup record tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/VendorSetupRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/VendorSetupRequest' multipart/form-data: schema: $ref: '#/components/schemas/VendorSetupRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/VendorSetup' description: '' /api/v1/wallet/balance/: get: operationId: v1_wallet_balance_retrieve description: |- Alias for MyWalletView, specifically focusing on the current balance state. Legacy Context: Previously served as a simple balance-only endpoint. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Wallet' description: '' /api/v1/wallet/escrow/hold/: post: operationId: v1_wallet_escrow_hold_create description: |- Places funds on escrow hold when a new order is initialized. Flow: 1. Verify user has sufficient balance. 2. Deduct amount from available balance. 3. Create a Hold record with PENDING status. 4. Increment 'held_balance'. Status Codes: 201 Created: Funds successfully locked in escrow. 400 Bad Request: Insufficient balance. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/EscrowHoldRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/EscrowHoldRequest' multipart/form-data: schema: $ref: '#/components/schemas/EscrowHoldRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/EscrowHold' description: '' /api/v1/wallet/escrow/release/: post: operationId: v1_wallet_escrow_release_create description: |- Releases escrowed funds to the vendor after order completion. Flow: 1. Locate the Hold record by reference. 2. Verify client authorization (or automated release trigger). 3. Calculate and deduct platform commission. 4. Credit vendor's available balance. 5. Mark Hold as RELEASED. Status Codes: 200 OK: Vendor successfully credited. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/EscrowReleaseRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/EscrowReleaseRequest' multipart/form-data: schema: $ref: '#/components/schemas/EscrowReleaseRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/EscrowRelease' description: '' /api/v1/wallet/me/: get: operationId: v1_wallet_me_retrieve description: |- Retrieves the authenticated user's digital wallet profile. Flow: 1. Check if wallet exists for the user. 2. If not, provision a new wallet with zero balance. 3. Return balance and hold statistics. Status Codes: 200 OK: Returns wallet details. tags: - v1 security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/Wallet' description: '' /api/v1/wallet/pin/change/: post: operationId: v1_wallet_pin_change_create description: |- Updates an existing transaction PIN after verifying the current one. Security: Requires 'current_pin' to prevent unauthorized changes. Status Codes: 200 OK: PIN updated. 400 Bad Request: Invalid current PIN or weak new PIN. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WalletPinChangeRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WalletPinChangeRequest' multipart/form-data: schema: $ref: '#/components/schemas/WalletPinChangeRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WalletPinChange' description: '' /api/v1/wallet/pin/set/: post: operationId: v1_wallet_pin_set_create description: |- Establishes a 4-digit transaction PIN for wallet authorization. Flow: 1. User provides a 4-digit numeric string. 2. Service hashes the PIN for secure storage. 3. Enables transaction capabilities for the wallet. Status Codes: 200 OK: PIN established. 400 Bad Request: Invalid format or PIN already set. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WalletPinSetRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WalletPinSetRequest' multipart/form-data: schema: $ref: '#/components/schemas/WalletPinSetRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WalletPinSet' description: '' /api/v1/wallet/pin/verify/: post: operationId: v1_wallet_pin_verify_create description: |- Validates a transaction PIN without performing a financial operation. Use Case: Frontend checks PIN before showing "Confirm Transfer" buttons. Status Codes: 200 OK: returns {"valid": bool} tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WalletPinVerifyRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WalletPinVerifyRequest' multipart/form-data: schema: $ref: '#/components/schemas/WalletPinVerifyRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WalletPinVerify' description: '' /api/v1/wallet/refund/: post: operationId: v1_wallet_refund_create description: |- Refunds escrowed funds back to the client available balance. Use Case: Order cancellation or dispute resolution in favor of the client. Flow: 1. Move funds from held_balance back to available_balance. 2. Mark Hold as REFUNDED. Status Codes: 200 OK: Client successfully refunded. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/EscrowRefundRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/EscrowRefundRequest' multipart/form-data: schema: $ref: '#/components/schemas/EscrowRefundRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/EscrowRefund' description: '' /api/v1/wallet/withdraw/: post: operationId: v1_wallet_withdraw_create description: |- Create a KYC-gated wallet withdrawal request. The service blocks before debit if KYC is incomplete, then moves funds from available to pending balance and writes a processing payout ledger row. tags: - v1 requestBody: content: application/json: schema: $ref: '#/components/schemas/WalletWithdrawalRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/WalletWithdrawalRequest' multipart/form-data: schema: $ref: '#/components/schemas/WalletWithdrawalRequest' required: true security: - jwtAuth: [] - tokenAuth: [] - cookieAuth: [] - basicAuth: [] - BearerAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/WalletWithdrawal' description: '' components: schemas: AddressCreate: type: object description: Input serializer for POST /addresses/. properties: label: type: string description: 'Short label: ''Home'', ''Office'', or ''Mum\''s place''.' maxLength: 80 full_name: type: string maxLength: 150 phone: type: string maxLength: 30 street_address: type: string description: Street, house number, landmark. city: type: string maxLength: 100 state: type: string maxLength: 100 country: type: string maxLength: 100 postal_code: type: string maxLength: 20 is_default: type: boolean description: True if this is the primary address shown at checkout. required: - city - state - street_address AddressCreateRequest: type: object description: Input serializer for POST /addresses/. properties: label: type: string description: 'Short label: ''Home'', ''Office'', or ''Mum\''s place''.' maxLength: 80 full_name: type: string maxLength: 150 phone: type: string maxLength: 30 street_address: type: string minLength: 1 description: Street, house number, landmark. city: type: string minLength: 1 maxLength: 100 state: type: string minLength: 1 maxLength: 100 country: type: string minLength: 1 maxLength: 100 postal_code: type: string maxLength: 20 is_default: type: boolean description: True if this is the primary address shown at checkout. required: - city - state - street_address Alert: type: object properties: id: type: integer readOnly: true rule: type: integer title: Alert Rule rule_name: type: string readOnly: true rule_severity: type: string readOnly: true status: $ref: '#/components/schemas/AlertStatusEnum' metric_value: type: number format: double title: Current Value message: type: string title: Alert Message metadata: {} fired_at: type: string format: date-time readOnly: true title: Triggered At resolved_at: type: string format: date-time nullable: true required: - fired_at - id - message - metric_value - rule - rule_name - rule_severity AlertRequest: type: object properties: rule: type: integer title: Alert Rule status: $ref: '#/components/schemas/AlertStatusEnum' metric_value: type: number format: double title: Current Value message: type: string minLength: 1 title: Alert Message metadata: {} resolved_at: type: string format: date-time nullable: true required: - message - metric_value - rule AlertRule: type: object properties: id: type: integer readOnly: true name: type: string title: Rule Name maxLength: 100 metric_name: type: string maxLength: 255 operator: allOf: - $ref: '#/components/schemas/OperatorEnum' title: Comparison Operator threshold: type: number format: double severity: $ref: '#/components/schemas/SeverityEnum' is_active: type: boolean description: type: string created_at: type: string format: date-time readOnly: true updated_at: type: string format: date-time readOnly: true required: - created_at - id - metric_name - name - operator - threshold - updated_at AlertRuleRequest: type: object properties: name: type: string minLength: 1 title: Rule Name maxLength: 100 metric_name: type: string minLength: 1 maxLength: 255 operator: allOf: - $ref: '#/components/schemas/OperatorEnum' title: Comparison Operator threshold: type: number format: double severity: $ref: '#/components/schemas/SeverityEnum' is_active: type: boolean description: type: string required: - metric_name - name - operator - threshold AlertStatusEnum: enum: - firing - resolved - suppressed type: string AssetTypeEnum: enum: - avatar - blog - brand - category - chat_file - collection - generic_image - generic_video - kyc_document - measurement - product_color - product_gallery - product_image - product_video - profile - vendor_shop type: string AuthGoogleAuth: type: object description: |- Serializer for Google ID Token authentication. Flow: Login (existing user): { id_token } — role is optional, ignored Register (new user): { id_token, role: 'vendor'|'client' } properties: id_token: type: string description: Google ID Token (JWT) returned by @react-oauth/google on the frontend. role: default: client description: User's role — required for new registrations, ignored for existing users. oneOf: - $ref: '#/components/schemas/RoleC2fEnum' - $ref: '#/components/schemas/BlankEnum' required: - id_token AuthGoogleAuthRequest: type: object description: |- Serializer for Google ID Token authentication. Flow: Login (existing user): { id_token } — role is optional, ignored Register (new user): { id_token, role: 'vendor'|'client' } properties: id_token: type: string minLength: 1 description: Google ID Token (JWT) returned by @react-oauth/google on the frontend. role: default: client description: User's role — required for new registrations, ignored for existing users. oneOf: - $ref: '#/components/schemas/RoleC2fEnum' - $ref: '#/components/schemas/BlankEnum' required: - id_token AuthLoginRequest: type: object description: |- Serializer for authenticating users with either email or phone. Enterprise-grade auth flow (priority order): 1. Alive-only lookup (is_deleted=False) 2. Soft-deleted pool check → SoftDeletedUserError (403) 3. Password check → InvalidCredentialsError (401) 4a. is_verified check FIRST → AccountNotVerifiedError (403) with OTP URLs 4b. is_active check SECOND → AccountDeactivatedError (403) with support URL Serializer for user authentication via Email or Phone. Validation Logic: 1. Normalise input identifier (email to lowercase). 2. Verify user exists and is not soft-deleted. 3. Verify password hash matches. 4. Check account lifecycle status (verified, active). Security: - Uses Django's `check_password` for constant-time comparison. - Throttled at the View level to prevent brute-force. properties: email_or_phone: type: string writeOnly: true minLength: 1 description: User's email or phone for login password: type: string writeOnly: true minLength: 1 description: User's password required: - email_or_phone - password AuthLogout: type: object description: Accepts the refresh token to blacklist on logout. properties: refresh: type: string description: Refresh token to blacklist on logout. required: - refresh AuthLogoutRequest: type: object description: Accepts the refresh token to blacklist on logout. properties: refresh: type: string minLength: 1 description: Refresh token to blacklist on logout. required: - refresh AuthMe: type: object description: |- Serializes the authenticated user's profile for the /auth/me/ endpoint. This serializer's output shape is the authoritative contract between the backend and the frontend Zustand auth store (useAuthHydration). Field-by-field null/blank behaviour: user_id → str (UUID) identifying_info → str (email or phone or fallback string) member_id → str | null (null only before first save race, practically never) email → str | null (null for phone-only accounts) phone → str | null (null for email-only accounts, E.164 format) first_name → str (empty string "" when not set — model blank=True) last_name → str (empty string "" when not set — model blank=True) role → str (choices: client | vendor | staff | admin | …) auth_provider → str (choices: email | phone | google) is_verified → bool is_active → bool is_staff → bool avatar → str | null (full Cloudinary HTTPS URL or null) bio → str (empty string "" when not set) country → str (empty string "" when not set) state → str (empty string "" when not set) city → str (empty string "" when not set) address → str (empty string "" when not set) date_joined → str | null (ISO-8601 datetime string or null) last_login → str | null (ISO-8601 datetime string or null) properties: user_id: type: string readOnly: true identifying_info: type: string readOnly: true member_id: type: string readOnly: true nullable: true description: Unique human-readable brand ID (e.g. FASTAR000062). Auto-generated on user creation. Cannot be changed. email: type: string format: email readOnly: true nullable: true title: Email address description: Primary unique identifier for email-based auth. phone: type: string readOnly: true first_name: type: string readOnly: true default: '' last_name: type: string readOnly: true default: '' role: allOf: - $ref: '#/components/schemas/RoleC2fEnum' readOnly: true description: RBAC Role. Cannot be changed after creation. auth_provider: allOf: - $ref: '#/components/schemas/AuthProviderEnum' readOnly: true description: Authentication provider used at signup. is_verified: type: boolean readOnly: true description: True if email/phone OTP is verified. is_active: type: boolean readOnly: true description: True if user account is active. is_staff: type: boolean readOnly: true title: Staff status description: Designates whether the user can log into this admin site. has_client_profile: type: string readOnly: true has_vendor_profile: type: string readOnly: true vendor_onboarding_status: type: string readOnly: true dashboard_entrypoint: type: string readOnly: true avatar: type: string readOnly: true bio: type: string readOnly: true description: User's biography. country: type: string readOnly: true description: User's country. state: type: string readOnly: true description: User's state or province. city: type: string readOnly: true description: User's city. address: type: string readOnly: true description: User's street address. date_joined: type: string format: date-time readOnly: true last_login: type: string format: date-time readOnly: true required: - address - auth_provider - avatar - bio - city - country - dashboard_entrypoint - date_joined - email - first_name - has_client_profile - has_vendor_profile - identifying_info - is_active - is_staff - is_verified - last_login - last_name - member_id - phone - role - state - user_id - vendor_onboarding_status AuthMethodEnum: enum: - email - phone - google - biometric type: string AuthOTP: type: object description: |- Serializer for OTP verification. Validation Logic: - Required: 6-digit string. - Numeric only. Security: - Max length enforced to prevent buffer/memory attacks. properties: otp: type: string description: One-Time Password (OTP) for verification. maxLength: 6 required: - otp AuthOTPRequest: type: object description: |- Serializer for OTP verification. Validation Logic: - Required: 6-digit string. - Numeric only. Security: - Max length enforced to prevent buffer/memory attacks. properties: otp: type: string minLength: 1 description: One-Time Password (OTP) for verification. maxLength: 6 required: - otp AuthPasswordResetConfirmEmailRequest: type: object description: |- Serializer for confirming password reset via email magic link. Validates the new password and confirmation match. The uidb64 + token URL params are merged in by the view. properties: password: type: string writeOnly: true minLength: 1 description: New password password2: type: string writeOnly: true minLength: 1 description: Confirm new password required: - password - password2 AuthPasswordResetConfirmPhone: type: object description: |- Serializer for confirming password reset via phone OTP. OTP-ONLY design (mirrors VerifyOTPView pattern exactly): - Client sends ONLY: otp + new_password + new_password_confirm. - phone is NOT required in the body — the service discovers the user via OTPService.verify_by_otp_sync(otp, purpose='password_reset'), which uses an O(1) SHA-256 hash index lookup in Redis: otp_hash:{sha256(otp)} → otp:{user_id}:password_reset:{snippet} - This prevents account enumeration: an attacker cannot test whether a phone number has an account by observing different error responses. Redis key schema (written during reset-request): Primary : otp:{user_id}:password_reset:{snippet} Value = "{encrypted_otp}|{sha256_hex}" Secondary: otp_hash:{sha256_hex} → primary_key (TTL = 300 s) Field names match Zod PasswordResetConfirmPhoneSchema exactly: Frontend sends: { otp, new_password, new_password_confirm } properties: otp: type: string description: 6-digit OTP received via SMS maxLength: 6 required: - otp AuthPasswordResetConfirmPhoneRequest: type: object description: |- Serializer for confirming password reset via phone OTP. OTP-ONLY design (mirrors VerifyOTPView pattern exactly): - Client sends ONLY: otp + new_password + new_password_confirm. - phone is NOT required in the body — the service discovers the user via OTPService.verify_by_otp_sync(otp, purpose='password_reset'), which uses an O(1) SHA-256 hash index lookup in Redis: otp_hash:{sha256(otp)} → otp:{user_id}:password_reset:{snippet} - This prevents account enumeration: an attacker cannot test whether a phone number has an account by observing different error responses. Redis key schema (written during reset-request): Primary : otp:{user_id}:password_reset:{snippet} Value = "{encrypted_otp}|{sha256_hex}" Secondary: otp_hash:{sha256_hex} → primary_key (TTL = 300 s) Field names match Zod PasswordResetConfirmPhoneSchema exactly: Frontend sends: { otp, new_password, new_password_confirm } properties: otp: type: string minLength: 1 description: 6-digit OTP received via SMS maxLength: 6 new_password: type: string writeOnly: true minLength: 1 description: New password new_password_confirm: type: string writeOnly: true minLength: 1 description: Confirm new password required: - new_password - new_password_confirm - otp AuthPasswordResetRequestRequest: type: object description: |- Serializer for requesting password reset. Uses all_with_deleted() so soft-deleted users can still trigger a reset. Anti-enumeration: always returns 200 regardless of whether user exists. properties: email_or_phone: type: string writeOnly: true minLength: 1 description: User's email or phone for password reset required: - email_or_phone AuthProtectedUser: type: object description: |- Expose safe, non-sensitive user information for authenticated profile reads. Used by endpoints that share user data with other users or services. Never exposes: password, groups, permissions, auth_provider, is_staff, internal timestamps, or any security-sensitive field. Fields returned: user_id → str (UUID) member_id → str | null email → str | null phone → str | null (E.164) first_name → str last_name → str role → str is_verified → bool is_active → bool avatar → str | null (Cloudinary URL) bio → str country → str state → str city → str address → str date_joined → ISO-8601 | null properties: user_id: type: string readOnly: true member_id: type: string readOnly: true nullable: true description: Unique human-readable brand ID (e.g. FASTAR000062). Auto-generated on user creation. Cannot be changed. email: type: string format: email readOnly: true nullable: true title: Email address description: Primary unique identifier for email-based auth. phone: type: string readOnly: true first_name: type: string readOnly: true default: '' last_name: type: string readOnly: true default: '' role: allOf: - $ref: '#/components/schemas/RoleC2fEnum' readOnly: true description: RBAC Role. Cannot be changed after creation. is_verified: type: boolean readOnly: true description: True if email/phone OTP is verified. is_active: type: boolean readOnly: true description: True if user account is active. avatar: type: string readOnly: true bio: type: string readOnly: true description: User's biography. country: type: string readOnly: true description: User's country. state: type: string readOnly: true description: User's state or province. city: type: string readOnly: true description: User's city. address: type: string readOnly: true description: User's street address. date_joined: type: string format: date-time readOnly: true required: - address - avatar - bio - city - country - date_joined - email - first_name - is_active - is_verified - last_name - member_id - phone - role - state - user_id AuthProviderEnum: enum: - email - phone - google type: string AuthResendOTPRequestRequest: type: object description: |- Serializer for requesting OTP resend by email or phone. CRITICAL FIX: Uses ``all_with_deleted()`` manager so that users who just registered (is_active=False, is_verified=False) are found. A newly-registered unverified user IS alive — they just haven't been activated yet. properties: email_or_phone: type: string writeOnly: true minLength: 1 description: User's email or phone for resend OTP required: - email_or_phone AuthTokenRefresh: type: object description: Wraps SimpleJWT token refresh for drf-yasg Swagger schema generation. properties: refresh: type: string description: A valid refresh token previously issued by the login endpoint. required: - refresh AuthTokenRefreshRequest: type: object description: Wraps SimpleJWT token refresh for drf-yasg Swagger schema generation. properties: refresh: type: string minLength: 1 description: A valid refresh token previously issued by the login endpoint. required: - refresh AuthUserProfile: type: object description: |- Full profile serializer for self-update (PATCH /api/v1/profile/me/). Read-only fields: id, member_id, email, phone, role, auth_provider, is_verified, is_active, is_staff, is_superuser, date_joined, last_login, password, groups, user_permissions Writable fields (matches PROFILE_EDITABLE_FIELDS in profile_service): first_name, last_name, bio, country, state, city, address, avatar Extra output fields (computed): user_id → str(uuid) identifying_info → str phone_display → E.164 string | null (read-only convenience field) avatar_url → Cloudinary URL string | null properties: user_id: type: string readOnly: true identifying_info: type: string readOnly: true id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. member_id: type: string readOnly: true nullable: true description: Unique human-readable brand ID (e.g. FASTAR000062). Auto-generated on user creation. Cannot be changed. email: type: string format: email readOnly: true nullable: true title: Email address description: Primary unique identifier for email-based auth. phone_display: type: string readOnly: true role: allOf: - $ref: '#/components/schemas/RoleC2fEnum' readOnly: true description: RBAC Role. Cannot be changed after creation. auth_provider: allOf: - $ref: '#/components/schemas/AuthProviderEnum' readOnly: true description: Authentication provider used at signup. is_verified: type: boolean readOnly: true description: True if email/phone OTP is verified. is_active: type: boolean readOnly: true description: True if user account is active. is_staff: type: boolean readOnly: true title: Staff status description: Designates whether the user can log into this admin site. first_name: type: string nullable: true last_name: type: string nullable: true bio: type: string description: User's biography. country: type: string description: User's country. maxLength: 100 state: type: string description: User's state or province. maxLength: 100 city: type: string description: User's city. maxLength: 100 address: type: string description: User's street address. maxLength: 255 avatar: type: string nullable: true description: 'Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. In admin: use the file picker widget to upload directly to Cloudinary.' avatar_url: type: string readOnly: true date_joined: type: string format: date-time readOnly: true last_login: type: string format: date-time readOnly: true required: - auth_provider - avatar_url - date_joined - email - id - identifying_info - is_active - is_staff - is_verified - last_login - member_id - phone_display - role - user_id AuthUserProfileRequest: type: object description: |- Full profile serializer for self-update (PATCH /api/v1/profile/me/). Read-only fields: id, member_id, email, phone, role, auth_provider, is_verified, is_active, is_staff, is_superuser, date_joined, last_login, password, groups, user_permissions Writable fields (matches PROFILE_EDITABLE_FIELDS in profile_service): first_name, last_name, bio, country, state, city, address, avatar Extra output fields (computed): user_id → str(uuid) identifying_info → str phone_display → E.164 string | null (read-only convenience field) avatar_url → Cloudinary URL string | null properties: first_name: type: string nullable: true last_name: type: string nullable: true bio: type: string description: User's biography. country: type: string description: User's country. maxLength: 100 state: type: string description: User's state or province. maxLength: 100 city: type: string description: User's city. maxLength: 100 address: type: string description: User's street address. maxLength: 255 avatar: type: string minLength: 1 nullable: true description: 'Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. In admin: use the file picker widget to upload directly to Cloudinary.' AuthUserRegistration: type: object description: |- Serializer for creating a new user account. Validation Logic: - Enforces One-of-Email-or-Phone. - Password strength validation via Django standard. - Duplicate check against active and soft-deleted pools. Security: - Atomic transaction check to prevent race-condition duplicates. properties: email: type: string format: email description: User's email address phone: type: string description: User's phone number role: allOf: - $ref: '#/components/schemas/Role09fEnum' description: 'User''s role: ''vendor'' or ''client''' first_name: type: string description: User's first name maxLength: 150 last_name: type: string description: User's last name maxLength: 150 required: - role AuthUserRegistrationRequest: type: object description: |- Serializer for creating a new user account. Validation Logic: - Enforces One-of-Email-or-Phone. - Password strength validation via Django standard. - Duplicate check against active and soft-deleted pools. Security: - Atomic transaction check to prevent race-condition duplicates. properties: email: type: string format: email description: User's email address phone: type: string description: User's phone number role: allOf: - $ref: '#/components/schemas/Role09fEnum' description: 'User''s role: ''vendor'' or ''client''' first_name: type: string description: User's first name maxLength: 150 last_name: type: string description: User's last name maxLength: 150 password: type: string writeOnly: true minLength: 1 description: User's password password2: type: string writeOnly: true minLength: 1 description: Confirm user's password required: - password - password2 - role BankAccountCreate: type: object properties: account_number: type: string pattern: ^\d{10}$ bank_code: type: string maxLength: 10 bank_name: type: string maxLength: 150 account_name: type: string description: Account holder name as resolved by Paystack. maxLength: 200 required: - account_name - account_number - bank_code - bank_name BankAccountCreateRequest: type: object properties: account_number: type: string minLength: 1 pattern: ^\d{10}$ bank_code: type: string minLength: 1 maxLength: 10 bank_name: type: string minLength: 1 maxLength: 150 account_name: type: string minLength: 1 description: Account holder name as resolved by Paystack. maxLength: 200 required: - account_name - account_number - bank_code - bank_name BankAccountOutput: type: object description: Safe serializer — never returns full account_number or enc bytes. properties: id: type: string format: uuid bank_name: type: string bank_code: type: string account_name: type: string account_last4: type: string masked_account: type: string paystack_recipient_code: type: string kyc_name_matched: type: boolean is_default: type: boolean verification_status: type: string is_verified: type: boolean created_at: type: string format: date-time required: - account_last4 - account_name - bank_code - bank_name - created_at - id - is_default - is_verified - kyc_name_matched - masked_account - paystack_recipient_code - verification_status BankAccountResolve: type: object properties: account_number: type: string pattern: ^\d{10}$ bank_code: type: string pattern: ^\d{3,10}$ required: - account_number - bank_code BankAccountResolveRequest: type: object properties: account_number: type: string minLength: 1 pattern: ^\d{10}$ bank_code: type: string minLength: 1 pattern: ^\d{3,10}$ required: - account_number - bank_code BespokeConsultationRequestRequest: type: object description: Serializer for booking bespoke tailoring consultation. properties: tailoring_type: type: string minLength: 1 description: Required bespoke item type (e.g. suit, gown, coat) preferred_date: type: string format: date description: Preferred date preferred_time: type: string minLength: 1 description: Preferred time slot urgency: allOf: - $ref: '#/components/schemas/UrgencyEnum' default: medium description: Urgency level design_details: type: string minLength: 1 description: Details of design ideas or reference requests BlankEnum: enum: - '' BusinessMetric: type: object properties: id: type: integer readOnly: true metric_name: type: string title: Business Metric Name maxLength: 100 value: type: number format: double period_start: type: string format: date-time period_end: type: string format: date-time metadata: {} created_at: type: string format: date-time readOnly: true required: - created_at - id - metric_name - period_end - period_start - value CashConfirmationConfirm: type: object properties: order_id: type: string maxLength: 120 client_token: type: string maxLength: 255 required: - client_token - order_id CashConfirmationConfirmRequest: type: object properties: order_id: type: string minLength: 1 maxLength: 120 client_token: type: string minLength: 1 maxLength: 255 required: - client_token - order_id CashConfirmationCreate: type: object properties: order_id: type: string maxLength: 120 required: - order_id CashConfirmationCreateRequest: type: object properties: order_id: type: string minLength: 1 maxLength: 120 required: - order_id CashConfirmationResend: type: object properties: order_id: type: string maxLength: 120 required: - order_id CashConfirmationResendRequest: type: object properties: order_id: type: string minLength: 1 maxLength: 120 required: - order_id CashPaymentModeEnum: enum: - disabled - cod - pay_at_shop - both type: string CatalogBlogMedia: type: object description: |- Read-optimised serialiser for BlogMedia gallery items. Exposes derived `public_id` and `image_url` fields sourced from the Cloudinary CloudinaryField. The raw `image` (CloudinaryField) is intentionally omitted from `fields` to avoid the DRF assertion that fires when a model property shares a name with a declared SerializerMethodField (image_url). Architecture note: ─ Uploads use the two-phase direct-upload pattern: 1. Frontend → POST /api/v1/upload/presign/ → signed token 2. Frontend POSTs file directly to Cloudinary (bypasses Django) 3. Cloudinary webhook → Celery task reconciles public_id here ─ `image_url` returns the full HTTPS secure_url from Cloudinary. properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. public_id: type: string readOnly: true image_url: type: string readOnly: true alt_text: type: string maxLength: 180 sort_order: type: integer maximum: 9223372036854775807 minimum: 0 format: int64 created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - created_at - id - image_url - public_id - updated_at CatalogBlogMediaRequest: type: object description: |- Read-optimised serialiser for BlogMedia gallery items. Exposes derived `public_id` and `image_url` fields sourced from the Cloudinary CloudinaryField. The raw `image` (CloudinaryField) is intentionally omitted from `fields` to avoid the DRF assertion that fires when a model property shares a name with a declared SerializerMethodField (image_url). Architecture note: ─ Uploads use the two-phase direct-upload pattern: 1. Frontend → POST /api/v1/upload/presign/ → signed token 2. Frontend POSTs file directly to Cloudinary (bypasses Django) 3. Cloudinary webhook → Celery task reconciles public_id here ─ `image_url` returns the full HTTPS secure_url from Cloudinary. properties: alt_text: type: string maxLength: 180 sort_order: type: integer maximum: 9223372036854775807 minimum: 0 format: int64 CatalogBlogPost: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. author: type: string format: uuid description: Author is retained as nullable to preserve published history. readOnly: true nullable: true author_name: type: string readOnly: true category: type: string format: uuid description: Optional catalog category used for discovery and SEO. nullable: true category_name: type: string readOnly: true title: type: string maxLength: 255 slug: type: string readOnly: true pattern: ^[-a-zA-Z0-9_]+$ excerpt: type: string content: type: string featured_image: type: string nullable: true description: Featured post image (public_id). featured_image_url: type: string readOnly: true image_url: type: string readOnly: true gallery_media: type: array items: $ref: '#/components/schemas/CatalogBlogMedia' readOnly: true status: $ref: '#/components/schemas/CatalogBlogPostStatusEnum' tags: {} seo_title: type: string maxLength: 180 seo_description: type: string maxLength: 320 is_featured: type: boolean published_at: type: string format: date-time readOnly: true nullable: true view_count: type: integer readOnly: true created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - author - author_name - category_name - content - created_at - featured_image_url - gallery_media - id - image_url - published_at - slug - title - updated_at - view_count CatalogBlogPostRequest: type: object properties: category: type: string format: uuid description: Optional catalog category used for discovery and SEO. nullable: true title: type: string minLength: 1 maxLength: 255 excerpt: type: string content: type: string minLength: 1 featured_image: type: string minLength: 1 nullable: true description: Featured post image (public_id). status: $ref: '#/components/schemas/CatalogBlogPostStatusEnum' tags: {} seo_title: type: string maxLength: 180 seo_description: type: string maxLength: 320 is_featured: type: boolean required: - content - title CatalogBlogPostStatusEnum: enum: - draft - review - published - archived type: string CatalogBrand: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. name: type: string readOnly: true title: type: string maxLength: 100 slug: type: string readOnly: true nullable: true pattern: ^[-a-zA-Z0-9_]+$ description: type: string nullable: true image: type: string nullable: true description: Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. image_url: type: string readOnly: true active: type: boolean created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - created_at - id - image_url - name - slug - title - updated_at CatalogBrandRequest: type: object properties: title: type: string minLength: 1 maxLength: 100 description: type: string nullable: true image: type: string minLength: 1 nullable: true description: Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. active: type: boolean required: - title CatalogCategory: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. name: type: string maxLength: 100 title: type: string readOnly: true slug: type: string readOnly: true nullable: true pattern: ^[-a-zA-Z0-9_]+$ image: type: string nullable: true description: Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. image_url: type: string readOnly: true is_deleted: type: boolean description: Flag indicating if the record is soft-deleted. created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - created_at - id - image_url - name - slug - title - updated_at CatalogCategoryRequest: type: object properties: name: type: string minLength: 1 maxLength: 100 image: type: string minLength: 1 nullable: true description: Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. is_deleted: type: boolean description: Flag indicating if the record is soft-deleted. required: - name CatalogCollection: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. name: type: string readOnly: true title: type: string nullable: true maxLength: 255 slug: type: string readOnly: true nullable: true pattern: ^[-a-zA-Z0-9_]+$ sub_title: type: string nullable: true maxLength: 255 description: type: string nullable: true image: type: string nullable: true description: Main collection thumbnail image (public_id). image_url: type: string readOnly: true background_image: type: string nullable: true description: Hero background image (public_id). background_image_url: type: string readOnly: true created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - background_image_url - created_at - id - image_url - name - slug - updated_at CatalogCollectionRequest: type: object properties: title: type: string nullable: true maxLength: 255 sub_title: type: string nullable: true maxLength: 255 description: type: string nullable: true image: type: string minLength: 1 nullable: true description: Main collection thumbnail image (public_id). background_image: type: string minLength: 1 nullable: true description: Hero background image (public_id). ChatbotResponseData: type: object description: Serializer for formatted chatbot responses. properties: content: type: string description: Response content message_type: type: string description: Message type response_data: description: Structured response data ai_confidence: type: number format: double description: AI confidence score processing_time: type: number format: double description: Processing time in seconds quick_replies: type: array items: type: object additionalProperties: {} description: Suggested quick replies required: - content - message_type ChatbotSession: type: object description: Serializer for chatbot sessions. properties: id: type: string format: uuid readOnly: true user: allOf: - $ref: '#/components/schemas/UserBasic' readOnly: true session_type: $ref: '#/components/schemas/SessionTypeEnum' status: $ref: '#/components/schemas/ChatbotSessionStatusEnum' context_data: description: Contextual info to maintain conversation state started_at: type: string format: date-time readOnly: true last_activity: type: string format: date-time readOnly: true ended_at: type: string format: date-time nullable: true expires_at: type: string format: date-time nullable: true duration: type: string readOnly: true is_active: type: string readOnly: true conversation_count: type: string readOnly: true metadata: {} required: - conversation_count - duration - id - is_active - last_activity - session_type - started_at - user ChatbotSessionRequest: type: object description: Serializer for chatbot sessions. properties: session_type: $ref: '#/components/schemas/SessionTypeEnum' status: $ref: '#/components/schemas/ChatbotSessionStatusEnum' context_data: description: Contextual info to maintain conversation state ended_at: type: string format: date-time nullable: true expires_at: type: string format: date-time nullable: true metadata: {} required: - session_type ChatbotSessionStatusEnum: enum: - active - paused - completed - expired type: string ClientAddress: type: object description: Read/Write serializer for ClientAddress. properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. label: type: string description: 'Short label: ''Home'', ''Office'', or ''Mum\''s place''.' maxLength: 80 full_name: type: string maxLength: 150 phone: type: string maxLength: 30 street_address: type: string description: Street, house number, landmark. city: type: string maxLength: 100 state: type: string maxLength: 100 country: type: string maxLength: 100 postal_code: type: string maxLength: 20 is_default: type: boolean description: True if this is the primary address shown at checkout. created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. required: - city - created_at - id - state - street_address ClientAddressRequest: type: object description: Read/Write serializer for ClientAddress. properties: label: type: string description: 'Short label: ''Home'', ''Office'', or ''Mum\''s place''.' maxLength: 80 full_name: type: string maxLength: 150 phone: type: string maxLength: 30 street_address: type: string minLength: 1 description: Street, house number, landmark. city: type: string minLength: 1 maxLength: 100 state: type: string minLength: 1 maxLength: 100 country: type: string minLength: 1 maxLength: 100 postal_code: type: string maxLength: 20 is_default: type: boolean description: True if this is the primary address shown at checkout. required: - city - state - street_address ClientCartOrder: type: object properties: id: type: string readOnly: true oid: type: string readOnly: true sub_total: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true shipping_amount: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true service_fee: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true total: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true payment_status: type: string readOnly: true order_status: type: string readOnly: true delivery_status: type: string readOnly: true tracking_id: type: string readOnly: true date: type: string format: date-time readOnly: true orderitem: type: array items: $ref: '#/components/schemas/ClientOrderItem' readOnly: true required: - date - delivery_status - id - oid - order_status - orderitem - payment_status - service_fee - shipping_amount - sub_total - total - tracking_id ClientOrderItem: type: object properties: id: type: string readOnly: true product: type: string readOnly: true product_title: type: string readOnly: true product_image: type: string readOnly: true qty: type: integer readOnly: true price: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true sub_total: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true shipping_amount: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true service_fee: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true total: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true date: type: string format: date-time readOnly: true required: - date - id - price - product - product_image - product_title - qty - service_fee - shipping_amount - sub_total - total ClientProfileOutput: type: object description: Full read-only profile serializer — used in GET /profile/ responses. properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. user_id: type: string readOnly: true user_email: type: string readOnly: true bio: type: string readOnly: true description: Short personal bio (max 500 chars). default_shipping_address: type: string readOnly: true description: Default shipping address for checkout. state: type: string readOnly: true country: type: string readOnly: true preferred_size: allOf: - $ref: '#/components/schemas/PreferredSizeEnum' readOnly: true description: Preferred clothing size. style_preferences: readOnly: true description: 'Style tags: ["casual", "afrocentric", "formal"]. Used by AI engine.' favourite_colours: readOnly: true description: Favourite colour hex codes or names. total_orders: type: integer readOnly: true total_spent_ngn: type: string format: decimal pattern: ^-?\d{0,12}(?:\.\d{0,2})?$ readOnly: true is_profile_complete: type: boolean readOnly: true description: True once size, address, and style preferences are filled in. email_notifications_enabled: type: boolean readOnly: true description: Receive order and promo email notifications. sms_notifications_enabled: type: boolean readOnly: true description: Receive SMS alerts for order updates. created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. addresses: type: array items: {} readOnly: true required: - addresses - bio - country - created_at - default_shipping_address - email_notifications_enabled - favourite_colours - id - is_profile_complete - preferred_size - sms_notifications_enabled - state - style_preferences - total_orders - total_spent_ngn - updated_at - user_email - user_id ClientProfileUpdate: type: object description: |- Input-only serializer for PATCH /profile/ requests. All fields are optional — clients send only what they want to change. properties: bio: type: string maxLength: 500 default_shipping_address: type: string state: type: string maxLength: 100 country: type: string maxLength: 100 preferred_size: oneOf: - $ref: '#/components/schemas/PreferredSizeEnum' - $ref: '#/components/schemas/BlankEnum' style_preferences: type: array items: type: string favourite_colours: type: array items: type: string email_notifications_enabled: type: boolean sms_notifications_enabled: type: boolean ClientProfileUpdateRequest: type: object description: |- Input-only serializer for PATCH /profile/ requests. All fields are optional — clients send only what they want to change. properties: bio: type: string maxLength: 500 default_shipping_address: type: string state: type: string maxLength: 100 country: type: string maxLength: 100 preferred_size: oneOf: - $ref: '#/components/schemas/PreferredSizeEnum' - $ref: '#/components/schemas/BlankEnum' style_preferences: type: array items: type: string minLength: 1 favourite_colours: type: array items: type: string minLength: 1 email_notifications_enabled: type: boolean sms_notifications_enabled: type: boolean ClientReview: type: object properties: id: type: string readOnly: true user: type: string readOnly: true user_full_name: type: string readOnly: true user_avatar: type: string readOnly: true product: type: string readOnly: true product_title: type: string readOnly: true review: type: string maxLength: 2000 rating: type: integer maximum: 5 minimum: 1 active: type: boolean readOnly: true date: type: string format: date-time readOnly: true required: - active - date - id - product - product_title - rating - review - user - user_avatar - user_full_name ClientReviewRequest: type: object properties: product_id: type: string format: uuid writeOnly: true review: type: string minLength: 1 maxLength: 2000 rating: type: integer maximum: 5 minimum: 1 required: - rating - review ClientWishlist: type: object properties: id: type: string readOnly: true product: allOf: - $ref: '#/components/schemas/WishlistProduct' readOnly: true date: type: string format: date-time readOnly: true required: - date - id - product CommonContactSubmission: type: object description: Input serializer for POST /api/v1/public/contact/. properties: full_name: type: string maxLength: 120 minLength: 2 email: type: string format: email phone: type: string maxLength: 40 subject: type: string maxLength: 120 message: type: string maxLength: 5000 minLength: 10 vendor: type: string maxLength: 120 inquiry_type: type: string maxLength: 60 page_url: type: string format: uri maxLength: 500 required: - email - full_name - message CommonContactSubmissionRequest: type: object description: Input serializer for POST /api/v1/public/contact/. properties: full_name: type: string minLength: 2 maxLength: 120 email: type: string format: email minLength: 1 phone: type: string maxLength: 40 subject: type: string maxLength: 120 message: type: string minLength: 10 maxLength: 5000 vendor: type: string maxLength: 120 inquiry_type: type: string maxLength: 60 page_url: type: string format: uri maxLength: 500 required: - email - full_name - message CommonNewsletterSignup: type: object description: Input serializer for POST /api/v1/public/newsletter/. properties: email: type: string format: email source: type: string default: newsletter maxLength: 80 required: - email CommonNewsletterSignupRequest: type: object description: Input serializer for POST /api/v1/public/newsletter/. properties: email: type: string format: email minLength: 1 source: type: string default: newsletter maxLength: 80 required: - email CommonPresignRequest: type: object description: |- Input serializer for POST /api/v1/upload/presign/ Validates the ``asset_type`` field before passing to ``generate_cloudinary_upload_params()``. Replaces the previous raw ``request.data.get("asset_type", "avatar")`` pattern with typed DRF validation that surfaces a proper 400 with field-level errors. Valid asset_types are derived dynamically from _ASSET_CONFIGS so the serializer stays in sync if new asset types are added. properties: asset_type: allOf: - $ref: '#/components/schemas/AssetTypeEnum' default: avatar description: 'Type of Cloudinary asset to upload. One of: avatar, product_image, product_video, measurement.' CommonPresignRequestRequest: type: object description: |- Input serializer for POST /api/v1/upload/presign/ Validates the ``asset_type`` field before passing to ``generate_cloudinary_upload_params()``. Replaces the previous raw ``request.data.get("asset_type", "avatar")`` pattern with typed DRF validation that surfaces a proper 400 with field-level errors. Valid asset_types are derived dynamically from _ASSET_CONFIGS so the serializer stays in sync if new asset types are added. properties: asset_type: allOf: - $ref: '#/components/schemas/AssetTypeEnum' default: avatar description: 'Type of Cloudinary asset to upload. One of: avatar, product_image, product_video, measurement.' CommonWaitlistSignup: type: object description: Input serializer for POST /api/v1/public/waitlist/. properties: email: type: string format: email source: type: string default: waitlist maxLength: 80 required: - email CommonWaitlistSignupRequest: type: object description: Input serializer for POST /api/v1/public/waitlist/. properties: email: type: string format: email minLength: 1 source: type: string default: waitlist maxLength: 80 required: - email Conversation: type: object description: Serializer for conversations including message history. properties: id: type: string format: uuid readOnly: true session: allOf: - $ref: '#/components/schemas/ChatbotSession' readOnly: true conversation_type: $ref: '#/components/schemas/ConversationTypeEnum' title: type: string maxLength: 200 is_active: type: boolean started_at: type: string format: date-time readOnly: true updated_at: type: string format: date-time readOnly: true summary: type: string tags: {} messages: type: array items: $ref: '#/components/schemas/Message' readOnly: true message_count: type: string readOnly: true last_message_time: type: string readOnly: true metadata: {} required: - id - last_message_time - message_count - messages - session - started_at - updated_at ConversationRequest: type: object description: Serializer for conversations including message history. properties: conversation_type: $ref: '#/components/schemas/ConversationTypeEnum' title: type: string maxLength: 200 is_active: type: boolean summary: type: string tags: {} metadata: {} ConversationTypeEnum: enum: - style_advice - size_recommendation - product_search - order_inquiry - general_support - general type: string DeliveryStatusEnum: enum: - pending - processing - shipped - fulfilled - cancelled type: string DeliveryStatusUpdate: type: object properties: delivery_status: type: string maxLength: 100 tracking_id: type: string maxLength: 255 DeliveryStatusUpdateRequest: type: object properties: delivery_status: type: string minLength: 1 maxLength: 100 tracking_id: type: string minLength: 1 maxLength: 255 DirectionEnum: enum: - inbound - outbound - internal type: string DisputeCreate: type: object properties: reason: type: string amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ required: - amount - reason DisputeCreateRequest: type: object properties: reason: type: string minLength: 1 amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ required: - amount - reason DocumentTypeEnum: enum: - nin_card - bvn_slip - passport - drivers_license - voters_card - selfie - cac_certificate - utility_bill type: string EnvironmentEnum: enum: - development - staging - production type: string EscrowHold: type: object properties: amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ reference: type: string maxLength: 120 order_id: type: string maxLength: 120 provider_reference: type: string maxLength: 120 required: - amount - reference EscrowHoldRequest: type: object properties: amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ reference: type: string minLength: 1 maxLength: 120 order_id: type: string maxLength: 120 provider_reference: type: string maxLength: 120 required: - amount - reference EscrowRefund: type: object properties: hold_reference: type: string maxLength: 120 required: - hold_reference EscrowRefundRequest: type: object properties: hold_reference: type: string minLength: 1 maxLength: 120 required: - hold_reference EscrowRelease: type: object properties: hold_reference: type: string maxLength: 120 vendor_user_id: type: string format: uuid commission_rate: type: string format: decimal pattern: ^-?\d{0,1}(?:\.\d{0,4})?$ default: '0.1000' required: - hold_reference EscrowReleaseRequest: type: object properties: hold_reference: type: string minLength: 1 maxLength: 120 vendor_user_id: type: string format: uuid commission_rate: type: string format: decimal pattern: ^-?\d{0,1}(?:\.\d{0,4})?$ default: '0.1000' required: - hold_reference GenderEnum: enum: - M - F - O type: string IntegrationCredential: type: object properties: id: type: string format: uuid readOnly: true provider: type: string format: uuid provider_name: type: string readOnly: true key_name: type: string maxLength: 100 masked_value: type: string readOnly: true is_encrypted: type: boolean environment: allOf: - $ref: '#/components/schemas/EnvironmentEnum' default: production is_active: type: boolean is_valid: type: boolean readOnly: true expires_at: type: string format: date-time nullable: true created_at: type: string format: date-time readOnly: true updated_at: type: string format: date-time readOnly: true created_by: type: string format: uuid description: UUID7 — globally unique, time-ordered primary key. readOnly: true nullable: true required: - created_at - created_by - id - is_valid - key_name - masked_value - provider - provider_name - updated_at IntegrationCredentialRequest: type: object properties: provider: type: string format: uuid key_name: type: string minLength: 1 maxLength: 100 key_value: type: string writeOnly: true minLength: 1 description: Stored in encrypted format. is_encrypted: type: boolean environment: allOf: - $ref: '#/components/schemas/EnvironmentEnum' default: production is_active: type: boolean expires_at: type: string format: date-time nullable: true required: - key_name - key_value - provider IntegrationLog: type: object properties: id: type: string format: uuid readOnly: true provider: type: string format: uuid provider_name: type: string readOnly: true log_level: $ref: '#/components/schemas/LogLevelEnum' service_name: type: string maxLength: 100 action: type: string maxLength: 100 request_data: {} response_data: {} error_message: type: string status_code: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 nullable: true duration_ms: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 nullable: true title: Duration (ms) user: type: string format: uuid description: UUID7 — globally unique, time-ordered primary key. nullable: true user_name: type: string nullable: true readOnly: true ip_address: type: string nullable: true created_at: type: string format: date-time readOnly: true title: Logged At required: - action - created_at - id - provider - provider_name - service_name - user_name IntegrationProvider: type: object properties: id: type: string format: uuid readOnly: true name: type: string title: Provider Name maxLength: 100 slug: type: string title: Unique Slug maxLength: 50 pattern: ^[-a-zA-Z0-9_]+$ provider_type: allOf: - $ref: '#/components/schemas/ProviderTypeEnum' title: Service Type status: $ref: '#/components/schemas/IntegrationProviderStatusEnum' description: type: string api_base_url: type: string format: uri maxLength: 200 documentation_url: type: string format: uri maxLength: 200 credentials_count: type: integer readOnly: true logs_count: type: integer readOnly: true created_at: type: string format: date-time readOnly: true updated_at: type: string format: date-time readOnly: true required: - created_at - credentials_count - id - logs_count - name - provider_type - slug - updated_at IntegrationProviderRequest: type: object properties: name: type: string minLength: 1 title: Provider Name maxLength: 100 slug: type: string minLength: 1 title: Unique Slug maxLength: 50 pattern: ^[-a-zA-Z0-9_]+$ provider_type: allOf: - $ref: '#/components/schemas/ProviderTypeEnum' title: Service Type status: $ref: '#/components/schemas/IntegrationProviderStatusEnum' description: type: string api_base_url: type: string format: uri maxLength: 200 documentation_url: type: string format: uri maxLength: 200 required: - name - provider_type - slug IntegrationProviderStatusEnum: enum: - active - inactive - maintenance type: string KycDocument: type: object description: Read serializer for a single KYC document. properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. document_type: allOf: - $ref: '#/components/schemas/DocumentTypeEnum' readOnly: true document_number: type: string readOnly: true description: The actual document number, e.g. NIN (11 digits), BVN, passport number. Encrypt at-rest in production. secure_url: type: string format: uri readOnly: true description: Cloudinary secure_url returned after client-side upload. public_id: type: string readOnly: true description: Cloudinary public_id returned after client-side upload. provider_verified: type: boolean readOnly: true description: True if the external KYC provider confirms this document is valid. provider_response: readOnly: true description: Raw JSON result from external KYC provider for this document. created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. required: - created_at - document_number - document_type - id - provider_response - provider_verified - public_id - secure_url KycSubmission: type: object description: |- Read serializer for a KycSubmission including nested documents. Used for GET /api/v1/kyc/status/ and detail views. properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. user: type: string readOnly: true status: allOf: - $ref: '#/components/schemas/KycSubmissionStatusEnum' readOnly: true is_approved: type: boolean readOnly: true is_pending: type: boolean readOnly: true is_rejected: type: boolean readOnly: true can_resubmit: type: boolean readOnly: true review_notes: type: string readOnly: true provider_reference: type: string readOnly: true description: External KYC provider job/session reference ID. submitted_at: type: string format: date-time readOnly: true reviewed_at: type: string format: date-time readOnly: true nullable: true documents: type: array items: $ref: '#/components/schemas/KycDocument' readOnly: true created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - can_resubmit - created_at - documents - id - is_approved - is_pending - is_rejected - provider_reference - review_notes - reviewed_at - status - submitted_at - updated_at - user KycSubmissionStatusEnum: enum: - pending - in_review - approved - rejected - resubmit type: string LogLevelEnum: enum: - debug - info - warning - error - critical type: string LoginEvent: type: object description: |- Read serializer for LoginEvent — used by the login activity list. Analogous to Binance's "Login Activity" or Google's "Recent Security Events" dashboard panel. All UUID7 primary keys are serialized as strings. ``timestamp`` is an alias for ``created_at`` (audit-log convention). properties: id: type: string readOnly: true outcome: allOf: - $ref: '#/components/schemas/OutcomeEnum' readOnly: true description: Result of the login attempt. is_successful: type: boolean readOnly: true description: True iff the login attempt succeeded and tokens were issued. failure_reason: type: string readOnly: true description: 'Short machine-readable failure code: ''invalid_credentials'', ''account_inactive'', ''account_deleted'', ''rate_limited'', ''mfa_required'', etc.' auth_method: allOf: - $ref: '#/components/schemas/AuthMethodEnum' readOnly: true description: Authentication method used for this attempt. ip_address: type: string readOnly: true description: Client IP address (supports IPv4 and IPv6). country: type: string readOnly: true description: Country name derived from IP (via MaxMind / ipapi). country_code: type: string readOnly: true description: ISO 3166-1 alpha-2 country code (e.g. 'NG', 'US'). city: type: string readOnly: true description: City name (e.g. 'Lagos', 'San Francisco'). client_type: allOf: - $ref: '#/components/schemas/LoginEventClientTypeEnum' readOnly: true description: 'Derived from User-Agent: web / mobile / api / curl.' browser: type: string readOnly: true os: type: string readOnly: true device_type: type: string readOnly: true description: 'Device category: desktop, mobile, tablet, bot, etc.' risk_score: type: integer readOnly: true description: Risk score 0-100. ≥70 triggers a security alert. is_new_device: type: boolean readOnly: true description: True if this is the first time this device fingerprint was seen. is_new_country: type: boolean readOnly: true description: True if the login country is new for this user. is_tor_exit_node: type: boolean readOnly: true description: True if the IP is a known Tor exit node. timestamp: type: string format: date-time readOnly: true required: - auth_method - browser - city - client_type - country - country_code - device_type - failure_reason - id - ip_address - is_new_country - is_new_device - is_successful - is_tor_exit_node - os - outcome - risk_score - timestamp LoginEventClientTypeEnum: enum: - web - mobile - api - curl - unknown type: string Message: type: object description: Serializer for messages. properties: id: type: string format: uuid readOnly: true sender_type: $ref: '#/components/schemas/SenderTypeEnum' message_type: $ref: '#/components/schemas/MessageTypeEnum' content: type: string minLength: 1 response_data: description: Structured options or response details ai_confidence: type: number format: double nullable: true description: Confidence score of AI response (0.0 to 1.0) processing_time: type: number format: double nullable: true description: Processing time in seconds is_sensitive: type: boolean description: Does the message contain sensitive info? created_at: type: string format: date-time readOnly: true edited_at: type: string format: date-time readOnly: true nullable: true is_from_user: type: string readOnly: true is_from_bot: type: string readOnly: true metadata: {} required: - content - created_at - edited_at - id - is_from_bot - is_from_user - sender_type MessageRequest: type: object description: Serializer for messages. properties: sender_type: $ref: '#/components/schemas/SenderTypeEnum' message_type: $ref: '#/components/schemas/MessageTypeEnum' content: type: string minLength: 1 response_data: description: Structured options or response details ai_confidence: type: number format: double nullable: true description: Confidence score of AI response (0.0 to 1.0) processing_time: type: number format: double nullable: true description: Processing time in seconds is_sensitive: type: boolean description: Does the message contain sensitive info? metadata: {} required: - content - sender_type MessageTypeEnum: enum: - text - quick_reply - attachment - card - carousel - typing type: string Metric: type: object properties: id: type: integer readOnly: true name: type: string title: Metric Name description: Name identifier of the metric. maxLength: 255 metric_type: $ref: '#/components/schemas/MetricTypeEnum' value: type: number format: double description: Numeric value of the metric. tags: description: Categorization tags. timestamp: type: string format: date-time readOnly: true required: - id - name - timestamp - value MetricTypeEnum: enum: - counter - gauge - histogram - timer type: string OperatorEnum: enum: - gt - gte - lt - lte - eq - ne type: string OutcomeEnum: enum: - success - failed - blocked - suspicious type: string OwnerTypeEnum: enum: - client - vendor - support - editor - moderator - admin - company type: string PaginatedAlertList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/Alert' PaginatedAlertRuleList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/AlertRule' required: - success - count - next - previous - results PaginatedAuthProtectedUserList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/AuthProtectedUser' required: - success - count - next - previous - results PaginatedBusinessMetricList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/BusinessMetric' PaginatedChatbotSessionList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/ChatbotSession' PaginatedClientAddressList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ClientAddress' required: - success - count - next - previous - results PaginatedClientCartOrderList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ClientCartOrder' required: - success - count - next - previous - results PaginatedConversationList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/Conversation' PaginatedIntegrationCredentialList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/IntegrationCredential' required: - success - count - next - previous - results PaginatedIntegrationLogList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/IntegrationLog' required: - success - count - next - previous - results PaginatedIntegrationProviderList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/IntegrationProvider' required: - success - count - next - previous - results PaginatedKycSubmissionList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/KycSubmission' required: - success - count - next - previous - results PaginatedLoginEventList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/LoginEvent' required: - success - count - next - previous - results PaginatedMessageList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/Message' PaginatedMetricList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/Metric' PaginatedPerformanceMetricList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/PerformanceMetric' PaginatedRateLimitRuleList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/RateLimitRule' required: - success - count - next - previous - results PaginatedReferenceBankList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ReferenceBank' required: - success - count - next - previous - results PaginatedReferenceCityList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ReferenceCity' required: - success - count - next - previous - results PaginatedReferenceCountryList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ReferenceCountry' required: - success - count - next - previous - results PaginatedReferenceLgaList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ReferenceLga' required: - success - count - next - previous - results PaginatedReferenceStateList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/ReferenceState' required: - success - count - next - previous - results PaginatedTransactionList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/Transaction' required: - success - count - next - previous - results PaginatedUserActivityList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/UserActivity' PaginatedUserSessionList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/UserSession' required: - success - count - next - previous - results PaginatedWebhookEndpointList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/WebhookEndpoint' required: - success - count - next - previous - results PaginatedWebhookEventList: type: object properties: success: type: boolean example: true count: type: integer nullable: true pages: type: integer nullable: true page: type: integer nullable: true page_size: type: integer next: type: string format: uri nullable: true previous: type: string format: uri nullable: true results: type: array items: $ref: '#/components/schemas/WebhookEvent' required: - success - count - next - previous - results PasswordChangeRequest: type: object description: |- Serializer for authenticated password change from the dashboard. Validates old password + new password match. properties: old_password: type: string writeOnly: true minLength: 1 description: Current password new_password: type: string writeOnly: true minLength: 1 description: New password confirm_password: type: string writeOnly: true minLength: 1 description: Confirm new password required: - confirm_password - new_password - old_password PatchedAlertRuleRequest: type: object properties: name: type: string minLength: 1 title: Rule Name maxLength: 100 metric_name: type: string minLength: 1 maxLength: 255 operator: allOf: - $ref: '#/components/schemas/OperatorEnum' title: Comparison Operator threshold: type: number format: double severity: $ref: '#/components/schemas/SeverityEnum' is_active: type: boolean description: type: string PatchedAuthUserProfileRequest: type: object description: |- Full profile serializer for self-update (PATCH /api/v1/profile/me/). Read-only fields: id, member_id, email, phone, role, auth_provider, is_verified, is_active, is_staff, is_superuser, date_joined, last_login, password, groups, user_permissions Writable fields (matches PROFILE_EDITABLE_FIELDS in profile_service): first_name, last_name, bio, country, state, city, address, avatar Extra output fields (computed): user_id → str(uuid) identifying_info → str phone_display → E.164 string | null (read-only convenience field) avatar_url → Cloudinary URL string | null properties: first_name: type: string nullable: true last_name: type: string nullable: true bio: type: string description: User's biography. country: type: string description: User's country. maxLength: 100 state: type: string description: User's state or province. maxLength: 100 city: type: string description: User's city. maxLength: 100 address: type: string description: User's street address. maxLength: 255 avatar: type: string minLength: 1 nullable: true description: 'Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. In admin: use the file picker widget to upload directly to Cloudinary.' PatchedCatalogBlogPostRequest: type: object properties: category: type: string format: uuid description: Optional catalog category used for discovery and SEO. nullable: true title: type: string minLength: 1 maxLength: 255 excerpt: type: string content: type: string minLength: 1 featured_image: type: string minLength: 1 nullable: true description: Featured post image (public_id). status: $ref: '#/components/schemas/CatalogBlogPostStatusEnum' tags: {} seo_title: type: string maxLength: 180 seo_description: type: string maxLength: 320 is_featured: type: boolean PatchedCatalogBrandRequest: type: object properties: title: type: string minLength: 1 maxLength: 100 description: type: string nullable: true image: type: string minLength: 1 nullable: true description: Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. active: type: boolean PatchedCatalogCategoryRequest: type: object properties: name: type: string minLength: 1 maxLength: 100 image: type: string minLength: 1 nullable: true description: Cloudinary image public_id. Set via the /api/v1/upload/presign/ → direct upload → webhook flow. Use .url in serializers to retrieve the full HTTPS secure_url. is_deleted: type: boolean description: Flag indicating if the record is soft-deleted. PatchedCatalogCollectionRequest: type: object properties: title: type: string nullable: true maxLength: 255 sub_title: type: string nullable: true maxLength: 255 description: type: string nullable: true image: type: string minLength: 1 nullable: true description: Main collection thumbnail image (public_id). background_image: type: string minLength: 1 nullable: true description: Hero background image (public_id). PatchedChatbotSessionRequest: type: object description: Serializer for chatbot sessions. properties: session_type: $ref: '#/components/schemas/SessionTypeEnum' status: $ref: '#/components/schemas/ChatbotSessionStatusEnum' context_data: description: Contextual info to maintain conversation state ended_at: type: string format: date-time nullable: true expires_at: type: string format: date-time nullable: true metadata: {} PatchedClientProfileUpdateRequest: type: object description: |- Input-only serializer for PATCH /profile/ requests. All fields are optional — clients send only what they want to change. properties: bio: type: string maxLength: 500 default_shipping_address: type: string state: type: string maxLength: 100 country: type: string maxLength: 100 preferred_size: oneOf: - $ref: '#/components/schemas/PreferredSizeEnum' - $ref: '#/components/schemas/BlankEnum' style_preferences: type: array items: type: string minLength: 1 favourite_colours: type: array items: type: string minLength: 1 email_notifications_enabled: type: boolean sms_notifications_enabled: type: boolean PatchedConversationRequest: type: object description: Serializer for conversations including message history. properties: conversation_type: $ref: '#/components/schemas/ConversationTypeEnum' title: type: string maxLength: 200 is_active: type: boolean summary: type: string tags: {} metadata: {} PatchedIntegrationCredentialRequest: type: object properties: provider: type: string format: uuid key_name: type: string minLength: 1 maxLength: 100 key_value: type: string writeOnly: true minLength: 1 description: Stored in encrypted format. is_encrypted: type: boolean environment: allOf: - $ref: '#/components/schemas/EnvironmentEnum' default: production is_active: type: boolean expires_at: type: string format: date-time nullable: true PatchedIntegrationProviderRequest: type: object properties: name: type: string minLength: 1 title: Provider Name maxLength: 100 slug: type: string minLength: 1 title: Unique Slug maxLength: 50 pattern: ^[-a-zA-Z0-9_]+$ provider_type: allOf: - $ref: '#/components/schemas/ProviderTypeEnum' title: Service Type status: $ref: '#/components/schemas/IntegrationProviderStatusEnum' description: type: string api_base_url: type: string format: uri maxLength: 200 documentation_url: type: string format: uri maxLength: 200 PatchedMessageRequest: type: object description: Serializer for messages. properties: sender_type: $ref: '#/components/schemas/SenderTypeEnum' message_type: $ref: '#/components/schemas/MessageTypeEnum' content: type: string minLength: 1 response_data: description: Structured options or response details ai_confidence: type: number format: double nullable: true description: Confidence score of AI response (0.0 to 1.0) processing_time: type: number format: double nullable: true description: Processing time in seconds is_sensitive: type: boolean description: Does the message contain sensitive info? metadata: {} PatchedRateLimitRuleRequest: type: object properties: provider: type: string format: uuid name: type: string minLength: 1 title: Rule Name maxLength: 100 endpoint_pattern: type: string minLength: 1 description: Supports wildcards like * maxLength: 255 max_requests: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 time_window_seconds: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 title: Time Window (Seconds) scope: $ref: '#/components/schemas/ScopeEnum' is_active: type: boolean PatchedVendorOrderStatusRequest: type: object properties: delivery_status: $ref: '#/components/schemas/DeliveryStatusEnum' tracking_id: type: string PatchedVendorProfileUpdateRequest: type: object description: Input-only serializer for PATCH /vendor/profile/. properties: store_name: type: string maxLength: 150 tagline: type: string maxLength: 200 description: type: string maxLength: 2000 logo_url: type: string format: uri cover_url: type: string format: uri city: type: string maxLength: 100 state: type: string maxLength: 100 country: type: string maxLength: 100 whatsapp: type: string maxLength: 20 opening_time: type: string format: time nullable: true closing_time: type: string format: time nullable: true business_hours: {} instagram_url: type: string format: uri tiktok_url: type: string format: uri twitter_url: type: string format: uri website_url: type: string format: uri cash_payment_mode: $ref: '#/components/schemas/CashPaymentModeEnum' collection_ids: type: array items: type: string minLength: 1 description: 1-15 Collection IDs this store specialises in. maxItems: 15 PatchedWebhookEndpointRequest: type: object properties: provider: type: string format: uuid name: type: string minLength: 1 title: Webhook Name maxLength: 100 endpoint_url: type: string minLength: 1 pattern: ^[a-zA-Z0-9-_/]+$ maxLength: 255 secret_key: type: string writeOnly: true minLength: 1 description: Used to verify webhook payload signatures. maxLength: 255 events: title: Subscribed Events description: List of event slugs this webhook processes. is_active: type: boolean retry_count: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 timeout_seconds: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 title: Timeout (Seconds) PaymentPathEnum: enum: - wallet - gateway - cod - pay_at_shop type: string PayoutRequest: type: object properties: bank_account_id: type: string format: uuid description: UUID of the saved VendorBankAccount to pay into. amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ description: Payout amount in NGN. Minimum determined by platform settings. narration: type: string default: Fashionistar Vendor Payout description: Bank transfer narration / description. maxLength: 255 required: - amount - bank_account_id PayoutRequestRequest: type: object properties: bank_account_id: type: string format: uuid description: UUID of the saved VendorBankAccount to pay into. amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ description: Payout amount in NGN. Minimum determined by platform settings. narration: type: string minLength: 1 default: Fashionistar Vendor Payout description: Bank transfer narration / description. maxLength: 255 required: - amount - bank_account_id PaystackBank: type: object properties: name: type: string slug: type: string code: type: string longcode: type: string nullable: true gateway: type: string nullable: true pay_with_bank: type: boolean active: type: boolean is_deleted: type: boolean nullable: true country: type: string currency: type: string type: type: string id: type: integer createdAt: type: string format: date-time updatedAt: type: string format: date-time required: - active - code - country - createdAt - currency - id - name - pay_with_bank - slug - type - updatedAt PaystackBanksResponse: type: object properties: status: type: boolean message: type: string data: type: array items: $ref: '#/components/schemas/PaystackBank' required: - data - message - status PaystackInitialize: type: object properties: amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ purpose: $ref: '#/components/schemas/PurposeEnum' currency: type: string default: NGN maxLength: 10 order_id: type: string maxLength: 120 measurement_request_id: type: string maxLength: 120 metadata: {} required: - amount - purpose PaystackInitializeRequest: type: object properties: amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ purpose: $ref: '#/components/schemas/PurposeEnum' currency: type: string minLength: 1 default: NGN maxLength: 10 order_id: type: string maxLength: 120 measurement_request_id: type: string maxLength: 120 metadata: {} required: - amount - purpose PaystackVerify: type: object properties: reference: type: string maxLength: 120 required: - reference PaystackWebhook: type: object properties: event: type: string data: {} required: - data - event PaystackWebhookRequest: type: object properties: event: type: string minLength: 1 data: {} required: - data - event PerformanceMetric: type: object properties: id: type: integer readOnly: true endpoint: type: string title: Endpoint Route description: Request URL pathway. maxLength: 255 method: type: string title: HTTP Method description: HTTP verb used in the request. maxLength: 10 response_time_ms: type: integer maximum: 9223372036854775807 minimum: 0 format: int64 title: Response Time (ms) status_code: type: integer maximum: 9223372036854775807 minimum: 0 format: int64 title: HTTP Status Code user: type: string format: uuid description: UUID7 — globally unique, time-ordered primary key. nullable: true user_username: type: string readOnly: true error_message: type: string metadata: {} timestamp: type: string format: date-time readOnly: true required: - endpoint - id - method - response_time_ms - status_code - timestamp - user_username PreferredSizeEnum: enum: - XS - S - M - L - XL - XXL - XXXL type: string ProductInquiryRequestRequest: type: object description: Serializer for specific product inquiries. properties: product_sku: type: string minLength: 1 description: Product SKU or Identifier client_size: type: string minLength: 1 description: Preferred size client_height: type: number format: double description: Client height (cm) fabric_preferences: type: array items: type: string minLength: 1 description: Preferred materials or material warnings (e.g. wool allergy) similar_products: type: array items: type: string minLength: 1 description: Similar SKUs of interest required: - product_sku ProviderEnum: enum: - wallet - paystack - flutterwave - olive_pay type: string ProviderTypeEnum: enum: - sms - payment - ai - storage - notification - analytics - other type: string PurposeEnum: enum: - wallet_topup - order_payment - measurement_fee - vendor_service - advertisement_fee type: string RateLimitRule: type: object properties: id: type: string format: uuid readOnly: true provider: type: string format: uuid provider_name: type: string readOnly: true name: type: string title: Rule Name maxLength: 100 endpoint_pattern: type: string description: Supports wildcards like * maxLength: 255 max_requests: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 time_window_seconds: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 title: Time Window (Seconds) scope: $ref: '#/components/schemas/ScopeEnum' is_active: type: boolean rate_description: type: string readOnly: true created_at: type: string format: date-time readOnly: true updated_at: type: string format: date-time readOnly: true required: - created_at - endpoint_pattern - id - max_requests - name - provider - provider_name - rate_description - time_window_seconds - updated_at RateLimitRuleRequest: type: object properties: provider: type: string format: uuid name: type: string minLength: 1 title: Rule Name maxLength: 100 endpoint_pattern: type: string minLength: 1 description: Supports wildcards like * maxLength: 255 max_requests: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 time_window_seconds: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 title: Time Window (Seconds) scope: $ref: '#/components/schemas/ScopeEnum' is_active: type: boolean required: - endpoint_pattern - max_requests - name - provider - time_window_seconds ReferenceBank: type: object properties: id: type: string code: type: string name: type: string country_code: type: string currency: type: string provider: type: string is_active: type: boolean required: - code - country_code - currency - id - is_active - name - provider ReferenceCity: type: object properties: code: type: string name: type: string lga_code: type: string state_code: type: string country_code: type: string latitude: type: number format: double nullable: true longitude: type: number format: double nullable: true is_active: type: boolean required: - code - country_code - is_active - latitude - lga_code - longitude - name - state_code ReferenceCountry: type: object properties: id: type: string code: type: string name: type: string flag: type: string phone_code: type: string is_active: type: boolean required: - code - flag - id - is_active - name - phone_code ReferenceLga: type: object properties: code: type: string name: type: string state_code: type: string country_code: type: string is_active: type: boolean required: - code - country_code - is_active - name - state_code ReferenceState: type: object properties: code: type: string name: type: string country_code: type: string is_active: type: boolean required: - code - country_code - is_active - name Refund: type: object properties: hold_reference: type: string maxLength: 120 required: - hold_reference RefundRequest: type: object properties: hold_reference: type: string minLength: 1 maxLength: 120 required: - hold_reference Role09fEnum: enum: - vendor - client type: string RoleC2fEnum: enum: - vendor - client - staff - admin - editor - support - assistant - moderator - super_admin - super_vendor - super_client - super_staff - super_editor - super_support - super_assistant - super_moderator type: string ScopeEnum: enum: - global - user - ip type: string SendMessageRequestRequest: type: object description: Serializer to validate sending a message. properties: message: type: string minLength: 1 description: User message content maxLength: 4000 message_type: allOf: - $ref: '#/components/schemas/MessageTypeEnum' default: text description: Message type context: description: Additional context for message processing required: - message SendMessageResponse: type: object description: Serializer for the response of sending a message. properties: response: allOf: - $ref: '#/components/schemas/ChatbotResponseData' description: Chatbot response user_message_id: type: string format: uuid description: User message UUID bot_message_id: type: string format: uuid description: Bot message UUID conversation_id: type: string format: uuid description: Conversation UUID session_id: type: string format: uuid description: Session UUID required: - bot_message_id - conversation_id - response - session_id - user_message_id SenderTypeEnum: enum: - user - bot - system type: string SessionTypeEnum: enum: - client - vendor type: string SeverityEnum: enum: - low - medium - high - critical type: string SizeRecommendationRequestRequest: type: object description: Serializer for sizing and fit recommendation requests. properties: measurements: type: array items: type: string minLength: 1 description: List of body measurements height_cm: type: integer maximum: 250 minimum: 0 description: Client height in cm gender: allOf: - $ref: '#/components/schemas/GenderEnum' description: Client gender fit_preference: type: string minLength: 1 description: Preferred fit profile (e.g. slim, regular, loose) prior_purchases: type: array items: type: string minLength: 1 description: Known comfortable sizing in other brands required: - measurements StartSessionResponse: type: object description: Serializer for starting a chatbot session. properties: session: allOf: - $ref: '#/components/schemas/ChatbotSession' description: Session info greeting_message: allOf: - $ref: '#/components/schemas/ChatbotResponseData' description: Greeting message quick_replies: type: array items: type: object additionalProperties: {} description: Initial quick replies required: - session StyleAssessmentRequestRequest: type: object description: Serializer for style and aesthetic assessment. properties: preferred_style: type: string minLength: 1 description: Primary style or aesthetic preference budget_range: type: string minLength: 1 description: Estimated budget range formality_level: type: integer maximum: 10 minimum: 1 description: Formality level (1-10) size_preferences: type: array items: type: string minLength: 1 description: Preferred sizing guidelines sizing_notes: type: string minLength: 1 description: Specific details regarding styling/fit history required: - budget_range - formality_level - preferred_style Transaction: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. transaction_type: $ref: '#/components/schemas/TransactionTypeEnum' status: $ref: '#/components/schemas/TransactionStatusEnum' direction: $ref: '#/components/schemas/DirectionEnum' amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ fee_amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ net_amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ reference: type: string maxLength: 120 external_reference: type: string maxLength: 160 provider_reference: type: string maxLength: 160 order_id: type: string maxLength: 120 measurement_request_id: type: string maxLength: 120 description: type: string maxLength: 500 from_wallet_currency: type: string readOnly: true to_wallet_currency: type: string readOnly: true created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. completed_at: type: string format: date-time nullable: true metadata: {} required: - amount - created_at - from_wallet_currency - id - reference - to_wallet_currency - transaction_type TransactionStatusEnum: enum: - pending - processing - completed - failed - cancelled - reversed - disputed type: string TransactionSummary: type: object properties: total_inflow: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ total_outflow: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ net_balance: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ count: type: integer required: - count - net_balance - total_inflow - total_outflow TransactionTypeEnum: enum: - order_payment - escrow_hold - escrow_release - commission - measurement_fee - vendor_subscription - platform_usage_fee - advertisement_fee - affiliate_revenue - refund - payout - transfer - reversal - adjustment type: string TransferRecipientCreate: type: object properties: account_number: type: string maxLength: 20 account_name: type: string maxLength: 180 bank_name: type: string maxLength: 180 bank_code: type: string maxLength: 20 required: - account_name - account_number - bank_code - bank_name TransferRecipientCreateRequest: type: object properties: account_number: type: string minLength: 1 maxLength: 20 account_name: type: string minLength: 1 maxLength: 180 bank_name: type: string minLength: 1 maxLength: 180 bank_code: type: string minLength: 1 maxLength: 20 required: - account_name - account_number - bank_code - bank_name UrgencyEnum: enum: - low - medium - high - rush type: string UserActivity: type: object properties: id: type: integer readOnly: true user: type: string format: uuid description: UUID7 — globally unique, time-ordered primary key. user_username: type: string readOnly: true action: type: string title: Action Performed description: Type of action performed by the user. maxLength: 100 resource: type: string title: Resource Name description: Affected resource or area of interaction. maxLength: 100 resource_id: type: integer maximum: 9223372036854775807 minimum: 0 format: int64 nullable: true ip_address: type: string nullable: true user_agent: type: string session_id: type: string maxLength: 40 metadata: {} timestamp: type: string format: date-time readOnly: true title: Action Time required: - action - id - timestamp - user - user_username UserBasic: type: object description: Serializer for basic user information. properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. first_name: type: string nullable: true maxLength: 150 last_name: type: string nullable: true maxLength: 150 phone: type: string readOnly: true nullable: true description: Primary unique identifier for phone-based auth. required: - id - phone UserBasicRequest: type: object description: Serializer for basic user information. properties: first_name: type: string nullable: true maxLength: 150 last_name: type: string nullable: true maxLength: 150 UserSession: type: object description: |- Read serializer for UserSession — used by the active sessions list. All UUID7 primary keys are serialized as strings (required for JavaScript, which cannot safely handle 128-bit integers). The ``is_current`` flag is computed dynamically at query time (via the view injecting the current JTI), so it is read-only here. The ``is_expired`` flag is a computed property (not stored in DB). properties: id: type: string readOnly: true device_name: type: string readOnly: true description: Human-readable label such as 'Chrome on Windows'. client_type: allOf: - $ref: '#/components/schemas/UserSessionClientTypeEnum' readOnly: true description: Browser / mobile app / API client. browser: type: string readOnly: true os: type: string readOnly: true ip_address: type: string readOnly: true nullable: true description: IP address captured at session creation time. country: type: string readOnly: true city: type: string readOnly: true created_at: type: string format: date-time readOnly: true last_used_at: type: string format: date-time readOnly: true expires_at: type: string format: date-time readOnly: true nullable: true is_current: type: boolean description: |- True when the session's JTI matches the current request's access token JTI. The view must pass `current_jti` in serializer context: serializer = UserSessionSerializer( sessions, many=True, context={"current_jti": current_jti} ) readOnly: true is_expired: type: boolean description: True when the session's refresh token has expired. readOnly: true required: - browser - city - client_type - country - created_at - device_name - expires_at - id - ip_address - is_current - is_expired - last_used_at - os UserSessionClientTypeEnum: enum: - web - mobile - api - unknown type: string VendorCollection: type: object description: Minimal representation of a Collection linked to this vendor. properties: id: type: string readOnly: true title: type: string readOnly: true slug: type: string readOnly: true pattern: ^[-a-zA-Z0-9_]+$ required: - id - slug - title VendorOrderStatus: type: object properties: delivery_status: $ref: '#/components/schemas/DeliveryStatusEnum' tracking_id: type: string required: - delivery_status VendorOrderStatusRequest: type: object properties: delivery_status: $ref: '#/components/schemas/DeliveryStatusEnum' tracking_id: type: string required: - delivery_status VendorPayoutDetails: type: object description: Input serializer for POST /vendor/payout/. properties: bank_name: type: string maxLength: 150 bank_code: type: string maxLength: 10 account_name: type: string maxLength: 200 account_number: type: string description: Bank account number. Will be encrypted before storage. maxLength: 20 paystack_recipient_code: type: string maxLength: 100 required: - account_name - account_number - bank_name VendorPayoutDetailsRequest: type: object description: Input serializer for POST /vendor/payout/. properties: bank_name: type: string minLength: 1 maxLength: 150 bank_code: type: string maxLength: 10 account_name: type: string minLength: 1 maxLength: 200 account_number: type: string minLength: 1 description: Bank account number. Will be encrypted before storage. maxLength: 20 paystack_recipient_code: type: string maxLength: 100 required: - account_name - account_number - bank_name VendorProfileOutput: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. user_id: type: string readOnly: true user_email: type: string readOnly: true store_name: type: string readOnly: true description: Public-facing store name shown on the marketplace. store_slug: type: string readOnly: true description: URL-safe unique store identifier. Auto-generated from store_name. pattern: ^[-a-zA-Z0-9_]+$ tagline: type: string readOnly: true description: type: string readOnly: true logo_url: type: string readOnly: true description: Cloudinary store logo URL. cover_url: type: string readOnly: true description: Cloudinary banner URL. city: type: string readOnly: true state: type: string readOnly: true country: type: string readOnly: true whatsapp: type: string readOnly: true opening_time: type: string format: time readOnly: true nullable: true closing_time: type: string format: time readOnly: true nullable: true business_hours: readOnly: true description: 'e.g. {''Monday'': ''9:00-17:00'', ''Tuesday'': ''9:00-17:00''}' instagram_url: type: string format: uri readOnly: true tiktok_url: type: string format: uri readOnly: true twitter_url: type: string format: uri readOnly: true website_url: type: string format: uri readOnly: true cash_payment_mode: allOf: - $ref: '#/components/schemas/CashPaymentModeEnum' readOnly: true description: Storefront display preference for COD / Pay At Shop availability. collections: type: array items: $ref: '#/components/schemas/VendorCollection' readOnly: true total_products: type: integer readOnly: true total_sales: type: integer readOnly: true total_revenue: type: string format: decimal pattern: ^-?\d{0,14}(?:\.\d{0,2})?$ readOnly: true average_rating: type: string format: decimal pattern: ^-?\d{0,1}(?:\.\d{0,2})?$ readOnly: true review_count: type: integer readOnly: true wallet_balance: type: string format: decimal pattern: ^-?\d{0,12}(?:\.\d{0,2})?$ readOnly: true is_verified: type: boolean readOnly: true description: Manually verified by Fashionistar staff. Does NOT gate dashboard access. is_active: type: boolean readOnly: true is_featured: type: boolean readOnly: true setup_state: allOf: - $ref: '#/components/schemas/VendorSetupState' readOnly: true created_at: type: string format: date-time readOnly: true description: Timestamp when the record was created. updated_at: type: string format: date-time readOnly: true description: Timestamp when the record was last updated. required: - average_rating - business_hours - cash_payment_mode - city - closing_time - collections - country - cover_url - created_at - description - id - instagram_url - is_active - is_featured - is_verified - logo_url - opening_time - review_count - setup_state - state - store_name - store_slug - tagline - tiktok_url - total_products - total_revenue - total_sales - twitter_url - updated_at - user_email - user_id - wallet_balance - website_url - whatsapp VendorProfileUpdate: type: object description: Input-only serializer for PATCH /vendor/profile/. properties: store_name: type: string maxLength: 150 tagline: type: string maxLength: 200 description: type: string maxLength: 2000 logo_url: type: string format: uri cover_url: type: string format: uri city: type: string maxLength: 100 state: type: string maxLength: 100 country: type: string maxLength: 100 whatsapp: type: string maxLength: 20 opening_time: type: string format: time nullable: true closing_time: type: string format: time nullable: true business_hours: {} instagram_url: type: string format: uri tiktok_url: type: string format: uri twitter_url: type: string format: uri website_url: type: string format: uri cash_payment_mode: $ref: '#/components/schemas/CashPaymentModeEnum' collection_ids: type: array items: type: string description: 1-15 Collection IDs this store specialises in. maxItems: 15 VendorSetup: type: object description: |- Minimal setup payload to create the first vendor profile. Called on the POST /vendor/setup/ endpoint. properties: store_name: type: string maxLength: 150 description: type: string maxLength: 2000 tagline: type: string maxLength: 200 logo_url: type: string format: uri cover_url: type: string format: uri city: type: string maxLength: 100 state: type: string maxLength: 100 country: type: string default: Nigeria maxLength: 100 whatsapp: type: string maxLength: 20 instagram_url: type: string format: uri tiktok_url: type: string format: uri twitter_url: type: string format: uri website_url: type: string format: uri cash_payment_mode: allOf: - $ref: '#/components/schemas/CashPaymentModeEnum' default: disabled collection_ids: type: array items: type: string maxItems: 15 required: - city - description - state - store_name VendorSetupRequest: type: object description: |- Minimal setup payload to create the first vendor profile. Called on the POST /vendor/setup/ endpoint. properties: store_name: type: string minLength: 1 maxLength: 150 description: type: string minLength: 1 maxLength: 2000 tagline: type: string maxLength: 200 logo_url: type: string format: uri cover_url: type: string format: uri city: type: string minLength: 1 maxLength: 100 state: type: string minLength: 1 maxLength: 100 country: type: string default: Nigeria maxLength: 100 whatsapp: type: string maxLength: 20 instagram_url: type: string format: uri tiktok_url: type: string format: uri twitter_url: type: string format: uri website_url: type: string format: uri cash_payment_mode: allOf: - $ref: '#/components/schemas/CashPaymentModeEnum' default: disabled collection_ids: type: array items: type: string minLength: 1 maxItems: 15 required: - city - description - state - store_name VendorSetupState: type: object properties: current_step: type: integer readOnly: true description: Step number (1–4) the vendor is currently on. profile_complete: type: boolean readOnly: true bank_details: type: boolean readOnly: true id_verified: type: boolean readOnly: true description: 'FUTURE: government ID verified via external KYC API (Youverify/Smile Identity). Does NOT block dashboard or product creation — informational only.' first_product: type: boolean readOnly: true onboarding_done: type: boolean readOnly: true description: True once profile_complete + bank_details + first_product are all done. Store becomes fully visible on the marketplace. completion_percentage: type: integer description: |- Return setup completion as an integer percentage 0–100. Based on the 3 active steps (id_verified excluded from formula). readOnly: true required: - bank_details - completion_percentage - current_step - first_product - id_verified - onboarding_done - profile_complete VendorTransactionPin: type: object description: Input serializer for PIN set/verify endpoints. properties: pin: type: string description: 4-digit numeric payout confirmation PIN. maxLength: 4 minLength: 4 required: - pin VendorTransactionPinRequest: type: object description: Input serializer for PIN set/verify endpoints. properties: pin: type: string minLength: 4 description: 4-digit numeric payout confirmation PIN. maxLength: 4 required: - pin Wallet: type: object properties: id: type: string format: uuid readOnly: true description: UUID7 — globally unique, time-ordered primary key. owner_type: $ref: '#/components/schemas/OwnerTypeEnum' name: type: string maxLength: 120 currency: type: string balance: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ available_balance: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ pending_balance: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ escrow_balance: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ status: $ref: '#/components/schemas/WalletStatusEnum' has_pin: type: boolean readOnly: true daily_limit: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ nullable: true monthly_limit: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ nullable: true last_transaction_at: type: string format: date-time nullable: true required: - currency - has_pin - id - name - owner_type WalletFundPayment: type: object properties: order_id: type: string maxLength: 120 amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ purpose: $ref: '#/components/schemas/PurposeEnum' provider: $ref: '#/components/schemas/ProviderEnum' currency: type: string default: NGN maxLength: 10 selected_percent: type: integer maximum: 100 minimum: 1 default: 100 cash_payment_mode: allOf: - $ref: '#/components/schemas/CashPaymentModeEnum' default: disabled payment_path: allOf: - $ref: '#/components/schemas/PaymentPathEnum' default: gateway metadata: {} required: - provider - purpose WalletFundPaymentRequest: type: object properties: order_id: type: string maxLength: 120 amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ purpose: $ref: '#/components/schemas/PurposeEnum' provider: $ref: '#/components/schemas/ProviderEnum' currency: type: string minLength: 1 default: NGN maxLength: 10 selected_percent: type: integer maximum: 100 minimum: 1 default: 100 cash_payment_mode: allOf: - $ref: '#/components/schemas/CashPaymentModeEnum' default: disabled payment_path: allOf: - $ref: '#/components/schemas/PaymentPathEnum' default: gateway metadata: {} required: - provider - purpose WalletPinChange: type: object properties: current_pin: type: string maxLength: 4 minLength: 4 pattern: ^\d{4}$ new_pin: type: string maxLength: 4 minLength: 4 pattern: ^\d{4}$ required: - current_pin - new_pin WalletPinChangeRequest: type: object properties: current_pin: type: string minLength: 4 maxLength: 4 pattern: ^\d{4}$ new_pin: type: string minLength: 4 maxLength: 4 pattern: ^\d{4}$ required: - current_pin - new_pin WalletPinSet: type: object properties: pin: type: string maxLength: 4 minLength: 4 pattern: ^\d{4}$ required: - pin WalletPinSetRequest: type: object properties: pin: type: string minLength: 4 maxLength: 4 pattern: ^\d{4}$ required: - pin WalletPinVerify: type: object properties: pin: type: string maxLength: 4 minLength: 4 pattern: ^\d{4}$ required: - pin WalletPinVerifyRequest: type: object properties: pin: type: string minLength: 4 maxLength: 4 pattern: ^\d{4}$ required: - pin WalletStatusEnum: enum: - active - inactive - frozen - suspended - closed type: string WalletTransfer: type: object description: |- Serializer for P2P fund transfers. Validates receiver existence, positive amount, and PIN format. properties: receiver_id: type: string format: uuid description: ID of the user receiving the funds. amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ description: Amount to transfer (min 0.01). transaction_password: type: string description: 4-digit transaction PIN for authorization. maxLength: 10 minLength: 4 required: - amount - receiver_id - transaction_password WalletTransferRequest: type: object description: |- Serializer for P2P fund transfers. Validates receiver existence, positive amount, and PIN format. properties: receiver_id: type: string format: uuid description: ID of the user receiving the funds. amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ description: Amount to transfer (min 0.01). transaction_password: type: string minLength: 4 description: 4-digit transaction PIN for authorization. maxLength: 10 required: - amount - receiver_id - transaction_password WalletWithdrawal: type: object description: Validate KYC-gated wallet withdrawal requests. properties: amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ pin: type: string maxLength: 4 minLength: 4 pattern: ^\d{4}$ bank_code: type: string maxLength: 20 account_number: type: string maxLength: 10 minLength: 10 pattern: ^\d{10}$ account_name: type: string maxLength: 160 required: - account_name - account_number - amount - bank_code - pin WalletWithdrawalRequest: type: object description: Validate KYC-gated wallet withdrawal requests. properties: amount: type: string format: decimal pattern: ^-?\d{0,18}(?:\.\d{0,2})?$ pin: type: string minLength: 4 maxLength: 4 pattern: ^\d{4}$ bank_code: type: string minLength: 1 maxLength: 20 account_number: type: string minLength: 10 maxLength: 10 pattern: ^\d{10}$ account_name: type: string minLength: 1 maxLength: 160 required: - account_name - account_number - amount - bank_code - pin WebhookEndpoint: type: object properties: id: type: string format: uuid readOnly: true provider: type: string format: uuid provider_name: type: string readOnly: true name: type: string title: Webhook Name maxLength: 100 endpoint_url: type: string pattern: ^[a-zA-Z0-9-_/]+$ maxLength: 255 events: title: Subscribed Events description: List of event slugs this webhook processes. is_active: type: boolean retry_count: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 timeout_seconds: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 title: Timeout (Seconds) events_count: type: integer readOnly: true pending_events: type: integer readOnly: true created_at: type: string format: date-time readOnly: true updated_at: type: string format: date-time readOnly: true required: - created_at - endpoint_url - events_count - id - name - pending_events - provider - provider_name - updated_at WebhookEndpointRequest: type: object properties: provider: type: string format: uuid name: type: string minLength: 1 title: Webhook Name maxLength: 100 endpoint_url: type: string minLength: 1 pattern: ^[a-zA-Z0-9-_/]+$ maxLength: 255 secret_key: type: string writeOnly: true minLength: 1 description: Used to verify webhook payload signatures. maxLength: 255 events: title: Subscribed Events description: List of event slugs this webhook processes. is_active: type: boolean retry_count: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 timeout_seconds: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 title: Timeout (Seconds) required: - endpoint_url - name - provider - secret_key WebhookEvent: type: object properties: id: type: string format: uuid readOnly: true webhook: type: string format: uuid webhook_name: type: string readOnly: true provider_name: type: string readOnly: true event_type: type: string maxLength: 100 payload: {} headers: {} signature: type: string maxLength: 255 is_valid: type: boolean readOnly: true title: Is Signature Valid is_processed: type: boolean readOnly: true processed_at: type: string format: date-time readOnly: true nullable: true error_message: type: string retry_count: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 received_at: type: string format: date-time readOnly: true required: - event_type - id - is_processed - is_valid - processed_at - provider_name - received_at - webhook - webhook_name WebhookEventRequest: type: object properties: webhook: type: string format: uuid event_type: type: string minLength: 1 maxLength: 100 payload: {} headers: {} signature: type: string maxLength: 255 error_message: type: string retry_count: type: integer maximum: 9223372036854775807 minimum: -9223372036854775808 format: int64 required: - event_type - webhook WishlistProduct: type: object properties: id: type: string readOnly: true pid: type: string readOnly: true title: type: string readOnly: true image: type: string readOnly: true price: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true old_price: type: string format: decimal pattern: ^-?\d{0,10}(?:\.\d{0,2})?$ readOnly: true stock_qty: type: integer readOnly: true status: type: string readOnly: true category_name: type: string readOnly: true required: - category_name - id - image - old_price - pid - price - status - stock_qty - title WishlistToggle: type: object properties: product_id: type: string format: uuid required: - product_id WishlistToggleRequest: type: object properties: product_id: type: string format: uuid required: - product_id securitySchemes: basicAuth: type: http scheme: basic cookieAuth: type: apiKey in: cookie name: sessionid jwtAuth: type: http scheme: bearer bearerFormat: JWT tokenAuth: type: apiKey in: header name: Authorization description: Token-based authentication with required prefix "Token" servers: - url: http://127.0.0.1:8001 description: Development (ASGI/Uvicorn)