Build with ARA.
Challenge definitions for community tools, served through the Academy.
Start here
- Use this base URL:
https://labs.almeidaracingacademy.com - Read the integration guide and import OpenAPI into your API tooling.
- Run the reference client with Node.js 24 to try login and challenge reads.
- Implement the same flow in your overlay and match the returned car and track IDs to iRacing.
Desktop authentication
- Create a login transaction with a fresh S256 proof.
- Show the returned code in the app and open the browser login link.
- The member enters the code and signs in with the Academy.
- Poll every five seconds with your original proof to receive an ARA session token.
Send the token in Authorization: Bearer …. Sessions last 12 hours. Sign out with DELETE /api/v1/auth/session. No localhost callback, shared secret or refresh token is needed in your application.
See the step-by-step login contract for exact requests, responses and error handling.
Training plans
Regular and weekly challenges use the same collection and detail routes. Personal results and live iRacing telemetry are outside this API's scope.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/garage61/training-plans | List ARA training plans |
| GET | /api/v1/garage61/training-plans/{trainingPlanId} | Read challenges, targets and car/track mappings |
Example authenticated request
curl 'https://labs.almeidaracingacademy.com/api/v1/garage61/training-plans?limit=100&offset=0' \
-H "Authorization: Bearer $ARA_ACCESS_TOKEN"Collection responses contain team, items, total, limit and offset. Follow pagination, then request each selected plan by ID. The OpenAPI specification contains full response examples.
Match the iRacing session
- Process
target_timecontent; preserve or skip other content types safely. - Check
platform === "iracing", then comparetrackInfo.platform_idandcarInfos[].platform_idwith the simulator's IDs. Garage61 IDs are different. - Medal targets use
labelandlapTimein seconds. Do not infer tiers from array order. - An explicitly empty
carslist permits all cars. Missing mappings for a nonempty list do not. - Use plan and content IDs for local progress. Date windows and weather fields are not guaranteed; do not infer weekly eligibility from creation timestamps.
Polling and failures
Fetch on startup and at most once every five minutes while the app is in use. The protective limits are 120 requests per minute per IP and 60 per minute per user. Vercel also limits all API traffic to 240 per minute per IP per region before it reaches the service. These are not recommended polling rates.
Respect Retry-After on 429, or wait 60 seconds if absent. Edge errors may have a non-JSON body. Use bounded retries with jitter for temporary failures. Show cached data as stale when appropriate; do not treat failed requests as an empty challenge list.
See the error reference for status codes. A 503 indicates temporary unavailability, not an empty challenge list.