The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "EDIFICIA - Template Storage (Retrieve)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "template-retrieve",
"responseMode": "responseNode",
"options": {}
},
"id": "tr-wh-0001-0000-0000-000000000001",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
340
]
},
{
"parameters": {
"jsCode": "// Valida X-Edificia-Auth contra la variable de entorno EDIFICIA_API_SECRET.\n// Extrae y expone el body para los nodos siguientes.\nconst items = $input.all();\nconst headers = items[0].json.headers;\nconst expectedSecret = $env.EDIFICIA_API_SECRET;\nconst receivedSecret = headers['x-edificia-auth'];\n\nif (!expectedSecret) {\n throw new Error('EDIFICIA_API_SECRET environment variable is not configured in n8n.');\n}\n\nif (!receivedSecret || receivedSecret !== expectedSecret) {\n return [{ json: { isValid: false } }];\n}\n\nconst body = items[0].json.body;\nreturn [{ json: { isValid: true, ...body } }];"
},
"id": "tr-auth-0001-0000-0000-000000000002",
"name": "Validate Auth",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
340
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "cond-auth-valid",
"leftValue": "={{ Boolean($json.isValid) }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "tr-if-000001-0000-0000-000000000003",
"name": "Auth Valid?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
680,
340
]
},
{
"parameters": {
"respondWith": "text",
"responseBody": "={{ JSON.stringify({ apiVersion: '1.0', operation: $json.operation ?? 'UNKNOWN', operationId: $json.operationId ?? '', success: false, code: 'AUTH_INVALID', message: 'Invalid or missing X-Edificia-Auth header', timestampUtc: new Date().toISOString() }) }}",
"options": {
"responseCode": 401,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
}
},
"id": "tr-401-0001-0000-0000-000000000004",
"name": "Respond 401",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
900,
500
]
},
{
"parameters": {
"jsCode": "// Valida que la operaci\u00f3n sea GET_TEMPLATE y que storageKey est\u00e9 presente.\nconst item = $input.first();\nconst operation = item.json.operation;\nconst storageKey = item.json.payload?.storageKey;\n\nif (operation !== 'GET_TEMPLATE') {\n return [{ json: { ...item.json, isValid: false, validationError: 'UNSUPPORTED_OPERATION', validationMessage: 'Este webhook solo acepta GET_TEMPLATE. Use /webhook/template-store para UPLOAD y DELETE.' } }];\n}\n\nif (!storageKey || typeof storageKey !== 'string' || storageKey.trim() === '') {\n return [{ json: { ...item.json, isValid: false, validationError: 'REQUEST_INVALID', validationMessage: 'payload.storageKey es obligatorio para GET_TEMPLATE.' } }];\n}\n\nreturn [{ json: { ...item.json, isValid: true } }];"
},
"id": "tr-val-0001-0000-0000-000000000005",
"name": "Validate GET Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
180
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "cond-req-valid",
"leftValue": "={{ Boolean($json.isValid) }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "tr-if2-00001-0000-0000-000000000006",
"name": "Request Valid?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1120,
180
]
},
{
"parameters": {
"respondWith": "text",
"responseBody": "={{ JSON.stringify({ apiVersion: '1.0', operation: $json.operation ?? 'GET_TEMPLATE', operationId: $json.operationId ?? '', success: false, code: $json.validationError ?? 'REQUEST_INVALID', message: $json.validationMessage ?? 'Petici\u00f3n inv\u00e1lida', timestampUtc: new Date().toISOString() }) }}",
"options": {
"responseCode": 400,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
}
},
"id": "tr-400-0001-0000-0000-000000000007",
"name": "Respond 400",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1340,
340
]
},
{
"parameters": {
"operation": "download",
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.payload.storageKey }}"
},
"options": {}
},
"id": "tr-gdd-0001-0000-0000-000000000008",
"name": "Download from Google Drive",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1340,
80
],
"continueOnFail": true,
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Comprueba si la descarga fue exitosa y construye la respuesta.\n// Si continueOnFail captur\u00f3 un error de Drive, responde TEMPLATE_NOT_FOUND.\nconst input = $input.first();\nconst original = $('Validate GET Request').first().json;\nconst hasError = !!input.json.error || !input.binary?.data;\n\nif (hasError) {\n return [{\n json: {\n apiVersion: '1.0',\n operation: 'GET_TEMPLATE',\n operationId: original.operationId,\n success: false,\n code: 'TEMPLATE_NOT_FOUND',\n message: 'La plantilla no existe en el almacenamiento',\n provider: 'google-drive',\n timestampUtc: new Date().toISOString(),\n data: null\n },\n _httpStatus: 404\n }];\n}\n\n// Encode binary to base64\nconst binaryData = input.binary.data;\nconst buffer = await this.helpers.getBinaryDataBuffer(input, 'data');\nconst contentBase64 = buffer.toString('base64');\n\nreturn [{\n json: {\n apiVersion: '1.0',\n operation: 'GET_TEMPLATE',\n operationId: original.operationId,\n success: true,\n code: 'TEMPLATE_STORAGE_OK',\n message: 'Plantilla recuperada correctamente',\n provider: 'google-drive',\n timestampUtc: new Date().toISOString(),\n data: {\n storageKey: original.payload.storageKey,\n mimeType: binaryData.mimeType ?? 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',\n fileSizeBytes: binaryData.fileSize ?? null,\n contentBase64\n }\n },\n _httpStatus: 200\n}];"
},
"id": "tr-resp-0001-0000-0000-000000000009",
"name": "Build GET Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1560,
80
]
},
{
"parameters": {
"respondWith": "firstIncomingItem",
"options": {
"responseCode": "={{ $json._httpStatus ?? 200 }}",
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
}
},
"id": "tr-200-0001-0000-0000-000000000010",
"name": "Respond GET",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1780,
80
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Validate Auth",
"type": "main",
"index": 0
}
]
]
},
"Validate Auth": {
"main": [
[
{
"node": "Auth Valid?",
"type": "main",
"index": 0
}
]
]
},
"Auth Valid?": {
"main": [
[
{
"node": "Validate GET Request",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 401",
"type": "main",
"index": 0
}
]
]
},
"Validate GET Request": {
"main": [
[
{
"node": "Request Valid?",
"type": "main",
"index": 0
}
]
]
},
"Request Valid?": {
"main": [
[
{
"node": "Download from Google Drive",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 400",
"type": "main",
"index": 0
}
]
]
},
"Download from Google Drive": {
"main": [
[
{
"node": "Build GET Response",
"type": "main",
"index": 0
}
]
]
},
"Build GET Response": {
"main": [
[
{
"node": "Respond GET",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "edificia-template-retrieve-v1",
"meta": {
"templateCredsSetupCompleted": false
},
"tags": [
{
"name": "edificia"
},
{
"name": "templates"
},
{
"name": "google-drive"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleDriveOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
EDIFICIA - Template Storage (Retrieve). Uses googleDrive. Webhook trigger; 10 nodes.
Source: https://github.com/jesusjbriceno/edificia/blob/6e21d29fa62e52c9f471e2e57dc85636d7e53d98/apps/n8n/workflow-template-retrieve.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow is perfect for app developers, SaaS founders, and mobile growth teams who need constant UGC-style video ads without hiring creators or agencies. If you're spending $500+ per creator and
AI Background Generation with Nano Banana (Gemini Image). Uses httpRequest, googleDrive. Webhook trigger; 35 nodes.
This template is for developers, teams, and automation enthusiasts who want a private, PIN-protected Telegram chatbot that answers questions from their own documents — without relying on external AI A
Storage Sync - Google Drive. Uses supabase, googleDrive, httpRequest. Webhook trigger; 22 nodes.
This workflow automates the creation of user-generated-content-style product videos by combining Gemini's image generation with OpenAI's SORA 2 video generation. It accepts webhook requests with produ