{
  "openapi": "3.0.3",
  "info": {
    "title": "Supplier Portal API",
    "description": "Django + DRF backend for the supplier portal.\n\nStandard JSON envelope: {status, code, message, data, errors}\n\nJWT auth (SimpleJWT). After login, access_token is stored in environment variable automatically.",
    "version": "1.0.0"
  },
  "servers": [
    { "url": "http://localhost:8000/api/v1", "description": "Local development" },
    { "url": "https://rfoof.io/api/v1", "description": "Production" }
  ],
  "tags": [
    { "name": "Health", "description": "Liveness probe" },
    { "name": "Auth - JWT", "description": "Login, refresh, verify, password reset" },
    { "name": "Auth - Users", "description": "User management. Admin role required for create/list/delete." },
    { "name": "Suppliers - Portal", "description": "Supplier self-service (role=supplier + linked)." },
    { "name": "Suppliers - Admin", "description": "Admin-only operations (role=admin)." }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/health/": {
      "get": {
        "tags": ["Health"],
        "summary": "Health check",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "example": { "status": "ok" } } }
          }
        }
      }
    },

    "/auth/jwt/create/": {
      "post": {
        "tags": ["Auth - JWT"],
        "summary": "Login",
        "description": "Returns user profile + JWT tokens.\n\n**Post-Response Script:**\n```js\nvar res = pm.response.json();\nif (res.status === 1 && res.data) {\n  pm.environment.set('access_token', res.data.access_token);\n  pm.environment.set('refresh_token', res.data.refresh_token);\n}\n```",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "password"],
                "properties": {
                  "email": { "type": "string", "format": "email", "example": "admin@rfoof.io" },
                  "password": { "type": "string", "example": "YourPassword123" }
                }
              },
              "example": { "email": "admin@rfoof.io", "password": "YourPassword123" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful",
            "content": {
              "application/json": {
                "example": {
                  "status": 1,
                  "code": 200,
                  "message": "Login successful",
                  "data": {
                    "id": 1,
                    "email": "admin@rfoof.io",
                    "full_name": "Admin User",
                    "role": "admin",
                    "language": "en",
                    "notifications_enabled": true,
                    "is_active": true,
                    "access_token": "eyJ...",
                    "refresh_token": "eyJ...",
                    "token_type": "Bearer",
                    "expires_at": "2026-06-02 12:00:00",
                    "refresh_expires_at": "2026-07-01 12:00:00"
                  },
                  "errors": []
                }
              }
            }
          },
          "401": { "description": "Invalid credentials" }
        }
      }
    },
    "/auth/jwt/refresh/": {
      "post": {
        "tags": ["Auth - JWT"],
        "summary": "Refresh access token",
        "description": "**Post-Response Script:**\n```js\nvar res = pm.response.json();\nif (res.status === 1 && res.data) {\n  pm.environment.set('access_token', res.data.access_token);\n  pm.environment.set('refresh_token', res.data.refresh_token);\n}\n```",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["refresh"],
                "properties": {
                  "refresh": { "type": "string", "example": "{{refresh_token}}" }
                }
              },
              "example": { "refresh": "{{refresh_token}}" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New token pair",
            "content": {
              "application/json": {
                "example": {
                  "status": 1, "code": 200, "message": "Success",
                  "data": { "access_token": "eyJ...", "refresh_token": "eyJ...", "token_type": "Bearer", "expires_at": "2026-06-02 12:00:00", "refresh_expires_at": "2026-07-01 12:00:00" },
                  "errors": []
                }
              }
            }
          }
        }
      }
    },
    "/auth/jwt/verify/": {
      "post": {
        "tags": ["Auth - JWT"],
        "summary": "Verify a token",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token"],
                "properties": { "token": { "type": "string", "example": "{{access_token}}" } }
              },
              "example": { "token": "{{access_token}}" }
            }
          }
        },
        "responses": {
          "200": { "description": "Token is valid" },
          "401": { "description": "Token is invalid or expired" }
        }
      }
    },
    "/auth/users/reset_password/": {
      "post": {
        "tags": ["Auth - JWT"],
        "summary": "Request password-reset email",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": { "email": { "type": "string", "format": "email", "example": "user@example.com" } }
              },
              "example": { "email": "user@example.com" }
            }
          }
        },
        "responses": { "204": { "description": "Email sent (if address exists)" } }
      }
    },
    "/auth/users/reset_password_confirm/": {
      "post": {
        "tags": ["Auth - JWT"],
        "summary": "Confirm password reset",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["uid", "token", "new_password", "re_new_password"],
                "properties": {
                  "uid": { "type": "string", "example": "MQ" },
                  "token": { "type": "string", "example": "abc123-token" },
                  "new_password": { "type": "string", "example": "NewStr0ngP@ss!" },
                  "re_new_password": { "type": "string", "example": "NewStr0ngP@ss!" }
                }
              },
              "example": { "uid": "MQ", "token": "abc123-token", "new_password": "NewStr0ngP@ss!", "re_new_password": "NewStr0ngP@ss!" }
            }
          }
        },
        "responses": { "204": { "description": "Password reset" } }
      }
    },

    "/auth/users/": {
      "get": {
        "tags": ["Auth - Users"],
        "summary": "List users (admin)",
        "description": "Requires role=admin.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "status": 1, "code": 200, "message": "Success",
                  "data": { "count": 2, "next": null, "previous": null, "results": [
                    { "id": 1, "email": "admin@rfoof.io", "full_name": "Admin", "role": "admin" },
                    { "id": 2, "email": "supplier@example.com", "full_name": "Supplier", "role": "supplier" }
                  ]},
                  "errors": []
                }
              }
            }
          },
          "403": { "description": "Forbidden — admin role required" }
        }
      },
      "post": {
        "tags": ["Auth - Users"],
        "summary": "Create user (admin)",
        "description": "Requires role=admin. New users default to role=supplier.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "password", "re_password"],
                "properties": {
                  "email": { "type": "string", "format": "email", "example": "newsupplier@example.com" },
                  "password": { "type": "string", "example": "Str0ngP@ssword!" },
                  "re_password": { "type": "string", "example": "Str0ngP@ssword!" },
                  "full_name": { "type": "string", "example": "New Supplier" }
                }
              },
              "example": { "email": "newsupplier@example.com", "password": "Str0ngP@ssword!", "re_password": "Str0ngP@ssword!", "full_name": "New Supplier" }
            }
          }
        },
        "responses": { "201": { "description": "Created" }, "403": { "description": "Forbidden" } }
      }
    },
    "/auth/users/{id}/": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" }, "example": 2 }],
      "get": {
        "tags": ["Auth - Users"],
        "summary": "Retrieve user (admin)",
        "responses": { "200": { "description": "OK" } }
      },
      "patch": {
        "tags": ["Auth - Users"],
        "summary": "Update user (admin)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "full_name": { "type": "string", "example": "Updated Name" },
                  "phone_number": { "type": "string", "example": "+971501234567" },
                  "language": { "type": "string", "enum": ["en", "ar"], "example": "ar" },
                  "notifications_enabled": { "type": "boolean", "example": false }
                }
              },
              "example": { "full_name": "Updated Name" }
            }
          }
        },
        "responses": { "200": { "description": "OK" } }
      },
      "delete": {
        "tags": ["Auth - Users"],
        "summary": "Delete user (admin)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["current_password"],
                "properties": { "current_password": { "type": "string", "example": "AdminPassword123" } }
              },
              "example": { "current_password": "AdminPassword123" }
            }
          }
        },
        "responses": { "204": { "description": "Deleted" } }
      }
    },
    "/auth/users/me/": {
      "get": {
        "tags": ["Auth - Users"],
        "summary": "Get my profile",
        "description": "Any authenticated user.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "status": 1, "code": 200, "message": "Success",
                  "data": { "id": 1, "email": "admin@rfoof.io", "full_name": "Admin User", "role": "admin", "phone_number": null, "avatar": null, "language": "en", "notifications_enabled": true, "is_active": true },
                  "errors": []
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": ["Auth - Users"],
        "summary": "Update my profile",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "full_name": { "type": "string", "example": "My New Name" },
                  "phone_number": { "type": "string", "example": "+971501234567" },
                  "language": { "type": "string", "enum": ["en", "ar"], "example": "ar" },
                  "notifications_enabled": { "type": "boolean", "example": true }
                }
              },
              "example": { "full_name": "My New Name", "language": "ar" }
            }
          }
        },
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/auth/users/set_password/": {
      "post": {
        "tags": ["Auth - Users"],
        "summary": "Change password",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["current_password", "new_password", "re_new_password"],
                "properties": {
                  "current_password": { "type": "string", "example": "OldPassword123" },
                  "new_password": { "type": "string", "example": "NewStr0ngP@ss!" },
                  "re_new_password": { "type": "string", "example": "NewStr0ngP@ss!" }
                }
              },
              "example": { "current_password": "OldPassword123", "new_password": "NewStr0ngP@ss!", "re_new_password": "NewStr0ngP@ss!" }
            }
          }
        },
        "responses": { "204": { "description": "Password changed" } }
      }
    },

    "/suppliers/me/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "My supplier profile",
        "description": "Requires role=supplier + linked.",
        "responses": { "200": { "description": "OK" }, "403": { "description": "Not a supplier or not linked" } }
      }
    },
    "/suppliers/me/dashboard/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "Dashboard totals and balances",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/suppliers/me/transactions/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "Transaction list",
        "description": "Lists the supplier's invoices/transactions recorded locally when created via POST /me/payments/. Pass refresh=1 to re-query live status (Paid/Pending) and payment method from MyFatoorah's GetPaymentStatus before returning.",
        "parameters": [
          { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Filter by customer name, reference, or invoice id", "example": "" },
          { "name": "status", "in": "query", "schema": { "type": "string" }, "description": "Filter by stored status", "example": "Paid" },
          { "name": "refresh", "in": "query", "schema": { "type": "string", "enum": ["0", "1"] }, "description": "Set to 1 to refresh live status from MyFatoorah", "example": "1" },
          { "name": "page", "in": "query", "schema": { "type": "integer" }, "example": 1 },
          { "name": "page_size", "in": "query", "schema": { "type": "integer" }, "example": 20 }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "status": 1, "code": 200, "message": "Success",
                  "data": { "count": 1, "next": null, "previous": null, "results": [
                    {
                      "id": 1,
                      "invoice_id": "5381611",
                      "invoice_url": "https://demo.myfatoorah.com/KWT/ie/...",
                      "customer_name": "MohamedWahba",
                      "customer_mobile": "501234567",
                      "customer_email": "",
                      "customer_reference": "2026000034",
                      "invoice_value": "5.000",
                      "currency": "AED",
                      "notification_option": "LNK",
                      "status": "Paid",
                      "payment_method": "Apple Pay",
                      "paid_at": "2026-06-09 20:51:00",
                      "created_at": "2026-06-09 20:47:00",
                      "updated_at": "2026-06-09 20:51:00"
                    }
                  ]},
                  "errors": []
                }
              }
            }
          }
        }
      }
    },
    "/suppliers/me/deposits/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "Deposit history",
        "parameters": [
          { "name": "search", "in": "query", "schema": { "type": "string" }, "example": "" },
          { "name": "start", "in": "query", "schema": { "type": "integer" }, "example": 0 },
          { "name": "length", "in": "query", "schema": { "type": "integer" }, "example": 10 },
          { "name": "sort_column", "in": "query", "schema": { "type": "string" }, "example": "DepositDate" },
          { "name": "sort_direction", "in": "query", "schema": { "type": "string", "enum": ["asc", "desc"] }, "example": "desc" }
        ],
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/suppliers/me/deposits/invoices/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "Invoices in a deposit",
        "parameters": [
          { "name": "deposit_reference", "in": "query", "required": true, "schema": { "type": "string" }, "example": "DEP-00123" }
        ],
        "responses": { "200": { "description": "OK" }, "400": { "description": "Missing deposit_reference" } }
      }
    },
    "/suppliers/me/refunds/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "Refund status lookup",
        "parameters": [
          { "name": "key", "in": "query", "required": true, "schema": { "type": "string" }, "example": "12345" },
          { "name": "key_type", "in": "query", "required": true, "schema": { "type": "string", "enum": ["InvoiceId", "RefundReference", "RefundId"] }, "example": "InvoiceId" }
        ],
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/suppliers/me/documents/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "List KYC documents",
        "responses": { "200": { "description": "OK" } }
      },
      "post": {
        "tags": ["Suppliers - Portal"],
        "summary": "Upload KYC document",
        "description": "Max 5 MB. Allowed: jpg, jpeg, png, bmp, gif, xls, xlsx, pdf, doc, docx.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file", "file_type"],
                "properties": {
                  "file": { "type": "string", "format": "binary" },
                  "file_type": { "type": "integer", "enum": [1, 2, 3, 4, 5, 6, 7, 16, 17, 20, 21, 25, 26, 27, 28, 30], "example": 1 },
                  "expire_date": { "type": "string", "format": "date", "example": "2027-12-31" }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Uploaded" }, "400": { "description": "Validation error" } }
      }
    },
    "/suppliers/me/payments/": {
      "post": {
        "tags": ["Suppliers - Portal"],
        "summary": "Create payment link",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["customer_name", "invoice_value", "notification_option"],
                "properties": {
                  "customer_name": { "type": "string", "example": "Ahmed" },
                  "customer_email": { "type": "string", "format": "email", "example": "ahmed@example.com" },
                  "customer_mobile": { "type": "string", "example": "501234567" },
                  "mobile_country_code": { "type": "string", "example": "971" },
                  "invoice_value": { "type": "number", "example": 100.00 },
                  "display_currency_iso": { "type": "string", "example": "AED" },
                  "notification_option": { "type": "string", "enum": ["LNK", "SMS", "EML", "ALL"], "example": "LNK" },
                  "language": { "type": "string", "enum": ["en", "ar"], "example": "en" },
                  "customer_reference": { "type": "string", "example": "ORD-001" },
                  "invoice_items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": ["item_name", "quantity", "unit_price"],
                      "properties": {
                        "item_name": { "type": "string", "example": "Service Fee" },
                        "quantity": { "type": "integer", "example": 1 },
                        "unit_price": { "type": "number", "example": 100.00 }
                      }
                    }
                  }
                }
              },
              "example": { "customer_name": "Ahmed", "invoice_value": 100.00, "notification_option": "LNK", "display_currency_iso": "AED" }
            }
          }
        },
        "responses": { "201": { "description": "Payment link created" }, "400": { "description": "Validation error" } }
      }
    },
    "/suppliers/me/payments/{invoice_id}/": {
      "parameters": [{ "name": "invoice_id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "12345" }],
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "Check payment status",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/suppliers/me/payment-methods/": {
      "get": {
        "tags": ["Suppliers - Portal"],
        "summary": "List payment methods",
        "parameters": [
          { "name": "amount", "in": "query", "schema": { "type": "number" }, "example": 100 },
          { "name": "currency", "in": "query", "schema": { "type": "string" }, "example": "AED" }
        ],
        "responses": { "200": { "description": "OK" } }
      }
    },

    "/suppliers/admin/link/": {
      "post": {
        "tags": ["Suppliers - Admin"],
        "summary": "Link user to supplier code",
        "description": "Requires role=admin.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["user_id", "supplier_code"],
                "properties": {
                  "user_id": { "type": "integer", "example": 2 },
                  "supplier_code": { "type": "integer", "example": 1001 }
                }
              },
              "example": { "user_id": 2, "supplier_code": 1001 }
            }
          }
        },
        "responses": { "201": { "description": "Linked" }, "403": { "description": "Forbidden" }, "404": { "description": "User not found" }, "400": { "description": "Invalid supplier code" } }
      }
    },
    "/suppliers/webhooks/payment/": {
      "post": {
        "tags": ["Suppliers - Admin"],
        "summary": "Payment webhook (MyFatoorah v2)",
        "description": "Public endpoint called by MyFatoorah when a payment status changes (Transaction Status Changed event). Verifies the request signature using HMAC-SHA256 (base64) against the configured webhook secret. On successful payment, stores the invoice locally and sends an email notification to the supplier.\n\nSignature is computed from: `Invoice.Id,Invoice.Status,Transaction.Status,Transaction.PaymentId,Invoice.ExternalIdentifier`",
        "security": [],
        "parameters": [
          { "name": "MyFatoorah-Signature", "in": "header", "required": true, "schema": { "type": "string" }, "description": "HMAC-SHA256 base64-encoded signature of ordered data fields" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "Event": {
                    "type": "object",
                    "properties": {
                      "Code": { "type": "integer", "example": 1 },
                      "Name": { "type": "string", "example": "PAYMENT_STATUS_CHANGED" },
                      "CountryIsoCode": { "type": "string", "example": "ARE" },
                      "CreationDate": { "type": "string", "example": "2026-06-09T20:51:05Z" },
                      "Reference": { "type": "string", "example": "WH-538161" }
                    }
                  },
                  "Data": {
                    "type": "object",
                    "properties": {
                      "Invoice": {
                        "type": "object",
                        "properties": {
                          "Id": { "type": "string", "example": "53816118" },
                          "Status": { "type": "string", "example": "PAID" },
                          "Reference": { "type": "string", "example": "2026000034" },
                          "ExternalIdentifier": { "type": "string", "example": "" }
                        }
                      },
                      "Transaction": {
                        "type": "object",
                        "properties": {
                          "Id": { "type": "string", "example": "142703" },
                          "Status": { "type": "string", "example": "SUCCESS" },
                          "PaymentMethod": { "type": "string", "example": "Apple Pay" },
                          "PaymentId": { "type": "string", "example": "0808538161183122001281" }
                        }
                      },
                      "Customer": {
                        "type": "object",
                        "properties": {
                          "Name": { "type": "string", "example": "MohamedWahba" },
                          "Mobile": { "type": "string", "example": "+971" },
                          "Email": { "type": "string", "example": "" }
                        }
                      },
                      "Amount": {
                        "type": "object",
                        "properties": {
                          "BaseCurrency": { "type": "string", "example": "AED" },
                          "ValueInBaseCurrency": { "type": "string", "example": "5" }
                        }
                      },
                      "Suppliers": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "Code": { "type": "integer", "example": 1 },
                            "Name": { "type": "string", "example": "Saafa and Co" },
                            "InvoiceShare": { "type": "string", "example": "5" }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "Event": { "Code": 1, "Name": "PAYMENT_STATUS_CHANGED", "CountryIsoCode": "ARE", "CreationDate": "2026-06-09T20:51:05Z", "Reference": "WH-538161" },
                "Data": {
                  "Invoice": { "Id": "53816118", "Status": "PAID", "Reference": "2026000034", "ExternalIdentifier": "" },
                  "Transaction": { "Id": "142703", "Status": "SUCCESS", "PaymentMethod": "Apple Pay", "PaymentId": "0808538161183122001281" },
                  "Customer": { "Name": "MohamedWahba", "Mobile": "+971", "Email": "" },
                  "Amount": { "BaseCurrency": "AED", "ValueInBaseCurrency": "5" },
                  "Suppliers": [{ "Code": 1, "Name": "Saafa and Co", "InvoiceShare": "5" }]
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Webhook processed" },
          "400": { "description": "Missing payment data" },
          "403": { "description": "Invalid or missing signature" },
          "502": { "description": "Failed to verify with MyFatoorah" }
        }
      }
    }
  }
}
