Overview
The Adosa Real Estate website uses a PHP proxy to submit lead and contact forms to the eGO Real Estate API. This architecture solves CORS issues and provides a unified interface for form submissions.
Architecture
Browser (Form) → PHP Proxy → eGO API
(CORS Safe) (AuthorizationToken)
The flow:
- User submits form on the website
- JavaScript calls
/api/proxy.php with form data
- PHP proxy forwards request to eGO API with authentication
- PHP returns standardized JSON response
- JavaScript displays success/error message
LeadService Class
The LeadService class in src/services/api/leads.ts handles all lead and contact submissions.
Property Lead Submission
Used when a visitor inquires about a specific property:
LeadService.submitPropertyLead({
name: "John Doe",
email: "[email protected]",
phone: "+34 600 123 456",
property_id: "ADO1234",
message: "I'm interested in this property"
});
Full name of the person submitting the lead
Email address for contact
Phone number with international format recommended
Property reference ID from the eGO system (e.g., “ADO1234”)
Optional message from the visitor
Implementation
The method constructs URL parameters and sends to the proxy:
static async submitPropertyLead(lead: any) {
const params = new URLSearchParams({
NAM: lead.name,
EML: lead.email,
PHO: lead.phone,
OBS: `REFERENCIA: ${lead.property_id}\n\n${lead.message || ''}`,
RID: lead.property_id,
CTY: "4" // 4 = wants to ask for more info (Lead)
});
const fetchUrl = `/api/proxy.php?type=Lead&${params.toString()}`;
const response = await fetch(fetchUrl);
const data = await response.json();
return {
success: data.success,
message: "Request sent successfully"
};
}
eGO API Parameters
Name parameter for eGO API
Email parameter for eGO API
Phone parameter for eGO API
Observations/message text. Includes property reference and user message
Reference ID - the property ID being inquired about
Contact type: "4" = wants to ask for more info (Lead)
Used for general contact form (not tied to a specific property):
LeadService.submitGeneralContact({
name: "Jane Smith",
email: "[email protected]",
phone: "+34 600 987 654",
message: "I'd like to schedule a consultation"
});
Implementation
static async submitGeneralContact(contact: any) {
const params = new URLSearchParams({
NAM: contact.name,
EML: contact.email,
PHO: contact.phone,
OBS: contact.message || '',
CTY: "1", // 1 = looking to buy a property (Contact)
});
const fetchUrl = `/api/proxy.php?type=Contact&${params.toString()}`;
const response = await fetch(fetchUrl);
const data = await response.json();
return {
success: data.success,
message: "Contact sent successfully"
};
}
Key difference: Contact endpoint uses CTY: "1" and does not require RID parameter.
PHP Proxy
The PHP proxy at public/api/proxy.php handles server-side API communication.
Configuration
$api_token = "u2fW9rOg0Oz5rPGVh+7wowfgDt4IiCugRCFDrohuR3vJzZIwRzFzgfdM3YDqDuN5";
$base_url = "https://websiteapi.egorealestate.com/v1";
The API token is hardcoded in the PHP file. In production, this should be moved to environment variables or a secure configuration file.
The proxy sets permissive CORS headers:
header("Content-Type: application/json");
header("Access-Control-Allow-Origin: *");
This allows the frontend to make requests from any domain during development and production.
Request Flow
- Extract Parameters:
$type = isset($_GET['type']) ? $_GET['type'] : 'Properties';
$params = $_GET;
unset($params['type']); // Remove internal proxy parameter
- Build Target URL:
$endpoint = $type; // "Lead" or "Contact"
$query = http_build_query($params);
$url = $base_url . "/" . $endpoint . "?" . $query;
- Configure cURL:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // CDMON compatibility
$headers = [
"AuthorizationToken: $api_token",
"Accept: application/json",
"User-Agent: AdosaRealEstate/1.0"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
- Execute and Return:
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// IIS Bypass: Always return 200 to client
http_response_code(200);
echo json_encode([
"success" => ($http_code >= 200 && $http_code < 300),
"ego_code" => $http_code,
"ego_response" => json_decode($response) ?: $response,
"curl_error" => $curl_err,
]);
IIS Bypass Strategy
The proxy always returns HTTP 200 to the client, even if the eGO API returns an error:
// IIS Bypass: Always return 200 so JS can read error body
http_response_code(200);
This solves an issue where IIS servers block error responses. The JavaScript checks the success field in the JSON response instead of the HTTP status code.
Response Structure
true if eGO API returned 2xx status code, false otherwise
The actual HTTP status code from the eGO API
Parsed JSON response from eGO API, or raw text if not JSON
cURL error message if request failed at network level
Full URL that was requested (for debugging)
HTTP method used (always “GET” for eGO API)
Error Handling
Both submitPropertyLead() and submitGeneralContact() include try-catch error handling:
try {
const response = await fetch(fetchUrl);
const data = await response.json();
if (!data.success) {
console.error("❌ eGO Error:", data.ego_code, data.ego_response);
throw new Error(`eGO Error: ${data.ego_code}`);
}
return { success: true, message: "Request sent successfully" };
} catch (error: any) {
console.error("❌ Critical failure:", error);
return { success: false, message: "Error sending request" };
}
Important: Methods return { success: false } instead of throwing errors, allowing the UI to display user-friendly error messages.
The CTY parameter defines the type of contact:
| Code | Type | Description |
|---|
"1" | Contact | General inquiry - looking to buy a property |
"4" | Lead | Specific property inquiry - wants more info |
These codes are defined by the eGO Real Estate API specification.
Frontend Integration
Example of using LeadService in an Astro component:
---
import { LeadService } from '../services/api/leads';
---
<form id="property-form">
<input name="name" required />
<input name="email" type="email" required />
<input name="phone" required />
<textarea name="message"></textarea>
<input type="hidden" name="property_id" value={propertyId} />
<button type="submit">Send</button>
</form>
<script>
const form = document.getElementById('property-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const result = await LeadService.submitPropertyLead({
name: formData.get('name'),
email: formData.get('email'),
phone: formData.get('phone'),
property_id: formData.get('property_id'),
message: formData.get('message')
});
if (result.success) {
alert('Thank you! We will contact you soon.');
form.reset();
} else {
alert('Error sending form. Please try again.');
}
});
</script>
Security Considerations
- API Token Exposure: The PHP proxy keeps the API token server-side, preventing exposure in client-side code
- CORS Protection: While the proxy allows all origins (
*), this is acceptable for public lead forms
- Rate Limiting: The eGO API may rate limit requests. Consider implementing client-side throttling for forms
- Input Validation: Always validate and sanitize user input before submission
- SSL/TLS: All requests use HTTPS to encrypt data in transit
Testing
Test lead submission with curl:
curl "https://yourdomain.com/api/proxy.php?type=Lead&NAM=Test&[email protected]&PHO=123456789&RID=ADO1234&CTY=4&OBS=Test%20message"
Expected response:
{
"success": true,
"ego_code": 200,
"ego_response": { ... },
"curl_error": ""
}