> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getmailr.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Mailr is a direct-mail marketing platform for US home-services contractors. Each postcard is personalized with an AI-enhanced image of the recipient's own home and a unique QR code that leads to a personalized landing page. Campaigns can target a neighborhood the customer draws on a map, the homes around past jobs they upload or import, or fire automatically from their CRM. Mailr does not mail an uploaded recipient list. When answering questions, prefer the exact steps and UI labels from these docs, and direct users to app.getmailr.com to sign in. For anything involving account-specific data, billing disputes, or mail that appears lost, direct the user to support@getmailr.com.

# Trigger a specific automation directly

> Fire one named automation directly (the pre-v1 path the Zapier app and
HubSpot workflows use). Prefer `POST /api/v1/events` for new integrations —
it binds by event type instead of hardcoding an automation id and reports
richer outcomes. The target automation is named in `?id=` and must belong
to the key's org. Idempotent on `deal_id` (a repeat short-circuits before
geocoding). Field extraction is tolerant of HubSpot/Zapier mappings, so
`properties.*` aliases and flat fields both work.




## OpenAPI

````yaml /api-reference/openapi.yaml post /api/v1/webhooks/trigger
openapi: 3.1.0
info:
  title: Mailr Developer API
  version: 1.0.0
  description: >
    The Mailr Developer API lets a contractor's own CRM or automation stack
    drive

    Mailr directly with a per-tenant bearer key — no vendor polling, no Zapier
    in

    the middle. You push **events** when a job or deal changes, Mailr matches
    them

    against the automations you configured in the app and mails per-recipient

    Street View postcards; you push **won deals** and **leads** for revenue

    attribution; you **subscribe** an endpoint to receive captured leads back

    (HMAC-signed); and you **stage past jobs** for a reactivation campaign.


    ## Authentication


    Every endpoint here authenticates with an organization-scoped API key

    presented as `Authorization: Bearer ak_…`. The key alone identifies the

    tenant — you never pass an `org_id`, connection id, or batch id in the body
    or

    query; anything you could name is derived from the key. Create keys in the

    Mailr app under your workspace name (bottom-left) -> Manage account ->

    API keys (workspace Owner only).


    ## Scopes


    Keys may declare scopes. Policy (v1): if a key declares **any** scopes, it
    must

    include the scope an operation requires; a key that declares **no** scopes
    is

    treated as unrestricted and passes every check. The scopes in use are

    `events:write`, `import:write`, and `webhooks:inbound`. Each operation below

    documents its required scope under `x-required-scope`.


    ## Base URL


    Production is `https://app.getmailr.com`. All paths below are relative to
    it.


    ## Versioning


    The public API is versioned under `/api/v1/*` — every endpoint documented

    here lives under it. The Mailr Zapier app targets `/api/v1/*`; build new

    integrations against the same prefix.


    ## Idempotency


    Write endpoints are idempotent on a caller-supplied key: `dedup_id` on
    events,

    `deal_id`/address on conversions and leads. Imports are **not**
    deduplicated:

    one request is one batch, and duplicate addresses within or across batches
    are

    staged independently.

    Replaying the same request is safe and is reported back to you (e.g.

    `duplicate: true`, `idempotent: true`, or `reason: "duplicate"`).


    ## Auth-path errors (all endpoints)


    Besides each endpoint's own statuses, every authenticated endpoint can

    return two RETRYABLE auth-path errors: `429` `{ "error": "rate_limited" }`

    when the pre-auth per-IP limit (60/min/IP) trips, and `503`

    `{ "error": "auth_unavailable" }` when the auth provider is temporarily

    unreachable (your key was NOT checked). Both carry `Retry-After`. Neither

    means your key is bad — only a `401` does.


    ## Delivery cadence


    There is **no reconciliation sweep**. Mailr does not reach back into your
    CRM

    to pull anything it missed — the caller is the sync. If a push fails or you

    suspect a gap, **replay your events**; idempotency makes replays free.
  contact:
    name: Mailr
    url: https://app.getmailr.com
servers:
  - url: https://app.getmailr.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Events
    description: Push CRM/automation events that trigger campaigns (Developer API v1).
  - name: Imports
    description: >-
      Stage a batch of past jobs/customers for a reactivation campaign
      (Developer API v1).
  - name: Leads
    description: Receive captured leads (subscribe) and poll recent leads.
  - name: Attribution
    description: >-
      Report won deals and synced leads so revenue attributes to the campaign
      that mailed the address.
  - name: Customers
    description: Register existing customers for address suppression.
  - name: Account
    description: Identify the key's organization and list its automations.
paths:
  /api/v1/webhooks/trigger:
    post:
      tags:
        - Attribution
      summary: Trigger a specific automation directly
      description: >
        Fire one named automation directly (the pre-v1 path the Zapier app and

        HubSpot workflows use). Prefer `POST /api/v1/events` for new
        integrations —

        it binds by event type instead of hardcoding an automation id and
        reports

        richer outcomes. The target automation is named in `?id=` and must
        belong

        to the key's org. Idempotent on `deal_id` (a repeat short-circuits
        before

        geocoding). Field extraction is tolerant of HubSpot/Zapier mappings, so

        `properties.*` aliases and flat fields both work.
      operationId: triggerAutomation
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
          description: The automation id to trigger.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TriggerRequest'
            example:
              address: 3134 River Valley Dr, Austin, TX 78701
              customer_first_name: Dana
              customer_last_name: Reyes
              deal_id: deal-9931
      responses:
        '202':
          description: |
            Queued (or already queued — `idempotent: true`). `queue_id` is
            Mailr's internal id for the queued campaign job. `attribution` is
            present only for `deal_won` automations that attributed revenue.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TriggerResult'
              examples:
                queued:
                  value:
                    success: true
                    automation: Post-job reactivation
                    customer_added: true
                    queued: true
                    queue_id: e5f6a7b8-0000-0000-0000-000000000040
                    idempotent: false
                    address: 3134 River Valley Dr, Austin, TX 78701, USA
                idempotent:
                  value:
                    success: true
                    queued: true
                    queue_id: e5f6a7b8-0000-0000-0000-000000000040
                    idempotent: true
        '400':
          description: >-
            Missing `?id=`, invalid JSON, automations globally disabled,
            automation disabled, or no address.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                noId:
                  value:
                    error: Missing ?id= query parameter for automation ID
                noAddress:
                  value:
                    error: No address found in payload
        '401':
          description: Unauthorized.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Unauthorized
        '404':
          description: >-
            Automation not found (or owned by another org — indistinguishable by
            design).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Automation 123 not found
        '413':
          description: >-
            Request body exceeds 1 MB (declared Content-Length or actual bytes).
            Nothing was applied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: payload_too_large
                detail: Body must be at most 1048576 bytes.
        '429':
          description: More than 60 requests in the current one-minute window.
          headers:
            Retry-After:
              schema:
                type: string
                example: '60'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Too many requests
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Internal server error
components:
  schemas:
    TriggerRequest:
      type: object
      required:
        - address
      description: >
        Highly tolerant of CRM/Zapier field shapes. `address` may be given flat
        or

        as `properties.address` (also `deal_address`/`install_address`). Name
        may

        be `customer_first_name`/`customer_last_name`, `customer_name`, or CRM

        `properties.dealname`/`contact_name`. `deal_id` may be
        `properties.hs_object_id`

        or `objectId`.
      properties:
        address:
          type: string
        customer_first_name:
          type: string
        customer_last_name:
          type: string
        customer_name:
          type: string
        deal_id:
          type: string
        deal_amount:
          oneOf:
            - type: string
            - type: number
        deal_stage:
          type: string
        deal_name:
          type: string
        contact_email:
          type: string
        deal_date:
          type: string
        mailr_lead_id:
          type: string
          description: >-
            Echo-loop guard. Map this from the Mailr New Lead trigger when
            applicable.
        campaign_id:
          type: string
        properties:
          type: object
          additionalProperties:
            type: string
    TriggerResult:
      type: object
      properties:
        success:
          type: boolean
        automation:
          type: string
          description: Automation name (omitted on the deal_id idempotent short-circuit).
        customer_added:
          type: boolean
        queued:
          type: boolean
        queue_id:
          type: string
          description: Mailr's internal id for the queued campaign job.
        idempotent:
          type: boolean
          description: True when this was a replay of an already-queued deal_id.
        address:
          type: string
          description: >-
            The geocoded/formatted address (omitted on the idempotent
            short-circuit).
        attribution:
          type:
            - object
            - 'null'
          description: Present only for deal_won automations that attributed revenue.
    Error:
      type: object
      description: >
        Error body. `error` is a stable machine code; `detail` (when present) is
        a

        human-readable explanation naming the offending field. Note two families

        of code style coexist across the API: snake_case machine codes on the v1

        and rate-limited endpoints (`invalid_payload`, `rate_limited`,

        `automations_disabled`) and human sentences on the legacy endpoints

        (`Unauthorized`, `No address found in payload`). Both are returned in
        the

        `error` field.
      required:
        - error
      properties:
        error:
          type: string
          example: invalid_payload
        detail:
          type: string
          example: event_type is required
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: ak_
      description: 'Organization-scoped Mailr API key. Header: `Authorization: Bearer ak_…`.'

````