Quick Start Guide
Option 1: Use Our SDK (Recommended for Most Use Cases)
The easiest way to integrate Efiwe is using our JavaScript SDK, which handles UI, offline caching, and user progress tracking.
Step 1: Add the SDK to your webpage
<script src="https://efiwe.com/api/efiwe-sdk.js"></script>
Step 2: Add a container for challenges
<div id="efiwe-challenge"></div>
Step 3: Initialize with one line of JavaScript
Display a single challenge. This example shows Challenge 1 from our HTML program.
<script>
EfiweSDK.renderChallenge('efiwe-challenge', 'html', 1);
</script>
- Change
'html'to'css'or'js'to load a challenge from our CSS or JavaScript program. - Change
'1'to any other number to display a different challenge. - Our HTML program has a maximum of 191 challenges.
- Our CSS program has a maximum of 298 challenges.
- Our JavaScript program has a maximum of 488 challenges.
Or display a range of challenges with navigation. This example shows challenges 1 to 50 from our HTML program, with navigation at the bottom.
<script>
EfiweSDK.renderChallengeList('efiwe-challenge', 'html', '1-50');
</script>
View a live sample of this range rendered on a webpage to see how it looks in action.
-
Change
'html'to'css'or'js'to load challenges from our CSS or JavaScript program. -
Change
'1-50'to any other range to display a different set of challenges. For example,'51-100'shows challenges 51 to 100. -
Change
'1-50'to'-80'to display challenges 1 to 80. -
Change
'1-50'to'50-'to display challenges from 50 to the last available challenge. -
Remove the range parameter entirely to display all challenges in the program. For example:
EfiweSDK.renderChallengeList('efiwe-challenge', 'html'); -
Pass a number instead of a range to start at a specific challenge:
EfiweSDK.renderChallengeList('efiwe-challenge', 'html', 25);
That's it! Right on your platform, your users now have access to interactive coding challenges with:
- Real-time code editor with syntax highlighting
- AI-powered diagnostics and hints
- Progress tracking in browser storage
Option 2: Direct API Integration (For Custom Implementations)
If you need more control or want to build your own UI, you can call the API directly.
Fetch a specific challenge:
// This fetches Challenge 1 from our HTML program. Update the program shortcode and challenge number as needed.
const response = await fetch('https://efiwe.com/api/api.php/api/html/challenge/1');
const challenge = await response.json();
console.log(challenge);
// Returns:
// {
// id: 1,
// topic: "Document Type Declaration",
// difficulty: "easy",
// introduction: "<p>HTML stands for HyperText Markup Language, and it's the fundamental building block of every website on the internet...",
// description: "Using the code example above, write the...",
// hints: ["Start with <!DOCTYPE and end with >."],
// explanation: "The doctype declaration tells the browser what type of document to expect."
// }
Validate user's code:
// Sample user code submission
const userCode = '<p>Hello World</p>';
// Update the program shortcode as needed.
const response = await fetch('https://efiwe.com/api/api.php/api/html/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 1, code: userCode, mode: 'default' })
});
const result = await response.json();
// Returns:
// {
// correct: true,
// feedback: "Great job!",
// diagnostics: []
// }
List all challenges (for building navigation):
// Update the program shortcode as needed.
const response = await fetch('https://efiwe.com/api/api.php/api/html/challenges');
const challenges = await response.json();
// Returns array of all challenges without solutions
// Use this to build custom challenge selectors or progress trackers
API Endpoints
The Efiwe API provides three core endpoints for accessing coding challenges and validating submissions:
GET: /api/{type}/challenges
Description: Retrieve challenges for a specific program. You can fetch all challenges or specify a range.
Parameters:
{type}- Challenge type:html,css, orjs
Endpoint Variations:
/api/html/challenges- All challenges/api/html/challenges/1-50- Challenges 1 to 50/api/html/challenges/51-- Challenge 51 to the last challenge/api/html/challenges/-50- First challenge to challenge 50
Examples:
// Fetch all HTML challenges
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges'
);
const allChallenges = await response.json();
// Fetch challenges 1-50 only
const rangeResponse = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges/1-50'
);
const challenges1to50 = await rangeResponse.json();
// Fetch from challenge 51 to the end
const fromResponse = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges/51-'
);
const challenges51toEnd = await fromResponse.json();
// Fetch first 50 challenges
const toResponse = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges/-50'
);
const firstFifty = await toResponse.json();
GET: /api/{type}/challenge/{id}
Description: Get a specific challenge by ID. Perfect for displaying individual challenges.
Parameters:
{type}- Challenge type:html,css, orjs{id}- Challenge ID (integer)
Example:
// Fetches Challenge 1 in our HTML program.
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/challenge/1'
);
const challenge = await response.json();
console.log(challenge);
// Returns:
// {
// id: 1,
// topic: "Document Type Declaration",
// difficulty: "easy",
// introduction: "<p>HTML stands for HyperText Markup Language, and it's the fundamental building block of every website on the internet...",
// description: "Using the code example above, write the...",
// hints: ["Start with <!DOCTYPE and end with >."],
// explanation: "The doctype declaration tells the browser what type of document to expect."
// }
POST: /api/{type}/validate
Description: Validate user's code submission. Returns Efiwe 1.0 AI-powered diagnostics and feedback. The mode parameter adjusts the similarity threshold: 'easy' (70%), 'intermediate' (80%), 'difficult' (90%), 'master' (100%). Default mode is AI-driven and adjusts based on user's error count (starts at 100%, lowers after repeated errors).
Parameters:
{type}- Challenge type:html,css, orjs
Request Body:
// Sample user code submission
{
"id": 1,
"code": "<p>Hello World</p>",
"mode": "default"
}
Example:
// Update the program shortcode as needed.
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/validate',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 1,
code: '<p>Hello World</p>',
mode: 'default'
})
}
);
const result = await response.json();
console.log(result);
// Returns:
// {
correct: true,
// feedback: "Great job!",
// diagnostics: []
// }
POST: /api/{type}/ai-feedback
Description: Get Efiwe 2.0 AI-powered feedback on user's code submission. Provides a short sentence of analysis. If AI is unavailable, falls back to pre-programmed responses. Responses are limited to 15 words maximum. The system rotates through multiple AI models for reliability.
Parameters:
{type}- Challenge type:html,css, orjs
Request Body:
{
"id": 1,
"code": "<p>Hello World</p>"
}
Example:
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/ai-feedback',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 1,
code: '<p>Hello World</p>'
})
}
);
const result = await response.json();
console.log(result);
// Returns:
// {
// feedback: "Correct! Your paragraph tag is properly opened and closed."
// }
POST: /api/{type}/ai-hint
Description: Request Efiwe 2.0 AI-generated hints for a specific challenge. Provides a short sentence of guidance. If AI is unavailable, falls back to pre-programmed hints. Responses are limited to 15 words maximum. The system rotates through multiple AI models for reliability.
Parameters:
{type}- Challenge type:html,css, orjs
Request Body:
{
"id": 1,
"code": "<p Hello World</p>"
}
Example:
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/ai-hint',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 1,
code: '<p Hello World</p>'
})
}
);
const result = await response.json();
console.log(result);
// Returns:
// {
// hint: "Remember that HTML tags need opening and closing brackets."
// }
POST: /api/{type}/ai-diagnose
Description: Get Efiwe 2.0 AI-powered diagnostics for incorrect code submissions. Returns an array of issues with solutions. If AI is unavailable, falls back to pre-programmed diagnostics. The system rotates through multiple AI models for reliability.
Parameters:
{type}- Challenge type:html,css, orjs
Request Body:
{
"id": 1,
"code": "<p>Hello World"
}
Example:
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/ai-diagnose',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 1,
code: '<p>Hello World'
})
}
);
const result = await response.json();
console.log(result);
// Returns:
// {
// diagnostics: [
// {
// issue: "Missing closing tag",
// solution: "Add </p> to close the paragraph tag"
// }
// ]
// }
API Keys & Rate Limits
Default Rate Limits
By default, our API allows 60 requests per minute per IP address. This is sufficient for most educational use cases, but if you need higher limits, you can purchase an API key.
Purchasing an API Key
API keys unlock higher rate limits based on your selected package. For example, a 500 request/minute package allows 500 requests per minute from your IP address.
Contact us at developer@efiwe.com to discuss API key packages that fit your needs.
Using Your API Key
With Direct API Calls:
Append your API key as a query parameter to any endpoint:
// Fetch challenges with API key
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges?api_key=YOUR-KEY-HERE'
);
// Validate with API key
const validateResponse = await fetch(
'https://efiwe.com/api/api.php/api/html/validate?api_key=YOUR-KEY-HERE',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 1, code: '<!DOCTYPE html>' })
}
);
With the SDK:
Set your API key once before rendering any challenges:
<script src="https://efiwe.com/api/efiwe-sdk.js"></script>
<script>
// Set your API key first
EfiweSDK.config.apiKey = 'YOUR-KEY-HERE';
// Now render challenges - all API calls will use your key
EfiweSDK.renderChallengeList('efiwe-challenge', 'html', '1-50');
</script>
Checking Rate Limit Status
Rate limit information is not returned in response headers. If you exceed the limit, you'll receive a 429 status with error message: {'error': 'Rate limit exceeded. Try again later.'}.
Important: Keep your API key secure. Never expose it in client-side code for public websites. For production use, proxy API calls through your backend server.
Advanced SDK Features
SDK Configuration
// Set API key for higher rate limits
EfiweSDK.config.apiKey = 'YOUR-KEY-HERE';
// Optionally override the API base URL
EfiweSDK.apiBase = 'https://your-custom-api.com/api.php';
Managing User Progress
// Check if a challenge is completed
const isCompleted = EfiweSDK.isCompleted('html', 5);
// Get user's submitted answer
const userAnswer = EfiweSDK.getAnswer('html', 5);
// Find next unanswered challenge in the full program
const nextChallenge = EfiweSDK.findFirstUnanswered('html');
// Note: Uses maxChallenges configuration for program limits
// Find next in range
const nextInRange = EfiweSDK.findFirstUnansweredInRange('html', 10, 50);
// Get all completed challenges
const completed = EfiweSDK.getCompleted('html');
// Returns:
// {
// 1: "<p>Hello</p>",
// 2: "<h1>Title</h1>", ...
// }
Using Your Own Custom Challenges
Want to use your own challenges instead of Efiwe's curated library? You can host your own challenge JSON file and point the SDK to it. Validation uses Efiwe's API endpoint and requires the 'solution' field in your JSON for comparison. If the JSON structure doesn't match (missing required fields like id, topic, difficulty, introduction, description, hints, solution), the SDK will fail to load challenges. Custom JSON must be publicly accessible via HTTPS with CORS enabled.
Challenge JSON Format (all fields required):
[
{
"id": 1,
"topic": "Your First Tag",
"difficulty": "easy", // Valid values: easy, intermediate, advanced
"introduction": "<p>Welcome to your first challenge!</p>", // Max 1000 chars recommended
"description": "<p>Write a paragraph tag with the text 'Hello World'.</p>", // Max 1000 chars
"hints": [
"Start with <p>",
"End with </p>"
], // Array of strings, max 5 hints
"solution": "<p>Hello World</p>", // Required for validation
"explanation": "<p>The <p> tag defines a paragraph in HTML.</p>" // Max 500 chars
},
{
"id": 2,
"topic": "Heading Tags",
"difficulty": "easy",
// ... more challenges
}
]
Loading Custom Challenges:
<div id="custom-challenges"></div>
<script src="https://efiwe.com/api/efiwe-sdk.js"></script>
<script>
// Parameters: (containerId, type, range, showNavigation, customJsonUrl)
EfiweSDK.renderChallengeList(
'custom-challenges',
'html', // Challenge type
'1-90', // Range: display challenges 1-90
true, // Show navigation (true/false)
'https://example.com/my-challenges.json' // URL to your JSON file
);
</script>
Without Navigation:
<script>
// Display challenges 1-50 without Previous/Next buttons
EfiweSDK.renderChallengeList(
'custom-challenges',
'html',
'1-50',
false // Hide navigation
);
</script>
Requirements for Custom Challenges:
- JSON file must be publicly accessible via HTTPS
- CORS must be enabled on your server
- All challenges must have unique sequential IDs
- The
solutionfield is required for validation to work - When using custom challenges, validation still uses Efiwe's API endpoint (applies to rate limits)
Customizing the Interface
The SDK applies default styles, but you can override them with your own.
If your custom styles are not taking effect, it is likely due to CSS specificity conflicts with the default Efiwe styles.
In such cases, use !important or more specific selectors to ensure your styles are applied.
/* Override Efiwe's default styles in your CSS */
.efiwe-container {
font-family: 'Your Custom Font', sans-serif;
max-width: 1200px;
background: #f9f9f9;
}
.efiwe-container button#submitCode {
background: #your-brand-color;
}
/* Customize the code editor appearance */
.CodeMirror {
font-size: 16px;
height: 400px !important;
}
Disabling Features
After SDK loads, you can hide specific buttons. Once applied, normal JavaScript toggling will not work unless !important is removed.
document
.getElementById('readAloud')
.style.setProperty('display', 'none', 'important');
document
.getElementById('showHints')
.style.setProperty('display', 'none', 'important');
Understanding Rate Limits
Our API allows 60 requests per minute per IP address by default. Here's how to work within these limits:
Best Practices:
// GOOD: Fetch all challenges once and cache them
const allChallenges = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges'
).then(r => r.json());
// Then use the cached data
localStorage.setItem('html_challenges', JSON.stringify(allChallenges));
// GOOD: Use range endpoints to fetch only what you need
const response = await fetch(
'https://efiwe.com/api/api.php/api/html/challenges/1-50'
);
// GOOD: The SDK handles caching automatically
EfiweSDK.renderChallengeList('container', 'html', '1-50');
Avoid:
// BAD: Fetching challenges one by one in a loop
for (let i = 1; i <= 191; i++) {
await fetch(`https://efiwe.com/api/api.php/api/html/challenge/${i}`);
// This will will hit rate limits!
}
// BAD: Making unnecessary repeated requests
setInterval(() => {
fetch('https://efiwe.com/api/api.php/api/html/challenges');
}, 1000); // Don't do this!
Need Higher Limits? If 60 requests/minute isn't enough for your use case, consider purchasing an API key.
Integration Examples for Different Use Cases
For Schools: Classroom Dashboard
<!-- Create a classroom view where students work through challenges -->
<div class="classroom-header">
<h1>Period 3: Introduction to Web Development</h1>
<p>Today's lesson: HTML Basics (Challenges 1-20)</p>
</div>
<div id="student-workspace"></div>
<script src="https://efiwe.com/api/efiwe-sdk.js"></script>
<script>
// Students start at first unanswered challenge in range
EfiweSDK.renderChallengeList('student-workspace', 'html', '1-20');
</script>
For NGOs: Mobile-First Community Program
<!-- Optimized for smartphones with limited connectivity -->
<div id="mobile-coding-app"></div>
<script src="https://efiwe.com/api/efiwe-sdk.js"></script>
<script>
// Find first incomplete challenge automatically
const startChallenge = EfiweSDK.findFirstUnanswered('html');
EfiweSDK.renderChallenge('mobile-coding-app', 'html', startChallenge);
</script>
For Bootcamps: Custom Learning Platform
// Build your own UI with direct API calls
class BootcampLearningPlatform {
async loadCurriculum() {
const htmlChallenges = await this.fetchChallenges('html');
const cssChallenges = await this.fetchChallenges('css');
const jsChallenges = await this.fetchChallenges('js');
return { html: htmlChallenges, css: cssChallenges, js: jsChallenges };
}
async fetchChallenges(type) {
const response = await fetch(
`https://efiwe.com/api/api.php/api/${type}/challenges`
);
return response.json();
}
async validateStudentWork(type, challengeId, code) {
const response = await fetch(
`https://efiwe.com/api/api.php/api/${type}/validate`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: challengeId, code })
}
);
const result = await response.json();
// Track student progress in your database
if (result.correct) {
await this.recordCompletion(studentId, type, challengeId);
}
return result;
}
}
Response Formats
Success Responses
All successful responses are in JSON format with HTTP 200 status.
// Challenge list or single challenge
[
{
"id": 1,
"topic": "Document Type Declaration",
"difficulty": "easy",
"introduction": "...",
"description": "...",
"hints": ["..."],
"explanation": "..."
},
// ...
]
// Efiwe 1.0 AI Validation
{
"correct": true,
"feedback": "Great job!",
"diagnostics": []
}
// Efiwe 2.0 AI Feedback/Hint
{
"feedback": "One short sentence." // or "hint"
}
// Efiwe 2.0 AI Diagnose
{
"diagnostics": [
{
"issue": "...",
"solution": "..."
}
]
}
Error Responses
Error responses use appropriate HTTP status codes with JSON body.
// 400 Bad Request (invalid type, missing fields)
{
"error": "Invalid challenge type"
}
// 404 Not Found
{
"error": "Challenge not found"
}
// 429 Rate Limit Exceeded
{
"error": "Rate limit exceeded. Try again later."
}
// 503 AI Unavailable
{
"error": "AI unavailable"
}
HTTP Status Codes
- 200 OK: Successful request
- 400 Bad Request: Invalid parameters or missing fields
- 404 Not Found: Challenge or endpoint not found
- 429 Too Many Requests: Rate limit exceeded
- 503 Service Unavailable: AI service temporarily down
Need Help?
Looking for assistance integrating our API into your platform? Email us at the address below, and a member of our Engineering team will get in touch. We’re excited to help you join us in making coding education accessible to everyone.


or