Send email from BambooHR when an employee record changes by using BambooHR’s outbound webhooks as the trigger and Volanea’s REST API as the delivery layer. BambooHR can POST employee-change data to an HTTPS endpoint, but the safe implementation is a server-side relay—not a direct call from BambooHR to an email API with a secret embedded in the URL.

This guide shows a practical integration for an HR workflow: notify a new employee after their Employment Status changes to Active. The same pattern works for onboarding reminders, manager notifications, equipment checklists, policy acknowledgements, and internal alerts triggered by changes to employee data.

What this BambooHR integration does

BambooHR does not need a native Volanea marketplace app for this workflow. Its webhook feature can notify an HTTPS endpoint when employee data changes, and your endpoint can decide whether that change should produce an email.

The flow is deliberately simple:

  1. An employee record changes in BambooHR.
  2. A Field-Based Webhook fires when a monitored employee field changes.
  3. BambooHR sends a JSON payload to an HTTPS endpoint you control.
  4. The endpoint verifies the BambooHR request, checks the relevant employee fields, and creates a stable idempotency key.
  5. The endpoint calls POST https://api.volanea.com/v1/send with the Volanea secret key held only on the server.
  6. Volanea accepts the transactional message for sending, while your relay records the result for support and audit purposes.

For the example below, the concrete BambooHR trigger is employee_with_fields.updated: a monitored field on an employee record changed. Configure Employment Status as the monitored field. The webhook may also include configured post fields such as Work Email, First Name, Last Name, Job Title, Department, and Hire Date.

That distinction matters. A BambooHR field-based webhook can contain the employee data you explicitly configure as post fields, but it is not a general-purpose workflow engine that can safely hold an outbound Volanea credential. Treat BambooHR as the system that signals a business event; treat your relay as the policy, security, and delivery boundary.

Choose the right BambooHR webhook payload

BambooHR supports Event-Based and Field-Based webhook structures. Event-Based webhooks are recommended by BambooHR for lightweight notifications: they identify the event and employee, then your service fetches the latest employee data through the BambooHR API. Field-Based webhooks are more convenient for a narrowly scoped email trigger because they can include selected employee fields directly in the webhook body.

For an onboarding email based on an Employment Status change, use a Field-Based Webhook. It gives the relay the fields required to make a send/no-send decision without immediately making a second API request.

The exact trigger to configure

In BambooHR, configure a Field-Based Webhook in Account Settings > Webhooks with these choices:

  • Event: employee_with_fields.updated
  • Monitor field: Employment Status
  • Format: JSON
  • Destination URL: your HTTPS relay endpoint, such as https://integrations.example.com/webhooks/bamboohr
  • Post fields: Work Email, First Name, Last Name, Job Title, Department, Hire Date, and Employment Status

Use field aliases where available so the payload is stable and readable. For example, map BambooHR fields to workEmail, firstName, lastName, jobTitle, department, hireDate, and employmentStatus in the outgoing payload.

The webhook will fire whenever the monitored Employment Status field changes. Your relay must still examine the value and send only when the employee has reached the state that should trigger the email. A webhook saying that Employment Status changed is not, by itself, proof that the new value is Active.

The BambooHR payload your relay receives

A Field-Based Webhook posts an employees array. An updated record includes an action, the changed field names, configured field values, an employee ID, and a timestamp. With aliases configured, a representative payload looks like this:

{
  "employees": [
    {
      "action": "Updated",
      "changedFields": ["employmentStatus"],
      "fields": {
        "firstName": "Avery",
        "lastName": "Nguyen",
        "workEmail": "avery.nguyen@example.com",
        "jobTitle": "Product Designer",
        "department": "Product",
        "hireDate": "2026-10-15",
        "employmentStatus": "Active"
      },
      "id": "12345",
      "timestamp": "2026-10-15T15:30:00+0000"
    }
  ]
}

Do not assume every field will always be populated. For example, a company may not use Work Email until an account-provisioning step is complete, a custom access level may not expose a requested field, or a field may be empty for a particular employee. Your relay should validate the exact fields needed for this message and return a successful webhook response after recording a non-send reason when an email address is absent.

Why a relay is required instead of a direct BambooHR-to-Volanea call

BambooHR webhooks send a POST request to the URL you configure. That is ideal for notifying a service you own, but it is not a safe place to store or expose the Volanea secret key.

A Volanea API key authorizes email sending. If you placed it in a destination URL query string, an exposed configuration, a browser-visible script, a screenshot, a ticket, or an access log could leak it. URL query strings are especially unsuitable for secrets because they are commonly retained by proxies, request logs, analytics tools, and support tooling.

The correct answer to “where does the Volanea API key live on the BambooHR side?” is: it does not live in BambooHR at all. Store it as a secret in the environment or secret manager for the relay that receives BambooHR’s webhook.

Use a deployment platform’s encrypted secret storage, such as a server environment variable, managed secret vault, or runtime secret binding. The relay should read VOLANEA_API_KEY at runtime. It should never return the value to BambooHR, include it in response bodies, log it, place it in a client-side application, or commit it to source control.

The relay gives you other operational benefits too:

  • It verifies that the request came from BambooHR before doing any work.
  • It prevents an accidental status update from creating an unwanted email.
  • It can apply business rules, such as only sending to a company address.
  • It can create idempotency keys for retry safety.
  • It can record which employee event produced which email submission.
  • It lets you evolve message templates without changing BambooHR configuration.

For the underlying endpoint, authentication, and message options, use the Volanea email API reference as the implementation source of truth.

Configure the BambooHR Field-Based Webhook

Start with a small and intentional payload. Sending every available HR field to an email relay increases privacy exposure and makes changes harder to reason about. An onboarding message normally does not need compensation data, personal addresses, tax information, or any other sensitive HR fields.

Recommended field selection

For this specific Active-status onboarding notification, configure only these post fields:

BambooHR fieldSuggested aliasWhy the relay needs it
Employment StatusemploymentStatusDetermines whether the webhook event qualifies for a send
Work EmailworkEmailTransactional recipient address
First NamefirstNamePersonalizes the message
Last NamelastNameOptional display and audit context
Job TitlejobTitleUseful onboarding context
DepartmentdepartmentUseful routing or copy decisions in the relay
Hire DatehireDateLets the relay prevent a premature or stale welcome email

Make Employment Status the monitored field. The other values are post fields so BambooHR includes their current values when that monitored field changes.

BambooHR documents that created and deleted Field-Based events have empty changedFields and fields objects. That is why this guide uses the updated event for a status-based message. The relay should not attempt to send a personalized message from a created or deleted notification unless it fetches the employee’s current data separately through the BambooHR API.

Keep the event rule precise

Avoid a broad rule such as “send whenever an employee is updated.” Many normal HR operations change employee records: title changes, department moves, manager updates, phone number corrections, and data clean-up. Sending an onboarding email on every update is a fast path to duplicate or confusing messages.

Instead, check all of these conditions in the relay:

  1. action is Updated.
  2. changedFields contains employmentStatus.
  3. fields.employmentStatus equals the specific value you use for active employees, such as Active.
  4. fields.workEmail is a syntactically valid company email address.
  5. The event has not already produced this logical message.

The exact spelling and available values of Employment Status are account-specific. Confirm whether your BambooHR account uses Active, Full-Time, Employed, a custom status, or another value. Do not copy a sample string into production without checking the value your account actually sends.

Map BambooHR fields to a Volanea email request

The following Node.js example receives an already verified BambooHR JSON payload, selects qualifying employee updates, and sends one Volanea transactional message per employee. It maps the concrete BambooHR fields values into the Volanea to, subject, text, and html fields.

The code intentionally keeps the Volanea key in process.env.VOLANEA_API_KEY. It also sends a stable Idempotency-Key based on the employee ID, the triggering timestamp, and the email purpose. If BambooHR retries the same delivery, Volanea can recognize the repeat request as the same logical send rather than creating a second email.

// Node.js 18+; call this only after verifying BambooHR's signature
// against the raw request body, X-BambooHR-Timestamp, and
// X-BambooHR-Signature using the private key generated by BambooHR.

const VOLANEA_API_URL = "https://api.volanea.com/v1/send";

function escapeHtml(value = "") {
  return String(value)
    .replaceAll("&", "&")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

function isCompanyEmail(email) {
  return typeof email === "string" &&
    /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

async function sendActiveEmployeeEmail(employee) {
  const { action, changedFields = [], fields = {}, id, timestamp } = employee;

  const statusChanged = changedFields.includes("employmentStatus");
  const becameActive = fields.employmentStatus === "Active";
  const recipient = fields.workEmail?.trim().toLowerCase();

  if (action !== "Updated" || !statusChanged || !becameActive) {
    return { skipped: true, reason: "event does not qualify" };
  }

  if (!isCompanyEmail(recipient)) {
    return { skipped: true, reason: "missing or invalid workEmail" };
  }

  const firstName = fields.firstName || "there";
  const jobTitle = fields.jobTitle || "your new role";
  const department = fields.department || "your team";

  const message = {
    from: "People Operations <people@example.com>",
    to: [recipient],
    subject: `Welcome to ${department}, ${firstName}`,
    text: [
      `Hi ${firstName},`,
      "",
      `Your BambooHR status is now Active for ${jobTitle}.`,
      "",
      "Welcome aboard. Your People Operations team will send the next onboarding steps shortly."
    ].join("\n"),
    html: `
      <p>Hi ${escapeHtml(firstName)},</p>
      <p>Your BambooHR status is now <strong>Active</strong> for ${escapeHtml(jobTitle)}.</p>
      <p>Welcome aboard. Your People Operations team will send the next onboarding steps shortly.</p>
    `
  };

  const idempotencyKey = `bamboohr-active-onboarding:${id}:${timestamp}`;

  const response = await fetch(VOLANEA_API_URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": idempotencyKey
    },
    body: JSON.stringify(message)
  });

  const result = await response.json().catch(() => ({}));

  if (!response.ok) {
    throw new Error(`Volanea send failed (${response.status}): ${JSON.stringify(result)}`);
  }

  return {
    skipped: false,
    employeeId: id,
    idempotencyKey,
    volanea: result
  };
}

export async function handleVerifiedBamboohrPayload(payload) {
  if (!Array.isArray(payload.employees)) {
    throw new Error("Unexpected BambooHR Field-Based Webhook payload");
  }

  return Promise.all(payload.employees.map(sendActiveEmployeeEmail));
}

Replace people@example.com with an address at a verified sending domain in your Volanea account. The from address is not just a branding detail: it should align with the domain authentication you have configured for delivery and recipient trust.

The example sends inline HTML and text because it is easy to test. For production onboarding programs, a reusable Volanea template can be a better long-term choice. It separates message design from the webhook receiver and makes it easier for HR and communications teams to review copy without editing application code.

Secure the BambooHR-to-relay hop

The email request is only half of the integration. The more important security boundary is the incoming BambooHR webhook.

BambooHR requires HTTPS webhook URLs and includes X-BambooHR-Timestamp and X-BambooHR-Signature headers. Its documentation instructs receivers to verify the signature with the webhook private key, the raw request body, and the timestamp. Capture and preserve the raw request body before a JSON parser changes whitespace or object representation; signature verification generally depends on the original bytes received.

Store two separate secrets

This design has two different secrets with different purposes:

  • BambooHR webhook private key: verifies that the inbound event is authentic. Store it as BAMBOOHR_WEBHOOK_PRIVATE_KEY in the relay’s secret manager.
  • Volanea secret API key: authorizes the outbound email request. Store it as VOLANEA_API_KEY in the same server-side secret manager, with access restricted to the relay runtime.

Do not confuse the two. The BambooHR private key should never be sent to Volanea. The Volanea key should never be sent to BambooHR.

Protect against replay and forged requests

Signature verification is necessary but not sufficient. Add a timestamp freshness check before processing a webhook. A valid old request replayed days later may still have a correct signature but should not be treated as a new onboarding event.

A strong receiver should:

  • Reject requests without the expected BambooHR signature and timestamp headers.
  • Verify the signature against the raw body using the private key BambooHR generated for the webhook.
  • Reject timestamps outside a short permitted clock-skew window.
  • Accept only application/json for this configuration.
  • Limit request body size.
  • Log the event type, employee ID, webhook timestamp, decision, and Volanea response reference—but never log secret values or full sensitive employee payloads.

If a webhook’s private key is lost, treat it like any other secret-rotation incident. Create or rotate the webhook according to BambooHR’s documented process, store the new private key safely, update the receiver, and test before disabling the old configuration.

Make duplicate sends unlikely, then make them harmless

A webhook delivery and an email send are separate network operations. Your relay can successfully submit an email to Volanea, lose its connection before reading the response, and then receive a retry from BambooHR. Without idempotency, that ambiguity can result in two welcome emails.

Volanea supports the Idempotency-Key header on send requests. Reuse the same key when retrying the same logical operation. Do not create a random UUID on every HTTP attempt; that would make every retry look like a new request.

Build the key from the business event

For this integration, the example uses:

bamboohr-active-onboarding:<employee-id>:<webhook-timestamp>

That is a reasonable starting key because the employee ID identifies the subject, the BambooHR timestamp identifies the event occurrence, and the prefix distinguishes this message type from future email types. If the exact same BambooHR webhook arrives again, the relay derives the same key.

Still, also keep your own durable event ledger. A database table with a unique constraint on employee_id, event_timestamp, and message_type protects you even if an upstream system changes retry behavior or a message needs additional operational review.

A minimal record can include:

  • BambooHR employee ID
  • BambooHR webhook timestamp
  • changed fields
  • normalized status value
  • email purpose, such as active-onboarding
  • recipient address used at send time
  • idempotency key
  • Volanea response or message reference
  • relay processing status and error details

This record also answers the support question that always appears eventually: “Why did Avery receive this email?”

Test the integration before enabling production sends

Email automation connected to HR data deserves a staged rollout. Test the webhook receiver, BambooHR field configuration, sending domain, and duplicate safeguards independently before you activate it for live employee records.

A practical test sequence

  1. Create a non-production or controlled test employee with a real test inbox you own.
  2. Configure the Field-Based Webhook with JSON output and only the required post fields.
  3. Point BambooHR temporarily at a request-inspection endpoint or a relay endpoint that logs redacted payload structure.
  4. Change Employment Status from a non-qualifying value to the qualifying value used by your account.
  5. Confirm that changedFields includes the alias for Employment Status and that fields contains the configured values.
  6. Restore the status and change it again to confirm your event rule works intentionally.
  7. Point the webhook at the production relay only after signature verification and field validation are in place.
  8. Use a Volanea test key if your account workflow supports it, then move to the production key and verified sender.
  9. Repeat the same webhook payload or force a relay retry to confirm the idempotency key prevents a duplicate logical send.
  10. Review the Volanea send log and the relay audit record together.

Test negative cases, not only the happy path. Change a job title without changing Employment Status and ensure no onboarding email is sent. Set Work Email to blank and confirm the relay records a skip. Change status to a non-qualifying value and confirm no message is sent. These checks prove that your business rule—not merely your HTTP plumbing—is correct.

If you need to validate addresses before using them in a workflow, use the email address verification tool as a separate preflight step. It should not replace BambooHR’s own data-governance process or cause you to send messages to personal addresses by default.

When this breaks

Every integration breaks at boundaries: an upstream payload changes, a network connection times out, an employee record is incomplete, or a user loses permission. Design for those specific failure modes instead of assuming a webhook is a once-only, perfectly ordered command.

BambooHR retries can create duplicate-send pressure

Webhook delivery is not a guarantee of exactly-once processing. If your endpoint returns an error, times out, or loses a connection before BambooHR recognizes a successful response, BambooHR may try delivery again. A retry can be the exact same employee update.

Your defenses are a stable Volanea Idempotency-Key and an internal event ledger with a unique constraint. Return a fast success response only after the event is safely recorded or durably queued. If sending email takes longer than the webhook response budget, write the event to a queue first, return success, and let a background worker call Volanea.

Do not rely solely on changedFields for deduplication. Two deliveries can have the same changed field and timestamp, and two legitimate employment-status changes may happen over time. Use a business-event identifier built from employee ID, webhook timestamp, and message type, then retain enough audit data to distinguish a replay from a new transition.

Webhook timeouts and slow downstream calls

Do not make BambooHR wait while the relay performs long-running work, renders complex templates, queries several systems, or retries an email provider repeatedly. A slow receiver increases the chance of delivery timeouts and retry traffic.

The production pattern is:

  1. Verify BambooHR’s signature.
  2. Validate and normalize the payload.
  3. Store a dedupe record and enqueue a job in one durable operation.
  4. Respond promptly to BambooHR.
  5. Let a worker send the message to Volanea with the stable idempotency key.
  6. Store the Volanea response and delivery-related outcomes for observability.

This architecture also isolates temporary Volanea API failures from inbound webhook availability. Your endpoint can remain responsive while the worker applies controlled retry rules for retryable outbound errors.

Payload fields may be unavailable or empty

The fields available to a BambooHR webhook depend on the webhook type and permissions. Global Webhooks have a predefined monitorable field list, while Permissioned Webhooks are tied to the access level of the API user that created them. A webhook can stop delivering the intended data when the underlying user is deactivated or when permissions are changed.

Plan for missing fields. workEmail may be empty, a post field may have a different alias than expected, and some fields may not be accessible under the creator’s access level. Custom-table fields are also not supported by BambooHR webhooks, so do not build a critical email trigger around data that exists only in a custom table.

A safe relay behavior is to mark the event as skipped_missing_recipient or skipped_missing_required_field, alert the integration owner when the rate rises, and avoid retrying indefinitely. Retrying cannot manufacture a missing email address.

The status value does not match your rule

An employee record may show a status string you did not expect. This often happens after HR configuration changes, localization changes, a new employment category is introduced, or a staging account differs from production.

Log the normalized status value and make the qualifying states configurable, for example through a server-side allowlist such as ACTIVE_EMPLOYMENT_STATUSES=Active,Regular. Do not make the allowlist client-visible or editable by an untrusted requester.

The sender domain is not ready

A valid webhook and successful API response do not automatically mean a recipient sees the message in the inbox. The sending domain must be verified and authenticated, and the from address must use that verified domain. Use a clear operational sender such as people@example.com or onboarding@example.com, not an employee’s personal address.

Before launch, send to test inboxes at major mailbox providers, inspect the rendered HTML and text versions, and confirm your organization’s HR communications policy permits this type of automated email.

Operational guidance for HR and engineering teams

The integration is technically small, but its impact is organizational. A message triggered from an HR system can communicate employment status, onboarding progress, team assignment, or access expectations. That makes correctness, privacy, and ownership more important than clever automation.

Define message ownership

Agree on who owns each part of the workflow:

  • HR or People Operations: defines the business trigger and approves copy.
  • BambooHR administrator: manages access, webhook configuration, and status-field semantics.
  • Engineering or IT: owns the receiver, signatures, secrets, deployment, retries, and monitoring.
  • Security or compliance: reviews the payload minimization and retention policy.

Write down the exact condition in human terms: “Send the onboarding email once when an employee’s Employment Status changes to Active and a work email exists.” That sentence is more useful in incident review than a vague automation name.

Keep employee data out of unnecessary systems

The webhook payload should include only fields that help produce the email. Do not send date of birth, home address, compensation, SSN, tax fields, or other sensitive HR data to a notification relay unless there is a documented and reviewed requirement.

Likewise, avoid placing raw webhook payloads in long-lived application logs. Store a redacted event audit record, such as employee ID, field names, decision, recipient domain, and message reference. Restrict access to any system that retains HR identifiers.

Monitor the whole chain

A reliable integration needs visibility at all three layers:

  • BambooHR: webhook configuration and delivery logs.
  • Relay: authentication failures, validation skips, queue depth, duplicate suppression, and outbound error rates.
  • Volanea: accepted sends, delivery events, bounces, suppressions, and provider responses.

BambooHR’s webhook logs cover recent delivery activity, so check them when an event does not appear in the relay. If the relay received the event but did not send, use your event ledger to identify the reason. If Volanea accepted the send but delivery fails later, troubleshoot the message and recipient state at the email layer rather than recreating the BambooHR event.

Alternatives when Field-Based Webhooks are not enough

Field-Based Webhooks are a good fit when the email decision depends on a small selection of employee fields. They are less suitable when your email needs complicated data assembly, cross-system lookups, approval logic, or custom-table data.

Use Event-Based Webhooks plus the BambooHR API

BambooHR’s Event-Based Webhooks provide a smaller payload containing the event type, company ID, employee ID, timestamp, and—on updates—the changed fields. Your relay can then fetch the latest employee data using the BambooHR API.

Choose this model when the email must use the most current record after several related updates, when payload minimization is important, or when your logic requires a canonical read from BambooHR. It adds an API call and credential management for BambooHR access, but it avoids relying on a large webhook body.

Use a middleware platform only when its security model fits

A middleware platform can receive BambooHR events and make an HTTP request to your service. It may be useful for prototypes or low-complexity routing, but do not let it become the only place where sensitive HR logic, recipient rules, and email credentials live unless it has the right secret storage, access control, auditability, and retry controls for your organization.

For most production teams, the most maintainable model remains: BambooHR webhook to a small protected relay, then relay to Volanea. That keeps the Volanea secret, idempotency logic, validation rules, and audit trail in infrastructure your team controls.

Conclusion

To send email from BambooHR with Volanea, configure a BambooHR Field-Based Webhook for employee_with_fields.updated, monitor Employment Status, and post only the employee fields needed for the message. Send that JSON to an HTTPS relay you control, verify the BambooHR signature, validate the event and recipient, and use the relay’s server-side Volanea key to call POST /v1/send.

The important engineering choice is not the HTTP request itself. It is the boundary around it: no API key in BambooHR configuration, no broad HR payloads, no unguarded retries, and no assumption that an employee update should always become an email. With field validation, a deterministic idempotency key, and an audit record, the workflow can stay dependable as HR data and operational requirements change.

FAQ

Can BambooHR send directly to Volanea?

BambooHR can send webhook POST requests to an HTTPS URL, but a direct webhook-to-email-API design would require exposing or embedding the Volanea secret somewhere BambooHR can use it. Use a server-side relay instead. The relay keeps the Volanea key secret, verifies BambooHR’s signature, and controls message logic.

What BambooHR event should trigger the email?

For a status-driven onboarding message, use the Field-Based Webhook event employee_with_fields.updated and make Employment Status the monitored field. In the relay, check that the changed field is Employment Status and that its new value matches your qualifying status, such as Active.

Why did no email send after a BambooHR update?

Common causes are an unchanged monitored field, a status value that does not match your rule, a missing Work Email post field, a permission change affecting the webhook, failed signature verification, a skipped duplicate event, or an unverified Volanea sender domain. Check BambooHR webhook logs, then inspect the relay audit record before resending manually.

How do I stop BambooHR webhook retries from sending duplicate emails?

Use one deterministic Idempotency-Key per logical email event, such as an employee ID plus BambooHR webhook timestamp and message type. Reuse that exact key on retries, and store a durable event ledger with a uniqueness rule so your relay can identify repeat deliveries.

Can I use the same pattern for manager or IT notifications?

Yes. Change the recipient mapping and business rule. For example, a department change could notify a provisioning queue, or an Employment Status transition could notify a manager. Keep the recipient decision on the server, minimize the BambooHR fields you transmit, and give each message type its own idempotency-key prefix.