Apex 26.1 Per User Token Management

Oracle APEX & PL/SQL Developer with 10 years of experience. Working mainly with manufacturing industry. My work is my passion. Avid gamer.
Oracle APEX 26.1 brings more AI features than ever.
More AI features means more governance, especially around token usage.
APEX can limit token usage per service over 24 hours, but not directly per app user.
In this post, I will show a simple pattern to enforce per-user limits.
What we will build:
A table to log AI usage per user
Request/response handlers in APEX AI configuration
Daily quota checks with warning and hard-stop behavior
Let's start by creating a table that will store all our users' AI calls.
create table ai_stats (
id number default on null to_number(sys_guid(), 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
constraint ai_stats_id_pk primary key,
apex_user varchar2(4000 char),
input_tokens number,
output_tokens number,
total_tokens number,
resp_time date,
component_name varchar2(4000 char),
component_static_id varchar2(4000 char)
);
Then we need to intercept the standard Oracle APEX calls to the LLM. Fortunately, Oracle APEX 26.1 gives us a standard way to do that.
Go to the Edit Application Definition of your chosen APEX app, then to the AI tab.
What we are interested in are the Request Handler Procedure and Response Handler Procedure fields. By default, they are empty.
Enter the following values:
ai_handler.ai_request
ai_handler.ai_response
Now every LLM request and response in your app will be routed through the ai_handler package.
The request handler blocks over-limit calls before they run, while the response handler logs usage and adds warnings as users approach the limit.
This implementation enforces limits based on total_tokens (input + output), not input tokens alone.
So let's create it:
create or replace package ai_handler as
procedure ai_request (
p_param in apex_ai.t_chat_request_handler_param,
p_result in out nocopy apex_ai.t_chat_request_handler_result
);
procedure ai_response (
p_param in apex_ai.t_chat_response_handler_param,
p_result in out nocopy apex_ai.t_chat_response_handler_result
);
end ai_handler;
/
create or replace package body ai_handler as
g_daily_total_allowance number := 10000;
g_daily_total_allowance_warning_threshold number := 8000;
procedure ai_request (
p_param in apex_ai.t_chat_request_handler_param,
p_result in out nocopy apex_ai.t_chat_request_handler_result
) is
l_total_tokens number;
begin
select nvl(sum(total_tokens),0)
into l_total_tokens
from ai_stats
where apex_user = sys_context(
'APEX$SESSION',
'APP_USER'
)
and trunc(resp_time) = trunc(sysdate);
if l_total_tokens > g_daily_total_allowance then
RAISE_APPLICATION_ERROR(-20001, 'Daily token allowance exceeded. You have used ' || l_total_tokens || ' total tokens today, which exceeds the daily allowance of ' || g_daily_total_allowance || ' tokens.');
end if;
end ai_request;
procedure ai_response (
p_param in apex_ai.t_chat_response_handler_param,
p_result in out nocopy apex_ai.t_chat_response_handler_result
) is
l_total_tokens number;
begin
insert into ai_stats (
apex_user,
input_tokens,
output_tokens,
total_tokens,
resp_time,
component_name,
component_static_id
) values (
sys_context('APEX$SESSION','APP_USER'),
p_result.response.input_tokens,
p_result.response.output_tokens,
p_result.response.total_tokens,
sysdate,
p_param.component.name,
p_param.component.static_id );
select nvl(sum(total_tokens),0)
into l_total_tokens
from ai_stats
where apex_user = sys_context(
'APEX$SESSION',
'APP_USER'
)
and trunc(resp_time) = trunc(sysdate);
if l_total_tokens > g_daily_total_allowance then
RAISE_APPLICATION_ERROR(-20001, 'Daily token allowance exceeded. You have used ' || l_total_tokens || ' total tokens today, which exceeds the daily allowance of ' || g_daily_total_allowance || ' tokens.');
end if;
if
l_total_tokens > g_daily_total_allowance_warning_threshold
and p_result.response.message.message is not null
then
p_result.response.message.message := p_result.response.message.message
|| chr(10)
|| 'Warning: You have used '
|| l_total_tokens
|| ' total tokens today, which is approaching the daily allowance of '
|| g_daily_total_allowance
|| ' tokens.';
end if;
end ai_response;
end ai_handler;
And that's it.
You may want to modify the g_daily_total_allowance and g_daily_total_allowance_warning_threshold variables. Or even move them to a separate table and build a whole system around this approach.
This is how it looks with a warning:
And this is what will happen when you exceed the limit:
APEX does not currently provide a clean cancel mechanism for this flow, so raising an application error is the most reliable way to stop over-limit requests.
With warning thresholds in place, users get clear notice before they hit the hard limit.
