A Flask-based REST API application for managing reseller registrations and purchase tracking with cashback calculations.
- Token authentication (JWT)
- Reseller registration
- Purchase registration
- Purchase editing
- Purchase listing
- Cashback calculation
- Backend: Flask 3.1
- Database: MySQL (via PyMySQL)
- ORM: SQLAlchemy 2.0
- Migrations: Alembic 1.18
- Authentication: Flask-JWT-Extended
- Validation: Marshmallow
- Testing: unittest, coverage
- Deployment: Docker, Docker Compose, Gunicorn
- Git
- Docker
- Docker Compose
- uv — for dependency management and running commands
- Postman - API testing
- Clone the repository:
git clone https://github.com/rdmsilva/reseller-api.git
cd reseller-apiDependencies are managed with uv and declared in pyproject.toml, with versions locked in uv.lock.
uv sync # create .venv and install runtime + dev dependencies
uv run gunicorn --bind 0.0.0.0:5000 main:app # run the app
uv run ./cover.sh # run the test suite with coverageBuild and start the Docker containers:
docker-compose build && docker-compose upThe API will be available at http://localhost:5000
Interactive API documentation is available at:
http://localhost:5000/apidocs
OpenAPI specification JSON:
http://localhost:5000/apispec_1.json
Import the pre-built collection for easy API testing:
postman/Reseller-API.postman_collection.json
POST /v1/resellers
All data fields are required.
curl --location --request POST 'localhost:5000/v1/resellers' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"cpf": 12345678900,
"name": "Rafael Revendedor",
"email": "rafael-revendedor@hotmail.com",
"password": "123456"
}
}'
- Code: 201
- Content:
{
"id": 1,
"msg": "saved"
}- Code: 400
- Content:
{
"msg": "{{error message}}"
}POST /v1/auth
Baisc Auth is required.
curl --user 12345678900:123456 --location --request POST 'localhost:5000/v1/auth'
- Code: 200
- Content:
{
"id": 1,
"token": "{{token}}"
}- Code: 400 | 401
- Content:
{
"msg": "{{error message}}"
}POST /v1/resellers/<reseller_id>/cashback
Bearer token and reseller_id are requrired.
curl --location --request GET 'localhost:5000/v1/resellers/1/cashback' \
--header 'Authorization: Bearer {{token}}'
- Code: 200
- Content:
{
"credit": "<<int:credit>>"
}- Code: 400 | 401 | 503
- Content:
{
"msg": "{{error message}}"
}POST /v1/purchases
Bearer token and all data fields are required.
curl --location --request POST 'localhost:5000/v1/purchases' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"code": "b111",
"value": 999.00,
"date": "2021-07-06",
"cpf": "12345678900"
}
}'
- Code: 201
- Content:
{
"id": 1,
"msg": "saved"
}- Code: 400 | 401
- Content:
{
"msg": "{{error message}}"
}GET /v1/purchases
Bearer token is required.
curl --location --request GET 'localhost:5000/v1/purchases' --header 'Authorization: Bearer {{token}}'
- Code: 200
- Content:
[
{
"cashback": 30.0,
"code": "b111",
"date": "2021-07-06",
"percent": 10,
"status": "Em validação",
"value": 300.0
}
]- Code: 400 | 401
- Content:
{
"msg": "{{error message}}"
}PUT /v1/purchases/<purchase_id>
Bearer token and purchase id are required.
curl --location --request PUT 'localhost:5000/v1/purchases/1' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"value": 300.0
}
}'
- Code: 200
- Content:
{
"code": "b111",
"date": "2021-07-06",
"status": "Em validação",
"value": 300.0
}- Code: 400 | 401
- Content:
{
"msg": "{{error message}}"
}DELETE /v1/purchases/<purchase_id>
Bearer token and purchase id are required.
curl --location --request DELETE 'localhost:5000/v1/purchases/1' \
--header 'Authorization: Bearer {{token}}'
- Code: 200
- Content:
{
"msg": "purchase deleted"
}- Code: 400 | 401
- Content:
{
"msg": "{{error message}}"
}