Operational Flows
This section details the step-by-step operational flows for the most common transactions within the Evercycle API system.
Flow 1: Authenticate and Store Tokens
Actors: HTTP client, Flask server, Evercycle backend
Client sends
POST /api/authwith JSON body containingusernameandpassword.api_server.pyvalidates that both fields are present; returns 400 if not.api_server.pycallsapi_client.authenticate(username, password).evercycle_api.pybuilds the payload and POSTs tohttps://api.evercycle.io/v1/auth/signin.On success, the backend returns an
AuthenticationResultwith: *AccessToken*IdToken*RefreshTokenevercycle_api.pywrites these three tokens toevercycle-api/auth.properties.api_server.pyupdates global variables: *refresh_token← RefreshToken *token_expiry← now + 3600 secondsFlask session is marked authenticated.
Response
200 OKwith status “success” is returned to the client.
Flow 2: Call a Protected API with Valid Token
Actors: HTTP client, Flask server, Evercycle backend
Client sends a request to
/api/get-allwith method GET.call_api('get-all')is invoked.refresh_auth_token()is called.is_token_valid()checkstoken_expiryagainstnow + 60s.Token is valid → function returns
Trueimmediately.api_server.pyprepares parameters: * For GET, parameters come fromrequest.args(query string). * No special path-parameter handling needed forget-all.api_client.call_api('get-all')is executed.Config file
config/get-all.jsonis loaded.Auth headers are injected: *
access-token←access_tokenfromauth.properties*Authorization←id_tokenfromauth.propertiesHTTP GET is dispatched to
https://api.evercycle.io/v1/asset.Response JSON is returned to the client wrapped in:
{"status": "success", "data": <response>}
Flow 3: Call an API with Expired Token (Auto-Refresh)
Actors: HTTP client, Flask server, Evercycle backend
Client sends
GET /api/get-all.call_api('get-all')begins.refresh_auth_token()detects thattoken_expiryhas passed.Server attempts to POST to
https://api.evercycle.io/v1/auth/refreshwith the storedrefresh_token.If refresh succeeds: * New tokens are extracted. *
auth.propertiesis overwritten. *token_expiryis updated. * Flow continues as in Flow 2.If refresh fails: * Server falls back to re-authentication. * It reads
config/auth-signin.jsonfor username/password. * Callsapi_client.authenticate(username, password). * On success, updates globals and proceeds. * On failure, returns401 Unauthorizedto the client.
Flow 4: Get Asset by ID (Runtime Path Patching)
Actors: HTTP client, Flask server
Client sends
GET /api/get-asset-id?id=12345.call_api('get-asset-id')is invoked.Authentication check passes (Flow 2/3 logic).
Because
api_name == 'get-asset-id', the server enters special handling: * Extractsasset_idfromrequest.args.get('id'). * Overridesapi_info['path']to/v1/asset/{asset_id}. * Dynamically monkey-patchesapi_client.call_apiwithpatched_call_api.The patched function ignores the normal config-driven URL construction and directly builds
https://api.evercycle.io/v1/asset/12345.It injects headers and calls
requests.get.The response is parsed and returned to the client.
Note: the monkey-patch is temporary for the duration of that single call.
Flow 5: Create a New Asset
Actors: HTTP client, Flask server
Client sends
POST /api/createwith JSON body fields.call_api('create')begins.Authentication is verified.
Server loads
config/create.jsonto obtain default body values.Request JSON body is merged on top of the defaults:
merged_data = default_body.copy(); merged_data.update(request.json)The merged JSON string is passed as a parameter to
api_client.call_api.api_client.call_apiparses the JSON and setsuser_config['body'].HTTP POST is dispatched to
https://api.evercycle.io/v1/asset/create.Response is returned to the client.
Flow 6: Edit Asset (PUT with Path Parameter)
Actors: HTTP client, Flask server
Client sends
PUT /api/edit-asset-idwith JSON body containingidand any fields to update.call_api('edit-asset-id')begins.Authentication is verified.
Server extracts
asset_idfrom bodyidfield.It loads
config/edit-asset-id.jsonfor default body values.Request body (minus
id) is merged into defaults.api_info['path']andapi_info['url']are both overridden to/v1/asset/{asset_id}.api_client.call_apireceivesasset_idand the merged JSON string.The path parameter
{id}is substituted in the URL.HTTP PUT is dispatched.
Flow 7: Grade Update (PUT with Multiple Path Parameters)
Actors: HTTP client, Flask server
Client sends
PUT /api/gradewith JSON body containingid,grade, and optionallyprice.call_api('grade')begins.Server extracts
asset_idandgrade_namefrom the body.It loads
config/grade.jsonfor defaults.Body fields other than
idandgradeare merged into defaults.api_info['path']andapi_info['url']are overridden to/v1/pricebook/{asset_id}/{grade_name}.api_client.call_apisubstitutes both path parameters.HTTP PUT is dispatched to the constructed URL.
Flow 8: CLI Auth and Config Generation
Actors: Terminal user, api_runner.py, filesystem
User runs
python3 api_runner.py generateinsideevercycle-api/.ApiRunner.load_endpoints()reads all*.mdfiles in the directory.Each markdown file is parsed by
parse_markdown_file(): * First line →path* Second line →description* Regex search →methodandurl* Table sections →headers,parameters,body_paramsFor each endpoint, a JSON config file is written to
config/{api_name}.jsonwith empty/default values for headers, path_params, query_params, and body.User edits the JSON config files to set desired values.
User runs
python3 api_runner.py run auth-signin.On success,
_handle_auth_signin_response()extracts tokens and writesauth.properties._update_config_files_with_tokens()iterates all other JSON configs and injects the new tokens into theirheadersobjects.