{
  "id": "LWWXKqrEi3hdNOy2",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Extract tracking numbers from Gmail PDF attachments to Google Sheets with okraPDF OCR",
  "tags": [],
  "nodes": [
    {
      "id": "ec424789-3e22-4124-9dd2-2308393103d2",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2480,
        -352
      ],
      "parameters": {
        "width": 480,
        "height": 560,
        "content": "## Extract tracking numbers from Gmail PDF attachments to Google Sheets with okraPDF OCR\n\nFor operations, ecommerce, logistics, and support teams that get scanned shipping labels or delivery PDFs in Gmail and need the tracking numbers logged in Google Sheets \u2014 without copying from images by hand.\n\n### How it works\n\n1. The Gmail trigger watches for messages with PDF attachments and downloads the first one.\n2. An IF node confirms the attachment is really a PDF.\n3. The PDF is uploaded to okraPDF and an OCR parse job is started.\n4. The workflow waits and polls the job until it reaches a terminal state.\n5. A row is appended to Google Sheets with the sender, subject, job status, tracking-number candidates found in the OCR text, and a short preview.\n\n### Setup\n\n- Add Gmail, Google Sheets, and okraPDF (HTTP Header Auth) credentials.\n- Get an okraPDF API key at okrapdf.com/settings/keys.\n- Pick your destination spreadsheet and sheet in the Google Sheets node.\n- In \"Configure OCR Options\", raise okra_parse_pages if labels span more than one page.\n\n### Customization\n\nEdit the tracking-number expression for carrier-specific formats, or duplicate the PDF branch to handle attachment_1 and beyond."
      },
      "typeVersion": 1
    },
    {
      "id": "ce773849-4aac-4568-a005-406476a9a5d1",
      "name": "Section - Receive",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1952,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 360,
        "content": "## 1. Receive & filter PDF emails\n\nThe Gmail trigger downloads the first attachment; the IF node lets only real PDFs continue."
      },
      "typeVersion": 1
    },
    {
      "id": "c50f31f6-3dfa-4f9a-9aa7-1553b7e889a1",
      "name": "Section - Upload & parse",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1488,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 620,
        "height": 360,
        "content": "## 2. Upload & start OCR\n\nSet OCR options, upload the PDF to okraPDF, and start an OCR parse job."
      },
      "typeVersion": 1
    },
    {
      "id": "4681f65b-2c6f-4d39-916c-fa7ae781507b",
      "name": "Section - Poll & log",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -816,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 840,
        "height": 360,
        "content": "## 3. Poll, then log to Sheets\n\nWait and re-poll the job until it's terminal, then append a tracking-number row to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "fb3f664e-48a2-48d2-915d-307dc713f4cf",
      "name": "Gmail Trigger - PDF Attachments",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -1904,
        -128
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "has:attachment filename:pdf",
          "readStatus": "unread"
        },
        "options": {
          "downloadAttachments": true,
          "dataPropertyAttachmentsPrefixName": "attachment_"
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "de87d992-c4fe-46c6-817b-5adab6359f9e",
      "name": "IF attachment_0 is PDF",
      "type": "n8n-nodes-base.if",
      "position": [
        -1680,
        -128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "has-attachment-0",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $binary.attachment_0?.mimeType || '' }}",
              "rightValue": "application/pdf"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "980fa6e5-dd29-47f5-9648-9ddc0efb1cdf",
      "name": "Configure OCR Options",
      "type": "n8n-nodes-base.set",
      "position": [
        -1456,
        -128
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "okra-parser",
              "name": "okra_parser",
              "type": "string",
              "value": "gemini-vision"
            },
            {
              "id": "okra-parse-pages",
              "name": "okra_parse_pages",
              "type": "string",
              "value": "1"
            },
            {
              "id": "okra-metadata-source",
              "name": "okra_metadata_source",
              "type": "string",
              "value": "n8n-gmail-tracking"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "6d93d0d4-4914-4fe3-bf32-404fec48f98b",
      "name": "Upload attachment_0 to okraPDF",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1232,
        -128
      ],
      "parameters": {
        "url": "https://api.okrapdf.com/v1/files",
        "method": "POST",
        "options": {
          "timeout": 300000
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "attachment_0"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e7068726-2075-479a-911f-df67b1c1305c",
      "name": "OCR Parse Uploaded PDF",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1008,
        -128
      ],
      "parameters": {
        "url": "https://api.okrapdf.com/v1/parse",
        "method": "POST",
        "options": {
          "timeout": 300000
        },
        "jsonBody": "={\n  \"parser\": \"{{ $('Configure OCR Options').item.json.okra_parser || 'gemini-vision' }}\",\n  \"file\": { \"id\": \"{{ $json.id }}\" },\n  \"pages\": \"{{ $('Configure OCR Options').item.json.okra_parse_pages || '1' }}\",\n  \"metadata\": { \"source\": \"{{ $('Configure OCR Options').item.json.okra_metadata_source || 'n8n-gmail-tracking' }}\" }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "824c49c6-5b94-46d3-9695-18f8849b6916",
      "name": "Wait for Parse Result",
      "type": "n8n-nodes-base.wait",
      "position": [
        -784,
        -128
      ],
      "parameters": {
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "ca06c61e-0fea-4fad-bdac-03f17a351930",
      "name": "Get Job Result",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -560,
        -208
      ],
      "parameters": {
        "url": "={{ ($json.status_url && $json.status_url.startsWith('http')) ? $json.status_url : ('https://api.okrapdf.com/v1/jobs/' + ($json.id || $json.job_id)) }}",
        "options": {
          "timeout": 300000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "78fa88fc-cec5-4c27-bacc-7ef036809c77",
      "name": "If Job Finished?",
      "type": "n8n-nodes-base.if",
      "position": [
        -336,
        -128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "terminal-status",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ ['succeeded','completed','completed_with_errors','failed','canceled','cancelled'].includes(($json.status || $json.internal_status || '').toLowerCase()) ? 'done' : 'pending' }}",
              "rightValue": "done"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "76063812-ff91-4546-bbea-29592e4a7e9a",
      "name": "Append Tracking Row to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -112,
        -128
      ],
      "parameters": {
        "columns": {
          "value": {
            "result": "={{ $json.result.formats.nodes.pages }}"
          },
          "schema": [
            {
              "id": "object",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "object",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "type",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "created",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "created",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "livemode",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "livemode",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "job_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "job_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "owner_user_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "owner_user_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "job_type",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "job_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "job_label",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "job_label",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "internal_status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "internal_status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "document_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "document_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "file_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "file_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "run_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "run_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "workflow_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "workflow_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "workflow_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "workflow_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "engine_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "engine_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "provider",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "provider",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "model",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "progress_current",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "progress_current",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "progress_total",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "progress_total",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "progress",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "progress",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pages_completed",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "pages_completed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pages_failed",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "pages_failed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pages_running",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "pages_running",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pages_pending",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "pages_pending",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pages_total",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "pages_total",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "chunks_completed",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "chunks_completed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "chunks_total",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "chunks_total",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "cost_usd",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "cost_usd",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "duration_ms",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "duration_ms",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "error",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "error",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "latest_error",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "latest_error",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_error",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_error",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "request",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "request",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "result",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "result",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "metadata",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "metadata",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "updated_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "completed_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "completed_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "completed",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "completed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Gg7QzB8Ap6XFBUsqAHKe865V-lt2e6QPm4rNqFud39I/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1Gg7QzB8Ap6XFBUsqAHKe865V-lt2e6QPm4rNqFud39I",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Gg7QzB8Ap6XFBUsqAHKe865V-lt2e6QPm4rNqFud39I/edit?usp=drivesdk",
          "cachedResultName": "n8n-okra"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "f41866bd-a4f3-476e-a573-762e57596745",
  "nodeGroups": [],
  "connections": {
    "Get Job Result": {
      "main": [
        [
          {
            "node": "If Job Finished?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Job Finished?": {
      "main": [
        [
          {
            "node": "Append Tracking Row to Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait for Parse Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure OCR Options": {
      "main": [
        [
          {
            "node": "Upload attachment_0 to okraPDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Parse Result": {
      "main": [
        [
          {
            "node": "Get Job Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF attachment_0 is PDF": {
      "main": [
        [
          {
            "node": "Configure OCR Options",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OCR Parse Uploaded PDF": {
      "main": [
        [
          {
            "node": "Wait for Parse Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload attachment_0 to okraPDF": {
      "main": [
        [
          {
            "node": "OCR Parse Uploaded PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Trigger - PDF Attachments": {
      "main": [
        [
          {
            "node": "IF attachment_0 is PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}