package main import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "strings" "time" ) // EUFundingAPI represents the EU Funding & Tenders Portal API client type EUFundingAPI struct { BaseURL string SearchAPIKey string FAQAPIKey string PersonAPIKey string Client *http.Client } // NewEUFundingAPI creates a new API client instance func NewEUFundingAPI() *EUFundingAPI { return &EUFundingAPI{ BaseURL: "https://api.tech.ec.europa.eu/search-api/prod/rest", SearchAPIKey: "SEDIA", FAQAPIKey: "SEDIA_FAQ", PersonAPIKey: "SEDIA_PERSON", Client: &http.Client{ Timeout: 30 * time.Second, }, } } // SearchQuery represents the Elasticsearch query structure type SearchQuery struct { Bool struct { Must []interface{} `json:"must"` } `json:"bool"` } // APIResponse represents the standard API response type APIResponse struct { Results []map[string]interface{} `json:"results"` Total int `json:"total"` } // makeRequest performs HTTP requests to the API func (api *EUFundingAPI) makeRequest(endpoint string, method string, data interface{}) (*APIResponse, error) { var body io.Reader if data != nil && method == "POST" { jsonData, err := json.Marshal(data) if err != nil { return nil, fmt.Errorf("failed to marshal request data: %v", err) } body = bytes.NewBuffer(jsonData) } req, err := http.NewRequest(method, endpoint, body) if err != nil { return nil, fmt.Errorf("failed to create request: %v", err) } req.Header.Set("User-Agent", "EU-Funding-API-Client-Go/1.0") req.Header.Set("Accept", "application/json") if body != nil { req.Header.Set("Content-Type", "application/json") } resp, err := api.Client.Do(req) if err != nil { return nil, fmt.Errorf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("API returned status %d", resp.StatusCode) } var response APIResponse if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, fmt.Errorf("failed to decode response: %v", err) } return &response, nil } // SearchGrantsTenders searches for grants and tenders func (api *EUFundingAPI) SearchGrantsTenders(query *SearchQuery) (*APIResponse, error) { endpoint := fmt.Sprintf("%s/search?apiKey=%s&text=***", api.BaseURL, api.SearchAPIKey) if query == nil { // Default query to get all grants and tenders query = &SearchQuery{} query.Bool.Must = []interface{}{ map[string]interface{}{ "terms": map[string][]string{ "type": {"0", "1", "2", "8"}, // All types }, }, map[string]interface{}{ "terms": map[string][]string{ "status": {"31094501", "31094502", "31094503"}, // All statuses }, }, } } return api.makeRequest(endpoint, "POST", query) } // GetTopicDetails gets detailed information about a specific topic func (api *EUFundingAPI) GetTopicDetails(topicIdentifier string) (*APIResponse, error) { endpoint := fmt.Sprintf("%s/search?apiKey=%s&text=\"%s\"", api.BaseURL, api.SearchAPIKey, topicIdentifier) return api.makeRequest(endpoint, "GET", nil) } // SearchGrantUpdates searches for grant updates func (api *EUFundingAPI) SearchGrantUpdates(frameworkProgramme string) (*APIResponse, error) { query := &SearchQuery{} query.Bool.Must = []interface{}{ map[string]interface{}{ "terms": map[string][]string{ "type": {"6"}, // Grant updates }, }, } if frameworkProgramme != "" { query.Bool.Must = append(query.Bool.Must, map[string]interface{}{ "terms": map[string][]string{ "frameworkProgramme": {frameworkProgramme}, }, }) } endpoint := fmt.Sprintf("%s/search?apiKey=%s&text=***", api.BaseURL, api.SearchAPIKey) return api.makeRequest(endpoint, "POST", query) } // SearchFAQs searches FAQs func (api *EUFundingAPI) SearchFAQs(programme string) (*APIResponse, error) { query := &SearchQuery{} query.Bool.Must = []interface{}{ map[string]interface{}{ "terms": map[string][]string{ "type": {"0", "1"}, // FAQ types }, }, map[string]interface{}{ "terms": map[string][]string{ "status": {"0", "1"}, // All statuses }, }, } if programme != "" { query.Bool.Must = append(query.Bool.Must, map[string]interface{}{ "term": map[string]string{ "programme": programme, }, }) } endpoint := fmt.Sprintf("%s/search?apiKey=%s&text=***", api.BaseURL, api.FAQAPIKey) return api.makeRequest(endpoint, "POST", query) } // GetOrganizationData gets organization public data func (api *EUFundingAPI) GetOrganizationData(picCode string) (*APIResponse, error) { endpoint := fmt.Sprintf("%s/document/%s?apiKey=%s", api.BaseURL, picCode, api.PersonAPIKey) return api.makeRequest(endpoint, "GET", nil) } // SearchPartners searches for partners in a specific topic func (api *EUFundingAPI) SearchPartners(topic string) (*APIResponse, error) { query := &SearchQuery{} query.Bool.Must = []interface{}{ map[string]interface{}{ "terms": map[string][]string{ "topics": {topic}, }, }, map[string]interface{}{ "terms": map[string][]string{ "type": {"ORGANISATION", "PERSON"}, }, }, } endpoint := fmt.Sprintf("%s/search?apiKey=%s&text=***", api.BaseURL, api.SearchAPIKey) return api.makeRequest(endpoint, "POST", query) } // SearchProjects searches for EU funded projects func (api *EUFundingAPI) SearchProjects(programmeID, missionGroup string) (*APIResponse, error) { query := &SearchQuery{} if programmeID != "" { query.Bool.Must = append(query.Bool.Must, map[string]interface{}{ "terms": map[string][]string{ "programId": {programmeID}, }, }) } if missionGroup != "" { query.Bool.Must = append(query.Bool.Must, map[string]interface{}{ "terms": map[string][]string{ "missionGroup": {missionGroup}, }, }) } endpoint := fmt.Sprintf("%s/search?apiKey=%s&text=***", api.BaseURL, api.SearchAPIKey) return api.makeRequest(endpoint, "POST", query) } func main() { fmt.Println("EU Funding & Tenders Portal API Client (Go)") fmt.Println("=" + strings.Repeat("=", 50)) api := NewEUFundingAPI() // Example 1: Search for EIC Accelerator opportunities fmt.Println("\n1. Searching for EIC Accelerator opportunities...") eicQuery := &SearchQuery{} eicQuery.Bool.Must = []interface{}{ map[string]interface{}{ "terms": map[string][]string{ "type": {"1", "2", "8"}, // Grants }, }, map[string]interface{}{ "terms": map[string][]string{ "status": {"31094501", "31094502", "31094503"}, // All statuses }, }, map[string]interface{}{ "term": map[string]string{ "callIdentifier": "HORIZON-EIC-2026-ACCELERATOR-01", }, }, } results, err := api.SearchGrantsTenders(eicQuery) if err != nil { log.Printf("Error searching grants: %v", err) } else { fmt.Printf("Found %d EIC Accelerator opportunities\n", len(results.Results)) for i, result := range results.Results { if i >= 3 { // Show first 3 break } if title, ok := result["title"].(string); ok { fmt.Printf("- %s\n", title) } } } // Example 2: Get topic details for EIC Accelerator fmt.Println("\n2. Getting EIC Accelerator topic details...") topicDetails, err := api.GetTopicDetails("HORIZON-EIC-2026-ACCELERATOR-01") if err != nil { log.Printf("Error getting topic details: %v", err) } else { fmt.Println("Topic details retrieved successfully") if len(topicDetails.Results) > 0 { topic := topicDetails.Results[0] if title, ok := topic["title"].(string); ok { fmt.Printf("Title: %s\n", title) } if status, ok := topic["status"].(string); ok { fmt.Printf("Status: %s\n", status) } if deadline, ok := topic["deadline"].(string); ok { fmt.Printf("Deadline: %s\n", deadline) } } } // Example 3: Search for grant updates fmt.Println("\n3. Searching for recent grant updates...") updates, err := api.SearchGrantUpdates("43108390") // Horizon Europe if err != nil { log.Printf("Error searching updates: %v", err) } else { fmt.Printf("Found %d grant updates\n", len(updates.Results)) } // Example 4: Search FAQs fmt.Println("\n4. Searching for FAQs...") faqs, err := api.SearchFAQs("") if err != nil { log.Printf("Error searching FAQs: %v", err) } else { fmt.Printf("Found %d FAQs\n", len(faqs.Results)) } fmt.Println("\nGo API client demonstration completed!") } // EICAcceleratorMonitor monitors EIC Accelerator opportunities func EICAcceleratorMonitor() { fmt.Println("EIC Accelerator Monitor") fmt.Println("=" + strings.Repeat("=", 30)) api := NewEUFundingAPI() // Query for EIC Accelerator opportunities query := &SearchQuery{} query.Bool.Must = []interface{}{ map[string]interface{}{ "terms": map[string][]string{ "type": {"1", "2", "8"}, }, }, map[string]interface{}{ "terms": map[string][]string{ "status": {"31094501", "31094502"}, // Open and forthcoming }, }, map[string]interface{}{ "term": map[string]string{ "frameworkProgramme": "43108390", // Horizon Europe }, }, map[string]interface{}{ "query_string": map[string]interface{}{ "query": "EIC Accelerator", "default_field": "title", }, }, } results, err := api.SearchGrantsTenders(query) if err != nil { log.Printf("Error monitoring EIC Accelerator: %v", err) return } if results != nil && len(results.Results) > 0 { fmt.Printf("Found %d EIC Accelerator opportunities:\n", len(results.Results)) for _, opp := range results.Results { title := getStringValue(opp, "title") identifier := getStringValue(opp, "identifier") status := getStringValue(opp, "status") deadline := getStringValue(opp, "deadline") fmt.Printf("\nšŸ“‹ %s\n", title) fmt.Printf(" ID: %s\n", identifier) fmt.Printf(" Status: %s\n", status) fmt.Printf(" Deadline: %s\n", deadline) } } else { fmt.Println("No EIC Accelerator opportunities found") } } // Helper function to safely get string values from map func getStringValue(data map[string]interface{}, key string) string { if value, ok := data[key].(string); ok { return value } return "N/A" } /Users/damirmukimov/city_resource_graph/eu_funding_api.go