This document describes how a client makes requests to the bizAPIs system when Two-Factor Authentication (2FA) is required for Autoridade Tributária.
Overview
2FA Request Flow
Phase 1: Initial Request with Credentials
Step 1: Client Sends Initial Request
The client makes a POST request to the orchestrator endpoint with credentials:
Endpoint: POST /v2/documents/{service}
Request Body:
{
"user": "username",
"password": "password"
}
Step 2: OTP Required Detection
After submitting credentials, the system checks if 2FA is required.
If OTP is not required, the flow skips directly to Phase 4 (Data Extraction and Response).
Phase 2: OTP Required Response
Step 3: Generate Second Request Token
When OTP is required, the service generates a second request token
Step 4: Return OTP Required Response
Response to Client:
{
"otpResponse": {
"secondRequestTokenId": "unique-token-uuid",
"otpStatus": "OTP_REQUIRED",
"requestId": "original-request-id"
}
}
Phase 3: OTP Submission
Step 5: Client Sends OTP Code
The client makes a second request with the OTP code:
Endpoint: POST /v2/documents/{service}
Request Body:
{
"otp": "123456",
"secondRequestTokenId": "unique-token-uuid"
}
Key Points:
- The
secondRequestTokenId
from the previous response is required - No credentials are needed in this request
- The OTP code is provided by the user (received via SMS)
Step 6: Submit OTP to Portal
The service submits the OTP
Step 7: Verify Authentication
After OTP submission, the system verifies authentication
Phase 4: Data Extraction and Response
Step 8: Extract Data After Authentication
Once authenticated, the service proceeds with data extraction
Step 9: Return Final Response
The service returns the extracted data to the client
Success Response:
{
"data": {
"..."
}
}
Error Response:
{
"message": "..."
}
Error Handling
OTP Attempt Validation
The system checks OTP attempts remaining
{
"message": "Can't authenticate - number of OTP attempts is about to be exceeded. Authenticate manually"
}
Session Expiration
Sessions can expire if:
- The client takes too long to submit OTP (TTL default: 300 seconds)
- The browser session is terminated
- The service instance restarts
Error Response:
{
"message": "Session expired or not found"
}
Invalid OTP
If an invalid OTP is submitted, the authentication framework detects it during verification and returns:
{
"message": "Failed to login - Invalid Credentials"
}
Mock Requests for Testing
The system includes a Demo Mode that allows testing the 2FA flow without actual portal authentication. This is useful for:
- Integration testing
- Client application development
- Simulating various error scenarios
- Understanding the complete request/response flow
Request Structure
All requests (both demo and production) use the same structure:
Special Password Values for Demo Mode
1. Successful Authentication (No OTP)
Password: Any value not matching special keywords (e.g., "success"
, "test123"
)
Request:
{
"user": "test-user",
"password": "success"
}
Response:
{
"data": {
"atInteracoesList": [
{
"tax": "IUC",
"description": "Entrega da declaração",
"date": "2025-10-13"
}
],
"atPiList": [
{
"title": "IUC",
"status": "verde"
}
],
"atAlertsList": [
{
"descriptionName": "IRC",
"description": "Data limite para entrega da declaração Modelo 25 de IRC relativo a 2025",
"limitDate": "2025-10-13"
}
],
"requestId": "generated-uuid"
}
}
2. OTP Required Scenario
Password: "otprequired"
(case-insensitive)
Initial Request:
{
"user": "test-user",
"password": "otprequired"
}
Initial Response:
{
"otpResponse": {
"requestId": "generated-uuid",
"secondRequestTokenId": "e67fe840-e6e5-4c98-a37e-1a79bca43035",
"otpStatus": "OTP_REQUIRED"
}
}
Second Request (with OTP):
{
"otp": "123456",
"secondRequestTokenId": "e67fe840-e6e5-4c98-a37e-1a79bca43035"
}
Final Response:
{
"data": {
"atInteracoesList": [...],
"atPiList": [...],
"atAlertsList": [...],
"requestId": "generated-uuid"
}
}
3. Error Scenarios
Each error scenario is triggered by a specific password value:
3.1. Session Expired
Password: "sessionexpired"
Response:
{
"message": "Session expired or not found"
}
3.2. Invalid Credentials
Password: "invalidcredentials"
Response:
{
"message": "Failed to login - Invalid Credentials"
}
3.3. Problem During Authentication
Password: "problemduringauthentication"
Response:
{
"message": "Failed to login - Problem during authentication"
}
3.4. OTP Error in Process
Password: "otperrorinprocess"
Response:
{
"message": "Failed to submit OTP - Error in process"
}
3.5. OTP Exception in Process
Password: "otpexceptioninprocess"
Response:
{
"message": "Failed to submit OTP - Exception occurred in process"
}
3.6. OTP Attempts Exceeded
Password: "numberofotpattemptsexceeded"
Response:
{
"message": "Can't authenticate - number of OTP attempts is about to be exceeded. Authenticate manually"
}
3.7. Problem Reaching Authentication Page
Password: "reachauthentication"
Response:
{
"message": "Failed to login - Problem reaching the authentication page."
}
3.8. Page Timeout
Password: "pagetimeout"
Response:
{
"message": "Problem loading the page (timeout)"
}
3.9. Extract Data Error
Password: "extractdata"
Response:
{
"message": "Failed to extract data"
}
3.10. Login Timeout
Password: "logintimeout"
Response:
{
"message": "Failed to login - Website Timeout"
}
Complete 2FA Flow Example (Demo Mode)
Scenario: User authentication requiring OTP
Step 1: Initial Authentication Request
curl -X POST /v2/documents/{service} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{
"{
"user": "test-user",
"password": "otprequired"
}"
}
Step 1 Response:
{
"otpResponse": {
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"secondRequestTokenId": "e67fe840-e6e5-4c98-a37e-1a79bca43035",
"otpStatus": "OTP_REQUIRED"
}
}
Step 2: Submit OTP Code
curl -X POST /v2/documents/{service} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{
"{
"otp": "123456",
"secondRequestTokenId": "e67fe840-e6e5-4c98-a37e-1a79bca43035"
}"
}
Step 2 Response:
{
"data": {
"atInteracoesList": [
{
"tax": "IUC",
"description": "Entrega da declaração",
"date": "2025-10-20"
},
{
"tax": "IRS",
"description": "Entrega da declaração",
"date": "2025-10-25"
}
],
"atPiList": [
{
"title": "IUC",
"status": "verde"
},
{
"title": "IRS",
"status": "amarelo"
},
{
"title": "Patrimonio",
"status": "verde"
}
],
"atAlertsList": [
{
"descriptionName": "IRC",
"description": "Data limite para entrega da declaração Modelo 25 de IRC relativo a 2025",
"limitDate": "2025-11-15"
},
{
"descriptionName": "IVA",
"description": "Data limite para entrega da declaração Modelo (texto exemplo)",
"limitDate": "2025-10-30"
}
],
"requestId": "550e8400-e29b-41d4-a716-446655440000"
}
}
Testing Checklist
Use demo mode to test the following scenarios:
OTP required flow
- Password:
"otprequired"
- Expected: OTP response → submit OTP → data returned
- This helps simulate the 2FA response flow
Session expiration
- Password:
"sessionexpired"
- Expected: Error message about expired session
Invalid credentials
- Password:
"invalidcredentials"
- Expected: Error message about invalid credentials
OTP attempt limit
- Password:
"numberofotpattemptsexceeded"
- Expected: Error message to authenticate manually
OTP submission errors
- Password:
"otperrorinprocess"
or"otpexceptioninprocess"
- Expected: Error message about OTP submission failure
Network/timeout errors
- Password:
"pagetimeout"
or"logintimeout"
- Expected: Error message about timeout
Data extraction failure
- Password:
"extractdata"
- Expected: Error message about extraction failure
Successful authentication without OTP
- Password: other value
- Expected: Data returned immediately
Note: In demo mode, any OTP code will be accepted as long as the correct secondRequestTokenId
is provided.
Security Considerations
- Token Security:
secondRequestTokenId
is a UUID, preventing guessing attacks - Session Isolation: Each requestId has its own isolated session
- OTP Attempt Limiting: System checks remaining OTP attempts before submission
- Time-Based Expiration: Sessions expire after configured TTL
- Error Message Sanitization: Detailed errors are logged but generic messages returned to clients
2FA Error Messages Reference
This section lists all error messages that were added or modified as part of the 2FA feature implementation.
Authentication Errors
1. Session expired or not found
HTTP Status: 200 (returned in response body) Context: Occurs when attempting to submit OTP for a session that no longer exists Response Example:
{
"message": "Session expired or not found"
}
Causes:
- Client took longer than the TTL (default 300 seconds) to submit OTP
- Invalid
secondRequestTokenId
provided
2. Failed to login - Problem during authentication
HTTP Status: 200 (returned in response body) Context: Generic authentication failure before OTP stage Response Example:
{
"message": "Failed to login - Problem during authentication"
}
Causes:
- Portal returned an error page after credential submission
- Portal structure changed and elements could not be found
- Unexpected exception during authentication process
3. Failed to login - Invalid Credentials
HTTP Status: 200 (returned in response body) Context: Portal explicitly indicated invalid username or password Response Example:
{
"message": "Failed to login - Invalid Credentials"
}
Causes:
- Incorrect username provided
- Incorrect password provided
- Invalid OTP code submitted
4. Can't authenticate - number of OTP attempts is about to be exceeded. Authenticate manually
HTTP Status: 200 (returned in response body) Context: Portal shows only 1 OTP attempt remaining Response Example:
{
"message": "Can't authenticate - number of OTP attempts is about to be exceeded. Authenticate manually"
}
Causes:
- Multiple invalid OTP codes have been submitted
- Portal security measure to prevent brute force attacks
- User has 1 OTP submission attempt remaining
Resolution:
- User MUST authenticate manually through the portal website
- System will not submit the final attempt to avoid account lockout
- After manual authentication, the counter will reset
5. Failed to submit OTP - Error in process
HTTP Status: 200 (returned in response body) Context: Generic error during OTP submission process Response Example:
{
"message": "Failed to submit OTP - Error in process"
}
Causes:
- Portal returned unexpected response during OTP submission
6. Failed to submit OTP - Exception occurred in process
HTTP Status: 200 (returned in response body) Context: Unexpected exception during OTP submission Response Example:
{
"message": "Failed to submit OTP - Exception occurred in process"
}
Causes:
- Unhandled exception in OTP submission code