How to Process Signed Onboarding Forms from a Mailhook into Deputy

Receive emailed onboarding PDFs at a dedicated Spojit mailhook address, extract each new hire's details with AI, and create the employee record in Deputy automatically.

What This Integration Does

When a new hire signs an onboarding form, that PDF usually lands in an HR inbox and someone copies the name, email, and phone number into your workforce system by hand. This workflow removes that step. Your applicant tracking tool, e-signature platform, or HR mailbox forwards the signed PDF to a Spojit mailhook address. Spojit fetches the attachment, has a Knowledge node in Query mode read the structured details out of it, and creates the employee in Deputy so they are ready to be scheduled on their first day.

The run is push-based: any mail arriving at the mailhook address starts an execution within seconds, with no mailbox or polling to configure. The signed PDF flows from the Attachment node into a transient Knowledge collection, gets queried for the fields you need, and ends as a new Deputy employee. Each message is deduplicated, so a forwarded copy of the same email will not create a duplicate run. If a run fails partway, no employee is created until the final Deputy step succeeds, so you can safely re-send the email after fixing the cause.

Prerequisites

  • A Deputy connection added under Connections, with permission to create employees.
  • An onboarding PDF that contains the new hire's first name, last name, email, and mobile number in readable text (not a flattened scan, unless you rely on OCR).
  • A source that can email the signed PDF to a fixed address: an ATS, an e-signature platform (for example a completed-document notification), or an HR forwarding rule.
  • Knowing which Deputy location or company the new hire belongs to, if you want to set it on creation.

Step 1: Add a Mailhook trigger and generate the address

Create a new workflow and open the Trigger node. Set Trigger Type to Mailhook. Optionally set an Address prefix (1 to 24 characters, for example onboarding; the default is mh), then click Generate email address. Spojit produces a unique address like onboarding-a1b2c3d4e5f6g7h8@mailhook.spojit.com. Copy it and configure your ATS, e-signature platform, or mail forwarding rule to send completed onboarding PDFs there. To keep stray mail out, set a From allowlist with your sending system's address and an optional Subject regex such as onboarding|signed. The trigger output is available downstream as {{ input }}, including {{ input.from }}, {{ input.subject }}, and the attachment references in {{ input.attachments }}.

Step 2: Fetch the signed PDF with an Attachment node

Add an Attachment node after the trigger. This node only saves inside a Mailhook workflow, and it pulls the actual bytes of the file the email carried. Set Mode to Single so you get the first matching file as an object. Set Content type to application/pdf and a Filename pattern of *.pdf so only the onboarding document is fetched. Leave Fail if no attachment matches turned on for this workflow so a malformed email surfaces as a failed run instead of silently creating nothing. The output gives you {{ attachment.filename }}, {{ attachment.contentType }}, {{ attachment.size }}, and {{ attachment.content }}, where content is the base64 body you feed into the next step. Each attachment must be within the 10 MB per-file limit.

Step 3: Embed the PDF into a transient Knowledge collection

Add a Knowledge node in Embed mode. In the Collection dropdown choose Transient so the document is embedded just for this run and cleaned up automatically afterward; you do not need a file name or a persistent archive for a one-off extraction. Set Document Type to PDF and the Document Input to the base64 body from the previous step:

Document Input: {{ attachment.content }}

Give it an Output Variable such as embedResult so the run records the chunk count. Because the collection is transient, the next node can query it within the same run without you managing any storage.

Step 4: Extract the new hire's details with a Knowledge query

Add a second Knowledge node in Query mode against the same Transient collection. Write a Prompt that asks for exactly the fields Deputy needs, and attach a Response Schema so the Knowledge node returns clean JSON instead of prose. A prompt and schema like this work well:

Prompt: Extract the new hire's details from the signed onboarding form.
Return their legal first name, last name, email address, and mobile
phone number. If a field is missing, return an empty string for it.

Response Schema:
{
  "type": "object",
  "properties": {
    "firstName": { "type": "string" },
    "lastName":  { "type": "string" },
    "email":     { "type": "string" },
    "mobile":    { "type": "string" }
  },
  "required": ["firstName", "lastName", "email"]
}

Set an Output Variable such as employeeData. You can leave Result Count at its default of 5, which is plenty for a single short document.

Step 5: Guard against incomplete extractions with a Condition node

Add a Condition node to stop a half-blank record from reaching Deputy. Branch on whether the required fields came back populated, for example checking that {{ employeeData.email }} is not empty and contains an @. Wire the false branch to a Send Email node that alerts your HR team. In that node set Recipients to your HR address, a Subject like Onboarding form needs review: {{ input.subject }}, and a body that quotes {{ input.from }} so the reviewer can find the original email. This keeps bad data out of Deputy while making sure nothing is dropped silently.

Step 6: Create the employee in Deputy

On the true branch, add a Connector node in Direct mode, choose the Deputy connector, and select the create-employee tool. Direct mode is deterministic and costs no AI credits, which is what you want for a single predictable write. Map the employee object from the extracted variables. Deputy expects capitalized field names:

{
  "FirstName": "{{ employeeData.firstName }}",
  "LastName":  "{{ employeeData.lastName }}",
  "Email":     "{{ employeeData.email }}",
  "Mobile":    "{{ employeeData.mobile }}"
}

Run the workflow and the new hire appears in Deputy, ready to be added to a roster. If you want to confirm receipt, add a final Send Email node addressed to {{ input.replyTo }} letting the sender know the employee was created, since a mailhook run never replies to the sender on its own.

Tips

  • Use a transient collection rather than a persistent one for per-email extraction: it is auto-created and auto-cleaned each run, so you never accumulate stale onboarding documents.
  • If your forms are flattened scans rather than text PDFs, set Document Type to the OCR option so the text can still be read before embedding.
  • Set an Address prefix like onboarding so the mailhook address is recognizable when you paste it into your ATS or e-signature settings.
  • Keep the Deputy mapping in Direct mode so you get a predictable single write with no AI cost; reserve Agent mode for cases where the agent must decide between several tools.

Common Pitfalls

  • An Attachment node will not save without a Mailhook trigger; build the trigger first, then add the Attachment node.
  • Deputy field names are capitalized (FirstName, LastName, Email, Mobile). Mapping lowercase keys will not populate the record correctly.
  • Embed and query the transient collection within the same run. A transient collection does not persist after the run completes, so a later workflow cannot read it.
  • Mailhook runs are always asynchronous and never reply to the sender automatically. If you need a confirmation, send it explicitly to {{ input.replyTo }} with a Send Email node.
  • Attachments over the 10 MB per-file limit (or 25 MB across a run) will not be fetched; ask your source system to send a reasonably sized PDF.

Testing

Before pointing your live ATS or e-signature platform at the address, email a single sample signed PDF to the mailhook address yourself from an allowlisted sender. Open the run in execution history and check each node in order: confirm the Attachment node returned a non-zero size, that the embed step reported a chunk count, that employeeData holds the right name, email, and mobile, and that the Condition node took the true branch. Verify the new employee exists in Deputy and looks correct. Once one clean form flows end to end, send a deliberately incomplete form to confirm the false branch emails your HR team instead of creating a partial record, then enable the workflow.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.