Importable n8n workflows for finding current, free photography open calls with online submission, extracting structured details with Gemini, and saving them to Airtable.
This repository contains:
setup-airtable.json- run once to create or validate the Airtable schema.daily-photo-open-calls.json- run manually once, then activate for daily 08:00 Asia/Ho_Chi_Minh discovery.
The automation is source-first to avoid burning search API quotas.
-
Airtable setup
setup-airtable.jsoncreates or validates two tables:Sources- known sites, aggregators, museums, galleries, festivals, and discovery metadata.Open Calls- individual open call records with deadline, summary, fee status, confidence, and review status.
-
Daily source recheck
- The daily workflow reads
ApprovedandCandidaterows fromSources. - It fetches those source pages directly over HTTP.
- It extracts likely open-call links from each page using anchor text and URL keywords such as
open call,call for entry,submission,deadline,photography,contest,award, andgrant. - This path does not spend search API credits.
- The daily workflow reads
-
Periodic discovery
- Discovery is controlled by
DISCOVERY_MODE. - Default
weeklymode runs search-provider discovery once a week and also runs discovery whenSourcesis empty, so the first run can seed the database. dailyruns discovery every day.manualdisables search-provider discovery and only checks existing Airtable sources.
- Discovery is controlled by
-
Search provider fallback
- Brave Search is attempted first when
BRAVE_SEARCH_API_KEYis present. - If Brave returns fewer than
MIN_RESULTS_BEFORE_FALLBACK, SerpAPI is tried whenSERPAPI_API_KEYis present. - If results are still below the threshold, Tavily Search is tried when
TAVILY_API_KEYis present. - Tavily Extract is intentionally not used; page content is fetched directly over HTTP to preserve Tavily quota.
- Brave Search is attempted first when
-
AI extraction
- Gemini classifies each candidate URL and returns structured JSON.
- The workflow asks for:
- whether it is a photography/photo/video/multimedia open call;
- whether required submission fee is absent;
- whether online/email/platform submission is available;
- deadline;
- short summary;
- confidence and rejection reason.
-
Airtable output
- Confirmed current records become
Active. - Unclear records, AI failures, rate limits, or exhausted run budgets become
Needs review. - Past-deadline records become
Expired. - Manual fields are preserved:
My Decision,Notes, andPriority.
- Confirmed current records become
-
Airtable API
- Stores
SourcesandOpen Calls. - Setup workflow uses Airtable Metadata API to create missing tables/fields.
- Daily workflow uses Airtable Records API for reads and upserts.
- Stores
-
Gemini API
- Performs structured extraction/classification.
- Uses Gemini
generateContentwith JSON response schema. - Controlled by
GEMINI_MODEL,AI_MAX_REQUESTS_PER_RUN, andAI_TIME_BUDGET_MS.
-
Brave Search API
- Primary search provider for periodic discovery if configured.
- Good for broad web discovery without using Tavily credits.
-
SerpAPI
- Optional fallback search provider.
- Useful when Brave is not connected or returns too few results.
-
Tavily Search
- Optional final fallback only.
- Tavily Extract is not used.
- Best kept as a backup because free monthly credits can disappear quickly during testing.
You can paste these directly into the config nodes after import:
- In
setup-airtable.json, open theAirtable Setup Confignode. - In
daily-photo-open-calls.json, open theOpen Calls Confignode.
Replace the PASTE_..._HERE placeholders with real values.
The workflows no longer read process.env, because n8n Code nodes may not expose process.
Alternatively, advanced users can move these values to n8n credentials or environment variables and adjust the config nodes.
Required values:
AIRTABLE_API_KEY- Airtable personal access token. Paste it into the config node field namedAIRTABLE_API_KEY.AIRTABLE_BASE_ID- target Airtable base id.GEMINI_API_KEY- Google AI Studio / Gemini API key for structured extraction.
Optional:
BRAVE_SEARCH_API_KEY- primary search provider for periodic discovery.SERPAPI_API_KEY- optional fallback search provider.TAVILY_API_KEY- optional final fallback search provider. Tavily Extract is not used.GEMINI_MODEL- defaultgemini-3.1-flash-lite; alternatives:gemini-2.5-flash-lite,gemini-2.5-flash.OPEN_CALL_CONFIDENCE_THRESHOLD- default0.75.OPEN_CALL_RESULTS_PER_QUERY- default8.DISCOVERY_MODE- defaultweekly; usedailyfor more discovery ormanualto disable search-provider discovery.DISCOVERY_QUERY_LIMIT- default3; recommended range1-3.MIN_RESULTS_BEFORE_FALLBACK- default3; use fallback provider only when the previous provider returns fewer results.SOURCE_RECHECK_LIMIT- default10; number of existing Airtable sources to check directly per run.DIRECT_LINK_LIMIT_PER_SOURCE- default8; max candidate links extracted from each source page.OPEN_CALL_MAX_CANDIDATES- default5; recommended range3-20.AI_MAX_REQUESTS_PER_RUN- default8; recommended range3-30.AI_TIME_BUDGET_MS- default240000, so the Code node stops before n8n's 300 second task timeout.
Daily runs first recheck existing Airtable Sources with direct HTTP, which does not spend search API credits. Search-provider discovery runs only when DISCOVERY_MODE allows it. With the default weekly mode, discovery also runs when the Sources table is empty so the first run can seed the registry.
Conservative weekly mode:
DISCOVERY_MODE = weekly
DISCOVERY_QUERY_LIMIT = 2
OPEN_CALL_RESULTS_PER_QUERY = 10
MIN_RESULTS_BEFORE_FALLBACK = 3
SOURCE_RECHECK_LIMIT = 20
DIRECT_LINK_LIMIT_PER_SOURCE = 10
OPEN_CALL_MAX_CANDIDATES = 10
AI_MAX_REQUESTS_PER_RUN = 10
One-off wider discovery run:
DISCOVERY_MODE = daily
DISCOVERY_QUERY_LIMIT = 4
OPEN_CALL_RESULTS_PER_QUERY = 10
OPEN_CALL_MAX_CANDIDATES = 20
AI_MAX_REQUESTS_PER_RUN = 20
After a one-off wider run, switch DISCOVERY_MODE back to weekly.
To avoid Tavily spend, leave TAVILY_API_KEY empty or keep MIN_RESULTS_BEFORE_FALLBACK low enough that SerpAPI results usually satisfy the fallback threshold.
- Import
setup-airtable.jsoninto n8n. - Run it once. It creates or validates the
SourcesandOpen Callstables. - Import
daily-photo-open-calls.json. - Run it manually once and inspect the execution summary.
- Activate the workflow.
- Do not commit real API keys.
- The workflow JSON files contain placeholders only, such as
PASTE_GEMINI_API_KEY_HERE. - If you export workflows from n8n after filling real keys into config nodes, do not commit those exports.
.gitignoreexcludes.env, local n8n data folders, credential dumps, execution dumps, logs, and common build artifacts.
Recommended validation before publishing:
node -e "for (const f of ['setup-airtable.json','daily-photo-open-calls.json']) JSON.parse(require('fs').readFileSync(f, 'utf8')); console.log('workflow json ok')"