{ "kind": "open-flow-workflow", "version": 1, "name": "Save Company Brand Assets to Airtable", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_084b5bb34d52d400": { "name": "Look up a company", "kind": "start", "inputDefs": [] }, "n_12f1abf7b431efcc": { "inputs": { "identifier": { "kind": "value", "value": "n8n.io" }, "lookupType": { "kind": "value", "value": "domain" } }, "name": "Get the company brand", "kind": "task", "task": { "inputs": [ { "description": "The identifier value matching `lookupType`, such as a domain, stock ticker, ISIN, crypto symbol, or Brand ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The identifier value matching `lookupType`, such as a domain, stock ticker, ISIN, crypto symbol, or Brand ID." }, "nullable": false, "handle": "identifier" }, { "description": "The identifier type to use. Use `domain` for website domains to avoid naming collisions.", "jsonSchema": { "type": "string", "enum": [ "domain", "ticker", "isin", "crypto", "brand_id" ], "description": "The identifier type to use. Use `domain` for website domains to avoid naming collisions." }, "nullable": false, "handle": "lookupType" }, { "description": "Whether Brandfetch may return brands flagged as NSFW.", "jsonSchema": { "type": "boolean", "description": "Whether Brandfetch may return brands flagged as NSFW." }, "nullable": true, "handle": "allowNsfw", "value": null } ], "outputs": [ { "description": "The Brandfetch brand identifier.", "jsonSchema": { "type": "string", "description": "The Brandfetch brand identifier." }, "nullable": true, "handle": "id" }, { "description": "The Brandfetch URN for the brand profile.", "jsonSchema": { "type": "string", "description": "The Brandfetch URN for the brand profile." }, "nullable": true, "handle": "urn" }, { "description": "The canonical brand name.", "jsonSchema": { "type": [ "string", "null" ], "description": "The canonical brand name." }, "nullable": true, "handle": "name" }, { "description": "The primary brand domain.", "jsonSchema": { "type": "string", "description": "The primary brand domain." }, "nullable": true, "handle": "domain" }, { "description": "Whether the brand profile is claimed on Brandfetch.", "jsonSchema": { "type": "boolean", "description": "Whether the brand profile is claimed on Brandfetch." }, "nullable": true, "handle": "claimed" }, { "description": "The short brand description.", "jsonSchema": { "type": [ "string", "null" ], "description": "The short brand description." }, "nullable": true, "handle": "description" }, { "description": "The long-form brand description.", "jsonSchema": { "type": [ "string", "null" ], "description": "The long-form brand description." }, "nullable": true, "handle": "longDescription" }, { "description": "The Brandfetch quality score for the brand.", "jsonSchema": { "type": "number", "description": "The Brandfetch quality score for the brand." }, "nullable": true, "handle": "qualityScore" }, { "description": "Whether the brand profile is flagged as NSFW.", "jsonSchema": { "type": "boolean", "description": "Whether the brand profile is flagged as NSFW." }, "nullable": true, "handle": "isNsfw" }, { "description": "The logos returned by Brandfetch.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "description": "The logo type, such as `icon` or `logo`." }, "theme": { "type": "string", "description": "The logo theme, such as `dark` or `light`." }, "formats": { "type": "array", "items": { "type": "object", "properties": { "src": { "type": "string", "description": "The source URL for the asset format." }, "format": { "type": "string", "description": "The asset file format, such as `svg` or `png`." }, "width": { "type": "number", "description": "The asset width in pixels." }, "height": { "type": "number", "description": "The asset height in pixels." }, "size": { "type": "number", "description": "The asset size in bytes." }, "background": { "type": "string", "description": "The background hint returned for the asset." } }, "required": [ "src", "format" ], "additionalProperties": false, "description": "One asset format returned by Brandfetch." }, "description": "The available logo formats." } }, "required": [ "type", "formats" ], "additionalProperties": false, "description": "One logo variant returned by Brandfetch." }, "description": "The logos returned by Brandfetch." }, "nullable": true, "handle": "logos" }, { "description": "The brand colors.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "hex": { "type": "string", "description": "The HEX color value." }, "type": { "type": "string", "description": "The color role returned by Brandfetch." }, "brightness": { "type": "number", "description": "The brightness score returned by Brandfetch." } }, "required": [ "hex", "type" ], "additionalProperties": false, "description": "One brand color returned by Brandfetch." }, "description": "The brand colors." }, "nullable": true, "handle": "colors" }, { "description": "The brand fonts.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The font name." }, "type": { "type": "string", "description": "The font usage type, such as `title` or `body`." }, "origin": { "type": "string", "description": "The font origin system." }, "originId": { "type": "string", "description": "The font origin identifier." } }, "required": [ "type" ], "additionalProperties": false, "description": "One font descriptor returned by Brandfetch." }, "description": "The brand fonts." }, "nullable": true, "handle": "fonts" }, { "description": "The brand images.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "description": "The image type returned by Brandfetch." }, "formats": { "type": "array", "items": { "type": "object", "properties": { "src": { "type": "string", "description": "The source URL for the asset format." }, "format": { "type": "string", "description": "The asset file format, such as `svg` or `png`." }, "width": { "type": "number", "description": "The asset width in pixels." }, "height": { "type": "number", "description": "The asset height in pixels." }, "size": { "type": "number", "description": "The asset size in bytes." }, "background": { "type": "string", "description": "The background hint returned for the asset." } }, "required": [ "src", "format" ], "additionalProperties": false, "description": "One asset format returned by Brandfetch." }, "description": "The available image formats." } }, "required": [ "type", "formats" ], "additionalProperties": false, "description": "One brand image variant returned by Brandfetch." }, "description": "The brand images." }, "nullable": true, "handle": "images" }, { "description": "The external links for the brand.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The social or link target name." }, "url": { "type": "string", "description": "The linked URL." } }, "required": [ "name", "url" ], "additionalProperties": false, "description": "One external link returned by Brandfetch." }, "description": "The external links for the brand." }, "nullable": true, "handle": "links" }, { "description": "The company metadata block returned by Brandfetch.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "Any company metadata value returned by Brandfetch." }, "description": "The company metadata block returned by Brandfetch." }, "nullable": true, "handle": "company" } ], "name": "Get the company brand", "executor": { "kind": "connector", "action": "brandfetch.get_brand" } } }, "n_3b7d106c54a75302": { "inputs": { "name": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_12f1abf7b431efcc", "output": "name" } ] }, "logos": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_12f1abf7b431efcc", "output": "logos" } ] } }, "name": "Select the icon and logo URLs", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": [ "string", "null" ], "description": "The canonical brand name." }, "nullable": true, "handle": "name" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "description": "The logo type, such as `icon` or `logo`." }, "theme": { "type": "string", "description": "The logo theme, such as `dark` or `light`." }, "formats": { "type": "array", "items": { "type": "object", "properties": { "src": { "type": "string", "description": "The source URL for the asset format." }, "format": { "type": "string", "description": "The asset file format, such as `svg` or `png`." }, "width": { "type": "number", "description": "The asset width in pixels." }, "height": { "type": "number", "description": "The asset height in pixels." }, "size": { "type": "number", "description": "The asset size in bytes." }, "background": { "type": "string", "description": "The background hint returned for the asset." } }, "required": [ "src", "format" ], "additionalProperties": false, "description": "One asset format returned by Brandfetch." }, "description": "The available logo formats." } }, "required": [ "type", "formats" ], "additionalProperties": false, "description": "One logo variant returned by Brandfetch." }, "description": "The logos returned by Brandfetch." }, "nullable": true, "handle": "logos" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "fields": { "type": "object", "additionalProperties": { "description": "A record value." }, "description": "Field values for the new Airtable record." } }, "required": [ "fields" ], "additionalProperties": false, "description": "Record payload used when creating Airtable records." }, "minItems": 1, "maxItems": 10, "description": "Records to create in the Airtable table." }, "nullable": false, "handle": "records" } ], "name": "Select the icon and logo URLs", "moduleId": "n_8aff457b4b70b006", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_f042babe7a993ba9": { "inputs": { "baseId": { "kind": "value", "value": "YOUR_AIRTABLE_BASE_ID" }, "tableIdOrName": { "kind": "value", "value": "YOUR_AIRTABLE_TABLE_ID" }, "records": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3b7d106c54a75302", "output": "records" } ] }, "typecast": { "kind": "value", "value": false }, "returnFieldsByFieldId": { "kind": "value", "value": false } }, "name": "Save one Airtable record", "kind": "task", "task": { "inputs": [ { "description": "Base ID in the format appXXXXXXXXXXXXXX.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Base ID in the format appXXXXXXXXXXXXXX." }, "nullable": false, "handle": "baseId" }, { "description": "Table ID or table name accepted by the Airtable path parameter.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Table ID or table name accepted by the Airtable path parameter." }, "nullable": false, "handle": "tableIdOrName" }, { "description": "Records to create in the Airtable table.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "fields": { "type": "object", "additionalProperties": { "description": "A record value." }, "description": "Field values for the new Airtable record." } }, "required": [ "fields" ], "additionalProperties": false, "description": "Record payload used when creating Airtable records." }, "minItems": 1, "maxItems": 10, "description": "Records to create in the Airtable table." }, "nullable": false, "handle": "records" }, { "description": "Whether Airtable should coerce incoming values to compatible field types.", "jsonSchema": { "type": "boolean", "description": "Whether Airtable should coerce incoming values to compatible field types." }, "nullable": true, "handle": "typecast", "value": null }, { "description": "Whether Airtable should return field IDs instead of field names in record objects.", "jsonSchema": { "type": "boolean", "description": "Whether Airtable should return field IDs instead of field names in record objects." }, "nullable": true, "handle": "returnFieldsByFieldId", "value": null } ], "outputs": [ { "description": "Records created by Airtable.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Record ID." }, "createdTime": { "type": "string", "description": "Record creation timestamp returned by Airtable." }, "fields": { "type": "object", "additionalProperties": { "description": "A record value." }, "description": "Record fields keyed by field name or field ID." }, "commentCount": { "type": "integer", "description": "Comment count returned by Airtable when enabled on the endpoint." } }, "required": [ "id", "fields" ], "additionalProperties": true, "description": "Airtable record." }, "description": "Records created by Airtable." }, "nullable": false, "handle": "records" } ], "name": "Save one Airtable record", "executor": { "kind": "connector", "action": "airtable.create_records" } } }, "n_9fd1b64e4acd48df": { "name": "Saved record", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Record ID." }, "createdTime": { "type": "string", "description": "Record creation timestamp returned by Airtable." }, "fields": { "type": "object", "additionalProperties": { "description": "A record value." }, "description": "Record fields keyed by field name or field ID." }, "commentCount": { "type": "integer", "description": "Comment count returned by Airtable when enabled on the endpoint." } }, "required": [ "id", "fields" ], "additionalProperties": true, "description": "Airtable record." }, "description": "Records created by Airtable." }, "nullable": false, "handle": "records" } ], "outputMappings": { "records": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f042babe7a993ba9", "output": "records" } ] } } } }, "edges": [ { "source": "n_084b5bb34d52d400", "target": "n_12f1abf7b431efcc" }, { "source": "n_12f1abf7b431efcc", "target": "n_3b7d106c54a75302" }, { "source": "n_3b7d106c54a75302", "target": "n_f042babe7a993ba9" }, { "source": "n_f042babe7a993ba9", "target": "n_9fd1b64e4acd48df" } ] } }, "modules": { "n_8aff457b4b70b006": { "name": "Select the icon and logo URLs", "imports": [], "source": "export default function brandAirtable({name, logos}) {\n if (typeof name !== 'string' || !name.trim() || !Array.isArray(logos)) throw new Error('Brand name and logo assets are required');\n function validUrl(value) {\n if (typeof value !== 'string' || /[\\s\\x00-\\x1f\\x7f\\\\]/.test(value) || /%(?![0-9a-f]{2})/i.test(value)) return false;\n const match = /^https?:\\/\\/([^/?#]+)(?:[/?#].*)?$/i.exec(value);\n if (!match || match[1].includes('@')) return false;\n const authority = match[1];\n let host, port;\n if (authority.startsWith('[')) {\n const parts = /^\\[([0-9a-f:]+)\\](?::(\\d+))?$/i.exec(authority);\n if (!parts) return false;\n host = parts[1]; port = parts[2];\n const halves = host.split('::');\n if (halves.length > 2) return false;\n const groups = halves.flatMap(part => part ? part.split(':') : []);\n if (groups.some(group => !/^[0-9a-f]{1,4}$/i.test(group))) return false;\n if (halves.length === 1 ? groups.length !== 8 : groups.length >= 8) return false;\n } else {\n const parts = /^([^:]+)(?::(\\d+))?$/.exec(authority);\n if (!parts) return false;\n host = parts[1]; port = parts[2];\n if (host.length > 253) return false;\n const labels = host.replace(/\\.$/, '').split('.');\n if (!labels.every(label => label.length > 0 && label.length <= 63 && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label))) return false;\n if (labels.every(label => /^\\d+$/.test(label)) && (labels.length !== 4 || labels.some(label => Number(label) > 255))) return false;\n }\n return port === undefined || (port.length <= 5 && Number(port) <= 65535);\n }\n function asset(type) {\n for (const logo of logos) {\n if (logo?.type !== type || !Array.isArray(logo.formats)) continue;\n for (const format of logo.formats) {\n if (validUrl(format?.src)) return format.src;\n }\n }\n throw new Error(`No usable ${type} URL returned by Brandfetch`);\n }\n return {records:[{fields:{Name:name,'Icon URL':asset('icon'),'Logo URL':asset('logo')}}]};\n}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }