{
  "name": "blue·auth · Complete signature (create + self-sign + events)",
  "meta": {
    "templateCreatedBy": "blue·auth",
    "description": "Creates a request, self-signs two authorized participants through the API until completion, and receives events in a webhook. The selfSign flag alone does not sign; the /self-sign nodes perform each signature."
  },
  "nodes": [
    {
      "parameters": {},
      "id": "trigger-manual",
      "name": "When clicking Test workflow",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        220,
        340
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://blueauth.co/api/v1/signature-requests",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"documentName\": \"Contract.pdf\",\n  \"pdfBase64\": \"data:application/pdf;base64,REPLACE_WITH_BASE64\",\n  \"webhookUrl\": \"PASTE_WEBHOOK_PRODUCTION_URL_HERE\",\n  \"qr\": { \"enabled\": true, \"placement\": \"bottom-right\", \"pages\": \"first\" },\n  \"signers\": [\n    { \"email\": \"me@company.example\", \"fullName\": \"My Company\", \"idNumber\": \"123456789\", \"selfSign\": true, \"signatureMethod\": \"traditional\", \"zones\": [{ \"page\": 1, \"x\": 60, \"y\": 700, \"width\": 180, \"height\": 60, \"type\": \"signature\" }] },\n    { \"email\": \"customer@example.com\", \"fullName\": \"Final Customer\", \"idNumber\": \"987654321\", \"selfSign\": true, \"signatureMethod\": \"traditional\", \"zones\": [{ \"page\": 1, \"x\": 330, \"y\": 700, \"width\": 180, \"height\": 60, \"type\": \"signature\" }] }\n  ]\n}",
        "options": {}
      },
      "id": "http-create",
      "name": "1 · Create request",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        340
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE",
          "name": "BlueAuth (Authorization: Bearer ba_…)"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://blueauth.co/api/v1/signature-requests/{{ $('1 · Create request').item.json.requestId }}/self-sign",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"signerEmail\": \"me@company.example\"\n}",
        "options": {}
      },
      "id": "http-self1",
      "name": "2 · Self-sign (me)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        660,
        340
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE",
          "name": "BlueAuth (Authorization: Bearer ba_…)"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://blueauth.co/api/v1/signature-requests/{{ $('1 · Create request').item.json.requestId }}/self-sign",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"signerEmail\": \"customer@example.com\"\n}",
        "options": {}
      },
      "id": "http-self2",
      "name": "3 · Self-sign (customer) → complete",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        340
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE",
          "name": "BlueAuth (Authorization: Bearer ba_…)"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "blueauth",
        "options": {
          "rawBody": true
        }
      },
      "id": "webhook-events",
      "name": "Receive blue·auth events",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        220,
        650
      ],
      "webhookId": "blueauth-events"
    },
    {
      "parameters": {
        "jsCode": "const crypto = require('crypto');\nconst WEBHOOK_SECRET = $env.BLUEAUTH_WEBHOOK_SECRET || 'whsig_REPLACE';\nconst raw = JSON.stringify($input.first().json.body ?? $input.first().json);\nconst header = ($input.first().json.headers || {})['x-blueauth-signature'] || '';\nconst expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(raw, 'utf8').digest('hex');\nconst valid = header && expected.length === header.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));\nconst event = ($input.first().json.headers || {})['x-blueauth-event'] || ($input.first().json.body || {}).event;\nreturn [{ json: { valid, event, payload: $input.first().json.body ?? $input.first().json } }];"
      },
      "id": "verify-hmac",
      "name": "Verify HMAC",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        650
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.event }}",
                    "rightValue": "signature.completed",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ]
              },
              "outputKey": "completed"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.event }}",
                    "rightValue": "signature.signed",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ]
              },
              "outputKey": "signed"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "id": "switch-event",
      "name": "Branch by event",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        660,
        650
      ]
    },
    {
      "parameters": {
        "content": "## ⚙️ One-time setup\n1. Add a **Header Auth** credential to the HTTP nodes: `Authorization` = `Bearer ba_test_…` (create one at blueauth.co/g/developer/api-keys).\n2. Copy the webhook **Production URL** (`/webhook/…`) and paste it into the `webhookUrl` field in **1 · Create request**.\n3. Set the workflow to **Active** to receive events.\n4. Add your PDF's base64 value to `pdfBase64` in **1 · Create request**.",
        "height": 200,
        "width": 920,
        "color": 7
      },
      "id": "note-setup",
      "name": "Sticky · Setup",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        200,
        20
      ]
    },
    {
      "parameters": {
        "content": "## 🟦 Lane A · Create and self-sign (without email)\nCreate the request → self-sign slot 0 (me) → self-sign slot 1 (customer). `selfSign:true` does not sign by itself: the **/self-sign** nodes apply the signatures in sequence (slot 0 before slot 1). The request then becomes **completed** with a stamped PDF and QR code.\n\n• `idNumber` appears in the stamp (Signed by · ID · Date).",
        "height": 230,
        "width": 920,
        "color": 5
      },
      "id": "note-laneA",
      "name": "Sticky · Lane A",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        200,
        250
      ]
    },
    {
      "parameters": {
        "content": "## 🟩 Lane B · Receive events\nThe webhook receives `signature.sent / signed / completed / declined`. **Verify HMAC** validates `X-BlueAuth-Signature` with the `webhookSecret`. The **Switch** branches by event type; connect any destination you need, such as Slack, email, or a database. `signature.completed` includes `signedPdfUrl`.",
        "height": 230,
        "width": 720,
        "color": 4
      },
      "id": "note-laneB",
      "name": "Sticky · Lane B",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        200,
        560
      ]
    }
  ],
  "connections": {
    "When clicking Test workflow": {
      "main": [
        [
          {
            "node": "1 · Create request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1 · Create request": {
      "main": [
        [
          {
            "node": "2 · Self-sign (me)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2 · Self-sign (me)": {
      "main": [
        [
          {
            "node": "3 · Self-sign (customer) → complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive blue·auth events": {
      "main": [
        [
          {
            "node": "Verify HMAC",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify HMAC": {
      "main": [
        [
          {
            "node": "Branch by event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  }
}
