Access Denied Error
https://bessapay.net/errors/access-deniedOverview
An Access Denied error occurs when a user has proper authentication but is denied access to a resource due to business rules or policy restrictions, rather than just missing permissions. This error is returned with HTTP status code 403 (Forbidden).
Unlike the more general Forbidden error, Access Denied errors are typically related to business policies, account status, or specific circumstances that prevent an otherwise authenticated and authorized user from performing an action.
Details
- Error Code: ACCESS_DENIED
- HTTP Status: 403
- Error Type: Client Error
Common scenarios
- • Account is suspended or under review
- • User has exceeded transaction limits
- • Geographical restrictions
- • Business hours restrictions
- • Compliance or regulatory restrictions
Example
1{
2 "type": "https://bessapay.net/errors/access-denied",
3 "title": "Access Denied",
4 "status": 403,
5 "detail": "Your account has been suspended due to suspicious activity",
6 "instance": "/api/v1/payments/transfer",
7 "errorCode": "ACCESS_DENIED",
8 "timestamp": "2023-06-15T21:05:18Z",
9 "reason": "ACCOUNT_SUSPENDED",
10 "resolutionSteps": [
11 "Contact customer support to verify your identity",
12 "Complete the account verification process"
13 ]
14}How to Handle
Check account status
Verify that the user's account is in good standing and not suspended or restricted. Access denied errors often relate to account status issues.
Look for resolution steps
The error response may include a resolutionSteps array with actions that can be taken to resolve the issue. Display these steps to the user.
Check transaction limits
If the error occurs during a transaction, check if the user has exceeded their transaction limits (daily, monthly, or per-transaction limits).
Contact support
Many access denied errors require intervention from support staff. Provide easy access to contact support when these errors occur.
1// Example of handling Access Denied with support contact
2function handleAccessDenied(errorData) {
3 // Create a case for the support team
4 const caseId = createSupportCase({
5 errorType: errorData.type,
6 errorDetail: errorData.detail,
7 errorCode: errorData.errorCode,
8 timestamp: errorData.timestamp,
9 userId: currentUser.id,
10 instance: errorData.instance
11 });
12
13 // Show error dialog with support case info
14 showErrorDialog({
15 title: "Access Restricted",
16 message: errorData.detail,
17 supportCaseId: caseId,
18 contactOptions: [
19 {
20 type: "email",
21 label: "Email Support",
22 action: () => openEmailSupport(caseId)
23 },
24 {
25 type: "chat",
26 label: "Live Chat",
27 action: () => openLiveChat(caseId)
28 },
29 {
30 type: "phone",
31 label: "Call Support",
32 action: () => showPhoneSupport(caseId)
33 }
34 ]
35 });
36
37 // Log the event for analytics
38 logAccessDeniedEvent({
39 reason: errorData.reason,
40 timestamp: errorData.timestamp,
41 userId: currentUser.id,
42 caseId: caseId
43 });
44}Look for alternative options
Sometimes there are alternative ways to achieve what the user wants that don't trigger the restrictions. For example, splitting a large transaction into smaller ones if there's a per-transaction limit.
Code Example: Comprehensive Access Denied Handling
1// Complete example of handling various access denied scenarios
2class AccessManager {
3 constructor(apiClient) {
4 this.apiClient = apiClient;
5 }
6
7 // Handle an access denied error
8 async handleAccessDenied(errorData, actionContext) {
9 // Determine the reason for access denial
10 const reason = errorData.reason || 'UNKNOWN';
11
12 switch (reason) {
13 case 'ACCOUNT_SUSPENDED':
14 return this.handleAccountSuspended(errorData, actionContext);
15
16 case 'LIMIT_EXCEEDED':
17 return this.handleLimitExceeded(errorData, actionContext);
18
19 case 'GEO_RESTRICTED':
20 return this.handleGeoRestriction(errorData, actionContext);
21
22 case 'VERIFICATION_REQUIRED':
23 return this.handleVerificationRequired(errorData, actionContext);
24
25 default:
26 return this.handleGenericAccessDenied(errorData, actionContext);
27 }
28 }
29
30 // Handle suspended account
31 async handleAccountSuspended(errorData, actionContext) {
32 // Check if the account can be automatically reactivated
33 const accountStatus = await this.apiClient.getAccountStatus();
34
35 if (accountStatus.canReactivate) {
36 return {
37 handled: true,
38 resolution: 'action',
39 message: 'Your account has been temporarily suspended.',
40 actions: [
41 {
42 label: 'Reactivate Account',
43 action: () => this.apiClient.reactivateAccount()
44 },
45 {
46 label: 'Contact Support',
47 action: () => this.openSupportChannel()
48 }
49 ]
50 };
51 }
52
53 // Account needs manual intervention
54 return {
55 handled: true,
56 resolution: 'support',
57 message: 'Your account has been suspended and requires verification.',
58 supportCaseId: this.createSupportCase(errorData),
59 actions: [
60 {
61 label: 'Contact Support',
62 action: () => this.openSupportChannel()
63 }
64 ]
65 };
66 }
67
68 // Handle transaction limits
69 async handleLimitExceeded(errorData, actionContext) {
70 // Get the current limits and usage
71 const limits = await this.apiClient.getTransactionLimits();
72
73 // Check if this is a transaction amount limit
74 if (actionContext.type === 'transaction' && actionContext.amount > limits.perTransaction) {
75 // Offer to split the transaction
76 const recommendedSplit = Math.ceil(actionContext.amount / limits.perTransaction);
77
78 return {
79 handled: true,
80 resolution: 'adjust',
81 message: `This transaction exceeds your limit of ${formatCurrency(limits.perTransaction)}`,
82 limitInfo: limits,
83 recommendations: [
84 {
85 label: `Split into ${recommendedSplit} transactions`,
86 action: () => this.splitTransaction(actionContext, recommendedSplit)
87 },
88 {
89 label: 'Reduce Amount',
90 action: () => this.adjustTransactionAmount(actionContext, limits.perTransaction)
91 },
92 {
93 label: 'Request Limit Increase',
94 action: () => this.requestLimitIncrease(actionContext.amount)
95 }
96 ]
97 };
98 }
99
100 // Check if this is a daily limit
101 if (limits.dailyRemaining <= 0) {
102 const resetTime = new Date(limits.dailyResetTimestamp);
103
104 return {
105 handled: true,
106 resolution: 'wait',
107 message: 'You have reached your daily transaction limit',
108 limitInfo: limits,
109 resetInfo: {
110 time: resetTime,
111 formattedTime: formatDateTime(resetTime)
112 },
113 actions: [
114 {
115 label: 'Request Limit Increase',
116 action: () => this.requestLimitIncrease(actionContext.amount)
117 },
118 {
119 label: 'Try Tomorrow',
120 action: () => this.scheduleTransaction(actionContext, resetTime)
121 }
122 ]
123 };
124 }
125
126 // Generic limit handling
127 return {
128 handled: true,
129 resolution: 'info',
130 message: 'You have exceeded your transaction limits',
131 limitInfo: limits,
132 actions: [
133 {
134 label: 'View Limits',
135 action: () => this.showLimitsPage()
136 },
137 {
138 label: 'Request Increase',
139 action: () => this.requestLimitIncrease()
140 }
141 ]
142 };
143 }
144
145 // Handle geographical restrictions
146 handleGeoRestriction(errorData, actionContext) {
147 return {
148 handled: true,
149 resolution: 'info',
150 message: 'This action is not available in your current location',
151 restrictionInfo: {
152 currentRegion: errorData.currentRegion,
153 allowedRegions: errorData.allowedRegions
154 },
155 actions: [
156 {
157 label: 'Learn More',
158 action: () => this.showRegionalRestrictions()
159 }
160 ]
161 };
162 }
163
164 // Handle verification requirements
165 async handleVerificationRequired(errorData, actionContext) {
166 // Get the verification status
167 const verificationStatus = await this.apiClient.getVerificationStatus();
168
169 return {
170 handled: true,
171 resolution: 'verification',
172 message: 'Additional verification is required to perform this action',
173 verificationInfo: verificationStatus,
174 actions: [
175 {
176 label: 'Complete Verification',
177 action: () => this.startVerificationProcess(verificationStatus.requiredSteps)
178 },
179 {
180 label: 'Learn More',
181 action: () => this.showVerificationInfo()
182 }
183 ]
184 };
185 }
186
187 // Generic handler for other access denied reasons
188 handleGenericAccessDenied(errorData, actionContext) {
189 return {
190 handled: true,
191 resolution: 'support',
192 message: errorData.detail || 'You do not have permission to perform this action',
193 supportCaseId: this.createSupportCase(errorData),
194 actions: [
195 {
196 label: 'Contact Support',
197 action: () => this.openSupportChannel()
198 },
199 {
200 label: 'Try Later',
201 action: () => this.dismissError()
202 }
203 ]
204 };
205 }
206
207 // Create a support case
208 createSupportCase(errorData) {
209 // Implementation details...
210 return 'CASE-' + Math.random().toString(36).substr(2, 9).toUpperCase();
211 }
212
213 // Open support channel
214 openSupportChannel() {
215 // Implementation details...
216 }
217}
218
219// Usage example
220async function performAction(action, context) {
221 try {
222 const result = await apiClient.request(action, context);
223 return result;
224 } catch (error) {
225 if (error.type === 'https://bessapay.net/errors/access-denied') {
226 const accessManager = new AccessManager(apiClient);
227 const handlerResult = await accessManager.handleAccessDenied(error, context);
228
229 if (handlerResult.handled) {
230 // Display appropriate UI based on the handler result
231 displayAccessDeniedUI(handlerResult);
232 return null;
233 }
234 }
235
236 // Handle other errors
237 console.error('Action failed:', error);
238 showErrorMessage('An error occurred while performing this action.');
239 return null;
240 }
241}