Skip to main content
RapidDev - Software Development Agency
outsystems-tutorial

API Gateway Patterns and Rate Limiting in OutSystems

OutSystems does not include a built-in API gateway. For production deployments, place an external gateway (AWS API Gateway, Kong, Apigee, Azure APIM) in front of your exposed OutSystems REST APIs. For lightweight rate limiting in O11 without an external gateway, implement a counter entity in the OnAuthentication callback. ODC provides platform-level adaptive throttling at 100 req/min for management APIs, but application-level rate limiting still requires external infrastructure.

What you'll learn

  • Understand why OutSystems requires external API gateway infrastructure for production APIs
  • Implement a lightweight rate limiting pattern using the OnAuthentication callback and a counter entity
  • Configure AWS API Gateway, Kong, or Azure APIM as a reverse proxy in front of OutSystems REST APIs
  • Apply API versioning and deprecation strategies that work with external gateways
  • Understand the ODC platform-level throttling model and how it differs from O11
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced10 min read30-40 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

OutSystems does not include a built-in API gateway. For production deployments, place an external gateway (AWS API Gateway, Kong, Apigee, Azure APIM) in front of your exposed OutSystems REST APIs. For lightweight rate limiting in O11 without an external gateway, implement a counter entity in the OnAuthentication callback. ODC provides platform-level adaptive throttling at 100 req/min for management APIs, but application-level rate limiting still requires external infrastructure.

API Gateway Architecture for OutSystems Applications

When you expose REST APIs from OutSystems and open them to external consumers, you immediately need capabilities that OutSystems does not provide out of the box: rate limiting, request throttling, API key lifecycle management, usage analytics, developer portal documentation, and DDoS protection. The correct architecture is to put an industry-standard API gateway between the internet and your OutSystems module. This tutorial covers both a lightweight in-OutSystems rate limiting pattern for simpler cases and the recommended external gateway integration pattern for enterprise deployments.

Prerequisites

  • An exposed REST API already working in OutSystems (Logic tab → Integrations → REST → Expose REST API)
  • Authentication already configured on the exposed API (see outsystems-api-authentication tutorial)
  • For external gateway sections: access to AWS API Gateway, Kong, Apigee, or Azure API Management
  • Service Center access to monitor API usage logs (O11) or ODC Portal for traces (ODC)

Step-by-step guide

1

Understand what OutSystems provides vs what you need a gateway for

OutSystems exposed REST APIs provide by default: - CORS headers (Access-Control-Allow-Origin: *) - Basic and Custom Authentication via OnAuthentication callback - HTTPS (SSL/TLS) on OutSystems Cloud environments - Auto-generated OpenAPI/Swagger documentation - Request/response logging in Service Center → Monitoring → Integrations OutSystems does NOT provide: - Rate limiting or request throttling - Request/response transformation at the network edge - API key lifecycle management (issuance, rotation, quotas) - Developer portal with self-service API key sign-up - DDoS protection at the API layer - Geographic routing or latency-based routing - Monetization and billing per API call For internal integrations (other OutSystems modules, trusted internal services), built-in authentication is usually sufficient. For external APIs exposed to third-party developers, a gateway is required.

Expected result: You have a clear understanding of the capability gaps and can make an informed architectural decision about whether to use an external gateway.

2

Implement lightweight rate limiting in the OnAuthentication callback

For cases where an external gateway is not available, implement rate limiting directly in OutSystems using a database counter pattern. First, create an entity: Data tab → Entities → Database → right-click → Add Entity. Name it ApiRateLimit with attributes: - ApiKeyId (ApiKey Identifier) - WindowStart (DateTime) - RequestCount (Integer) - MaxRequests (Integer, default: 100) - WindowSeconds (Integer, default: 60) In the OnAuthentication action (Logic tab → Integrations → REST → [YourAPI] → OnAuthentication), after the API key is validated, add: Start → ... validate API key ... → [GetCurrentWindow: Aggregate, Filter: ApiRateLimit.ApiKeyId = ValidatedKeyId AND ApiRateLimit.WindowStart >= AddSeconds(CurrDateTime(), -ApiRateLimit.WindowSeconds), MaxRecords: 1] → If (GetCurrentWindow.List.Empty) [True] CreateApiRateLimit (WindowStart = CurrDateTime(), RequestCount = 1, MaxRequests = 100, WindowSeconds = 60, ApiKeyId = ValidatedKeyId) [False] If (GetCurrentWindow.List.Current.ApiRateLimit.RequestCount >= GetCurrentWindow.List.Current.ApiRateLimit.MaxRequests) [True] Raise Exception (RateLimitExceeded, User Exception) -- returns HTTP 429 [False] UpdateApiRateLimit (Id = GetCurrentWindow.Id, RequestCount = GetCurrentWindow.RequestCount + 1) → End

Expected result: API consumers exceeding their request quota receive HTTP 429 Too Many Requests. The rate limit resets after the configured window.

3

Add Retry-After header to 429 responses

When returning a 429 rate limit error, best practice is to include a Retry-After header telling the consumer when they can retry. In the OnAuthentication callback, when raising RateLimitExceeded, you cannot directly add a response header from the exception. Instead, use the OnAfterResponse callback on the same REST API node: In OnAfterResponse (set On After Response → New OnAfterResponse): Start → If (Response.StatusCode = 429) → [True] GetRequestHeader (Name = "X-API-Key") → GetRateLimitWindow (Aggregate for the key) → Assign RetryAfterSeconds = AddSeconds(GetRateLimitWindow.List.Current.ApiRateLimit.WindowStart, GetRateLimitWindow.List.Current.ApiRateLimit.WindowSeconds) → Use SetResponseHeader (HTTPRequestHandler) to add Retry-After header → [False] pass → Assign CustomizedResponse = Response → End Alternatively, include the retry-after information in the exception message so it appears in the JSON error body: "Rate limit exceeded. Retry after " + IntegerToText(SecondsRemaining) + " seconds."

Expected result: Rate-limited responses include timing information so consumers implement proper back-off without guessing.

4

Integrate AWS API Gateway as a front-end proxy

For production APIs, place AWS API Gateway in front of OutSystems: 1. In AWS Console, create a new REST API in API Gateway 2. Create a resource and method matching your OutSystems endpoint (e.g., GET /products/{id}) 3. Set Integration Type to HTTP Proxy 4. Set Endpoint URL to your OutSystems endpoint: https://yourserver.outsystemscloud.com/Module/rest/v1/products/{id} 5. Configure method request to pass the {id} path parameter through 6. Add a Usage Plan: API Gateway → Usage Plans → Create → set Throttle (rate/burst) and Quota (daily limit) 7. Create an API Key in API Gateway and attach it to the Usage Plan 8. Deploy the API to a Stage (dev/prod) OutSystems-side configuration: - Update your OnAuthentication to validate the AWS API Gateway consumer key OR trust that AWS handles authentication and configure OutSystems to accept only requests from the AWS Gateway IP ranges - Consider removing OutSystems-level authentication for gateway traffic to avoid double authentication overhead Environment variable configuration: Store the API Gateway URL as a Site Property for use in documentation and logging.

Expected result: External consumers access your OutSystems APIs through the AWS API Gateway URL. Rate limiting, API key management, and usage analytics are handled by AWS.

5

Configure Kong as a self-hosted gateway for on-premises O11

For on-premises O11 deployments, Kong is a popular open-source gateway: 1. Install Kong (Docker: docker run -d --name kong kong:latest) 2. Configure a Service pointing to your OutSystems server: POST http://localhost:8001/services { "name": "outsystems-api", "url": "https://yourserver/Module/rest/v1" } 3. Add a Route: POST http://localhost:8001/services/outsystems-api/routes { "paths": ["/api/v1"], "strip_path": true } 4. Enable the Rate Limiting plugin: POST http://localhost:8001/services/outsystems-api/plugins { "name": "rate-limiting", "config": { "minute": 100, "hour": 1000, "policy": "local" } } 5. Enable the Key Auth plugin for API key management: { "name": "key-auth", "config": { "key_names": ["X-API-Key"] } } With Kong handling authentication and rate limiting, update your OutSystems OnAuthentication to either pass through (Authentication = None — only safe if Kong and OutSystems are on the same private network) or validate an internal key that Kong injects after its own validation.

Expected result: Kong proxies all requests to OutSystems, enforcing rate limits and API key validation before they reach the OutSystems module.

6

Understand ODC platform-level rate limiting

ODC differs from O11 in rate limiting: Platform-level limits (ODC, automatic, cannot be modified): - Management APIs (ODC Portal APIs): 100 requests/minute with adaptive throttling - Application REST APIs (your exposed endpoints): No platform-level request throttling — rate limiting is your responsibility - Container scaling: ODC scales containers automatically, so rate limiting is about protecting downstream systems and controlling costs, not protecting OutSystems itself For ODC application APIs: - Use the same OnAuthentication counter pattern from step 2 (works identically in ODC) - Preferred: integrate with AWS API Gateway (OutSystems uses AWS, so low latency) or use Cloudflare Workers in front of the ODC app domain - ODC Portal → App Security → provides vulnerability scanning but not rate limiting ODC adaptive throttling for management APIs returns HTTP 429 with Retry-After header automatically when the 100 req/min limit is exceeded — no configuration needed.

Expected result: You understand ODC's rate limiting model and have implemented the appropriate strategy for your deployment.

Complete working example

RateLimit_OnAuthentication_Pattern.txt
1/* OnAuthentication Action API Key Validation + Rate Limiting
2 Attached to: Exposed REST API node
3 Entities required:
4 - ApiKey (KeyValue Text, IsActive Boolean, ExpiresOn DateTime)
5 - ApiRateLimit (ApiKeyId FK, WindowStart DateTime, RequestCount Integer, MaxRequests Integer, WindowSecs Integer)
6*/
7
8Start
9 |
10 v
11[GetRequestHeader] Name = "X-API-Key" -> ApiKeyValue
12 |
13 v
14[GetApiKeyRecord] -- Aggregate
15 Filter: ApiKey.KeyValue = ApiKeyValue
16 AND ApiKey.IsActive = True
17 MaxRecords: 1
18 |
19 v
20[If] GetApiKeyRecord.List.Empty OR ApiKey.ExpiresOn < CurrDateTime()
21 |
22 True -->
23 [Raise Exception: InvalidApiKey (Security Exception)]
24 -- HTTP 401 returned
25 |
26 False -->
27 [Assign] ValidatedKeyId = GetApiKeyRecord.List.Current.ApiKey.Id
28 [Assign] MaxReq = GetApiKeyRecord.List.Current.ApiKey.RateLimit -- attribute on ApiKey entity
29 |
30 v
31 [GetCurrentWindow] -- Aggregate
32 Filter: ApiRateLimit.ApiKeyId = ValidatedKeyId
33 AND ApiRateLimit.WindowStart >= AddSeconds(CurrDateTime(), -60)
34 MaxRecords: 1
35 |
36 v
37 [If] GetCurrentWindow.List.Empty
38 |
39 True -->
40 [CreateApiRateLimit]
41 ApiKeyId = ValidatedKeyId
42 WindowStart = CurrDateTime()
43 RequestCount = 1
44 MaxRequests = MaxReq
45 WindowSecs = 60
46 |
47 False -->
48 [If] GetCurrentWindow.List.Current.ApiRateLimit.RequestCount >= MaxReq
49 |
50 True -->
51 [Raise Exception: RateLimitExceeded (User Exception)
52 Message = "Rate limit exceeded. Retry after "
53 + IntegerToText(60 - DiffSeconds(GetCurrentWindow.List.Current.ApiRateLimit.WindowStart, CurrDateTime()))
54 + " seconds."]
55 -- HTTP 429 returned
56 |
57 False -->
58 [UpdateApiRateLimit]
59 Id = GetCurrentWindow.List.Current.ApiRateLimit.Id
60 RequestCount = GetCurrentWindow.List.Current.ApiRateLimit.RequestCount + 1
61 |
62 v
63End

Common mistakes

Why it's a problem: Assuming OutSystems exposed REST APIs are protected from DDoS or abusive traffic by default

How to avoid: OutSystems Cloud provides basic network-level protection, but application-layer rate limiting and request throttling require explicit implementation. An unprotected public API with no rate limiting can be hammered by automated clients, exhausting your OutSystems platform capacity.

Why it's a problem: Implementing rate limiting in the action flow of each individual REST method instead of in OnAuthentication

How to avoid: Rate limiting should run before the method logic executes — implement it in OnAuthentication so it applies consistently to all methods in the API without duplicating logic. Per-method implementation is error-prone and easy to miss when adding new methods.

Why it's a problem: Not cleaning up old rate limit window records, causing the counter entity to grow indefinitely

How to avoid: Create a Timer (Logic tab → right-click Timers → Add Timer) that runs hourly and deletes ApiRateLimit records older than 2 hours: Delete Where WindowStart < AddHours(CurrDateTime(), -2). This keeps the table small and the rate limit lookups fast.

Why it's a problem: Using the same OutSystems endpoint URL directly in client documentation when an API Gateway is in use

How to avoid: Always expose the gateway URL in documentation, not the underlying OutSystems URL. The gateway URL is stable; the OutSystems URL may change during deployments or server migrations. Store the gateway URL as a Site Property for use in logging and documentation.

Best practices

  • Never rely solely on OutSystems-level authentication for public APIs — place a gateway in front to provide DDoS protection, rate limiting, and API key lifecycle management.
  • If implementing the database rate-limiting counter pattern, add an index on ApiRateLimit.ApiKeyId and ApiRateLimit.WindowStart to prevent this from becoming a performance bottleneck at scale.
  • Use separate rate limit tiers for different API consumers — free tier (100 req/min), paid tier (1000 req/min), partner tier (unlimited). Store the limit on the ApiKey entity rather than hardcoding it.
  • Set up a cleanup Timer to delete old ApiRateLimit records (older than 24 hours) — without cleanup the table grows unbounded and slows the rate limit lookups.
  • For AWS API Gateway integration, use AWS WAF alongside the gateway to block malicious traffic before it reaches your rate limit logic.
  • Document your rate limits in the API's Swagger description so consumers know the limits before hitting them.
  • Return the X-RateLimit-Limit and X-RateLimit-Remaining headers on every response (not just 429s) so consumers can proactively throttle their own request rates.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I'm running an OutSystems 11 application that exposes REST APIs to external partners. I need to implement rate limiting without an external API gateway. My OutSystems module has an ApiKey entity and an OnAuthentication callback already set up for API key validation. Help me design: 1) the ApiRateLimit entity schema with support for per-key rate limit tiers, 2) the rate limiting logic to add to OnAuthentication, 3) a cleanup Timer to delete old records, and 4) how to return the remaining quota in response headers.

OutSystems Prompt

I'm integrating AWS API Gateway in front of my OutSystems exposed REST API. The OutSystems API uses X-API-Key header authentication. I want AWS API Gateway to validate API keys using Usage Plans, and then pass through to OutSystems. Should I keep OutSystems authentication enabled or disable it? How should I configure the HTTP Proxy integration in AWS API Gateway to pass path parameters and query strings through correctly to the OutSystems endpoint format: https://server/Module/rest/v1/resource/{id}?

Frequently asked questions

Does OutSystems have any built-in rate limiting for exposed REST APIs?

No. OutSystems does not include application-level rate limiting for exposed REST APIs in either O11 or ODC. ODC has platform-level adaptive throttling for management APIs (100 req/min), but this does not apply to application endpoints you create. You must implement rate limiting either in the OnAuthentication callback using a counter entity pattern, or by placing an external API gateway (AWS, Kong, Apigee, Azure APIM) in front of your OutSystems endpoints.

What is the recommended API gateway for OutSystems Cloud deployments?

AWS API Gateway is the natural choice since OutSystems Cloud runs on AWS infrastructure — the two services are co-located in the same AWS regions, minimizing latency. For organizations already on Azure, Azure API Management integrates well with O11 deployments on Azure. For self-hosted O11, Kong (open-source) or nginx with lua-resty-limit-req are cost-effective options.

Can I implement rate limiting that persists across multiple OutSystems front-end servers in a farm setup?

The entity-based counter pattern in this tutorial uses the OutSystems database as a shared store, so it works correctly across multiple front-end servers in an O11 farm — all servers read from and write to the same database. The concern is write contention: at very high request rates (thousands per second), concurrent updates to the same rate limit window record can cause database locking. For those volumes, use an external gateway with a dedicated rate limiting backend (Redis, DynamoDB).

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.