{"openapi":"3.0.3","info":{"title":"MightyAutomation Agent API","version":"1.0.0","description":"Project-scoped automation & CRM API. Authenticate every request with `Authorization: Bearer <key>` — keys are minted in the app under Integrations → Zapier (scope `zapier`) or the agent-keys settings (scope `agent`). The project is resolved from the key; there is no project parameter on any route."},"servers":[{"url":"https://mightyautomation.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"mva_<scope>_<token>"}},"schemas":{"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"first_name":{"type":"string","nullable":true},"last_name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"lifecycle":{"type":"string","enum":["lead","prospect","contact","customer","churned"]},"pipeline_stage":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"do_not_contact":{"type":"boolean"},"custom":{"type":"object","additionalProperties":true},"physical_address_line1":{"type":"string","nullable":true},"physical_address_line2":{"type":"string","nullable":true},"physical_city":{"type":"string","nullable":true},"physical_state":{"type":"string","nullable":true},"physical_zip":{"type":"string","nullable":true},"mailing_address_line1":{"type":"string","nullable":true},"mailing_address_line2":{"type":"string","nullable":true},"mailing_city":{"type":"string","nullable":true},"mailing_state":{"type":"string","nullable":true},"mailing_zip":{"type":"string","nullable":true},"physical_country":{"type":"string","nullable":true},"mailing_country":{"type":"string","nullable":true},"middle_name":{"type":"string","nullable":true},"job_title":{"type":"string","nullable":true},"email_2":{"type":"string","nullable":true},"website":{"type":"string","nullable":true},"date_of_birth":{"type":"string","nullable":true},"external_id":{"type":"string","nullable":true},"social_x":{"type":"string","nullable":true},"social_linkedin":{"type":"string","nullable":true},"social_linkedin_page":{"type":"string","nullable":true},"social_facebook":{"type":"string","nullable":true},"social_instagram":{"type":"string","nullable":true},"social_tiktok":{"type":"string","nullable":true},"social_youtube":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"AgentEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","description":"contact_created | tag_added | entered_stage | lifecycle_changed | form_submitted | activity_logged | appointment_booked | appointment_rescheduled | appointment_cancelled | appointment_completed | appointment_no_show | call_completed | call_outcome"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"string","format":"uuid"},"contact_id":{"type":"string","format":"uuid","nullable":true},"contact":{"$ref":"#/components/schemas/Contact"},"data":{"type":"object","additionalProperties":true}}},"ContactUpsert":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"company":{"type":"string"},"lifecycle":{"type":"string"},"pipeline_stage":{"type":"string","description":"Must match a stage name from GET /api/agent/pipeline-stages"},"source":{"type":"string"},"tags":{"type":"array","items":{"type":"string"},"description":"Merged, never replaced"},"notes":{"type":"string","description":"Appended to the contact notes"},"physical_address_line1":{"type":"string"},"physical_address_line2":{"type":"string"},"physical_city":{"type":"string"},"physical_state":{"type":"string"},"physical_zip":{"type":"string"},"mailing_address_line1":{"type":"string"},"mailing_address_line2":{"type":"string"},"mailing_city":{"type":"string"},"mailing_state":{"type":"string"},"mailing_zip":{"type":"string"},"physical_country":{"type":"string"},"mailing_country":{"type":"string"},"middle_name":{"type":"string"},"job_title":{"type":"string"},"email_2":{"type":"string"},"website":{"type":"string"},"date_of_birth":{"type":"string"},"external_id":{"type":"string"},"social_x":{"type":"string"},"social_linkedin":{"type":"string"},"social_linkedin_page":{"type":"string"},"social_facebook":{"type":"string"},"social_instagram":{"type":"string"},"social_tiktok":{"type":"string"},"social_youtube":{"type":"string"},"custom":{"type":"object","additionalProperties":true}}}}},"security":[{"bearer":[]}],"paths":{"/api/agent/me":{"get":{"summary":"Validate the API key and return the bound project","responses":{"200":{"description":"{ ok, project_id, project_name, key_label, scope }"}}}},"/api/agent/contacts":{"get":{"summary":"List or search contacts (newest first)","parameters":[{"name":"email","in":"query","schema":{"type":"string"},"description":"Case-insensitive email match — contact lookup"},{"name":"phone","in":"query","schema":{"type":"string"},"description":"Any of the contact phone numbers (normalized to E.164)"},{"name":"id","in":"query","schema":{"type":"string","format":"uuid"},"description":"One contact by id ([] when absent)"},{"name":"created_after","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"{ ok, contacts: Contact[] }"}}},"post":{"summary":"Create or update a contact (upsert by email)","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpsert"}}}},"responses":{"200":{"description":"{ ok, contact_id, created, events }"}}}},"/api/agent/contacts/{id}":{"get":{"summary":"Contact detail + recent activity","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok, contact, activities, upcoming_events }"}}},"patch":{"summary":"Update contact fields (stage, lifecycle, tags, phone, names, do_not_contact)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pipeline_stage":{"type":"string","description":"Stage name (case-insensitive) from GET /api/agent/pipeline-stages"},"stage_id":{"type":"string","format":"uuid","description":"Alternative: stage id from GET /api/agent/pipeline-stages (wins over pipeline_stage)"}},"additionalProperties":true}}}},"responses":{"200":{"description":"{ ok, contact }"}}}},"/api/agent/contacts/{id}/notes":{"post":{"summary":"Add a note to the contact timeline","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string"}}}}}},"responses":{"200":{"description":"{ ok, note }"}}}},"/api/agent/contacts/{id}/email":{"post":{"summary":"Send an email to the contact (merge fields render; DNC + suppression enforced)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subject","body"],"properties":{"subject":{"type":"string"},"body":{"type":"string","description":"Plain-text body"},"cc":{"type":"string"},"bcc":{"type":"string"}}}}}},"responses":{"200":{"description":"{ ok, sent, status }"}}}},"/api/agent/contacts/tags":{"get":{"summary":"Distinct tags used in the project (Zapier Tag dropdowns)","responses":{"200":{"description":"{ ok, tags: string[] }"}}},"post":{"summary":"Add tags to a contact (merge; locate by contact_id or email)","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"contact_id":{"type":"string"},"email":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"{ ok, contact_id, tags, added }"}}},"delete":{"summary":"Remove tags from a contact (case-insensitive; locate by contact_id or email)","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"contact_id":{"type":"string"},"email":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"{ ok, contact_id, tags, removed }"}}}},"/api/agent/contacts/custom-fields":{"get":{"summary":"Custom contact field keys in use in the project (read-only)","responses":{"200":{"description":"{ ok, fields: [{ key, count, type }] }"}}}},"/api/agent/leads":{"get":{"summary":"Lead search with CRM filters (q, stage, lifecycle, has_phone)","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"stage","in":"query","schema":{"type":"string"}},{"name":"lifecycle","in":"query","schema":{"type":"string"}},{"name":"has_phone","in":"query","schema":{"type":"string","enum":["true"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"{ ok, leads, total }"}}}},"/api/agent/automations":{"get":{"summary":"List the project automations (id, name, status)","responses":{"200":{"description":"{ ok, automations }"}}}},"/api/agent/enroll":{"post":{"summary":"Enroll a contact in an automation","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"automation_id":{"type":"string"},"automation_name":{"type":"string","description":"Alternative: case-insensitive name match"},"contact_id":{"type":"string"},"email":{"type":"string","description":"Alternative: locate the contact by email"}}}}}},"responses":{"200":{"description":"enrollment result"}}},"delete":{"summary":"Unenroll a contact: cancel its live enrollment in an automation and stop the run (idempotent)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"automation_id":{"type":"string"},"automation_name":{"type":"string","description":"Alternative: case-insensitive name match"},"contact_id":{"type":"string"},"email":{"type":"string","description":"Alternative: locate the contact by email"}}}}}},"responses":{"200":{"description":"{ ok, contact_id, automation_id, cancelled, status: cancelled|not_enrolled }"}}}},"/api/agent/pipeline-stages":{"get":{"summary":"Pipeline stage names in board order","responses":{"200":{"description":"{ ok, stages }"}}}},"/api/agent/appointments":{"get":{"summary":"Upcoming appointments (optionally ?from=&to=; contact_id/email narrow to one contact)","parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"contact_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"email","in":"query","schema":{"type":"string"},"description":"Contact email (resolved inside the project)"},{"name":"include_past","in":"query","schema":{"type":"string","enum":["true"]},"description":"Allow a past from (no lower bound without one) and include completed / no-show meetings"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"{ ok, appointments }"}}},"post":{"summary":"Create a CRM appointment (no Google event, no email) — BG-00083","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["title","scheduled_at"],"properties":{"title":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time","description":"ISO 8601 with an offset"},"duration_minutes":{"type":"integer","minimum":5,"maximum":480,"default":30},"type":{"type":"string","enum":["appointment","call","meeting"]},"contact_id":{"type":"string","format":"uuid"},"email":{"type":"string","description":"Contact email (resolved inside the project)"},"notes":{"type":"string"},"location":{"type":"string"},"meeting_url":{"type":"string"}}}}}},"responses":{"201":{"description":"{ ok, appointment }"},"404":{"description":"contact_not_found"}}}},"/api/agent/appointments/{id}/reschedule":{"post":{"summary":"Move a CRM appointment; Google-synced or scheduling-link bookings answer 409 manage_in_app","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["scheduled_at"],"properties":{"scheduled_at":{"type":"string","format":"date-time"},"duration_minutes":{"type":"integer","minimum":5,"maximum":480}}}}}},"responses":{"200":{"description":"{ ok, appointment }"},"404":{"description":"not_found"},"409":{"description":"manage_in_app | already_cancelled | not_upcoming"}}}},"/api/agent/appointments/{id}/cancel":{"post":{"summary":"Cancel a CRM appointment; Google-synced or scheduling-link bookings answer 409 manage_in_app","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"{ ok, appointment }"},"404":{"description":"not_found"},"409":{"description":"manage_in_app | already_cancelled"}}}},"/api/agent/pipeline":{"get":{"summary":"Pipeline stages in board order with a contact count each","responses":{"200":{"description":"{ ok, stages, unstaged_count, total_contacts, truncated }"}}}},"/api/agent/campaigns":{"get":{"summary":"Email campaigns with send stats (read-only)","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","sending","sent","paused"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"{ ok, campaigns }"}}}},"/api/agent/automations/{id}":{"get":{"summary":"One automation (trigger + steps)","responses":{"200":{"description":"{ ok, automation }"},"404":{"description":"not_found"}}}},"/api/agent/content-calendar":{"get":{"summary":"Content Calendar items in a window (plan items, blog posts, podcast episodes, clips)","parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"{ ok, items }"}}}},"/api/agent/media-assets":{"get":{"summary":"Media Assets library metadata (no file URLs)","parameters":[{"name":"kind","in":"query","schema":{"type":"string","enum":["image","audio","video","document"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"{ ok, assets }"}}}},"/api/agent/dial/calls":{"get":{"summary":"Mighty Dial call log (no recordings or transcripts)","parameters":[{"name":"direction","in":"query","schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"contact_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"{ ok, calls }"}}}},"/api/agent/booking-links":{"post":{"summary":"Mint a one-off booking link, optionally bound to a contact","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"contact_id":{"type":"string"},"title":{"type":"string"},"duration_minutes":{"type":"integer","enum":[15,30],"default":15},"expires_in_days":{"type":"integer","default":14,"description":"0 = never"},"extra_attendees":{"type":"string","description":"Comma-separated emails invited to every booking"}}}}}},"responses":{"201":{"description":"{ ok, url, slug, link_id }"}}}},"/api/agent/events":{"get":{"summary":"Event feed — newest first (Zapier trigger samples / polling)","parameters":[{"name":"type","in":"query","schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"maximum":100}}],"responses":{"200":{"description":"{ ok, events: AgentEvent[] }"}}}},"/api/agent/hooks":{"get":{"summary":"List REST-hook subscriptions","responses":{"200":{"description":"{ ok, subscriptions }"}}},"post":{"summary":"Subscribe a target URL to an event type (Zapier REST-hook subscribe)","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["event_type","target_url"],"properties":{"event_type":{"type":"string","description":"An event type or * for all"},"target_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"{ ok, id, event_type, target_url }"}}}},"/api/agent/hooks/{id}":{"delete":{"summary":"Unsubscribe a REST hook (idempotent — Zapier unsubscribe)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok: true }"}}}},"/api/agent/files":{"post":{"summary":"Import a remote file (https URL) into Media Assets. Allowed types: image/*, audio/*, video/*, application/pdf. Max 10 MB.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"name":{"type":"string"},"contact_id":{"type":"string","description":"Optional — attaches a note to this contact"}}}}}},"responses":{"200":{"description":"{ ok, asset, url }"}}}},"/api/agent/credits":{"get":{"summary":"MightyAI credit balance + recent ledger entries","responses":{"200":{"description":"{ ok, balance_micros, balance_usd, lifetime_*_usd, recent_transactions }"}}}},"/api/agent/grok/transcripts":{"post":{"summary":"Grok Boost: store a transcript for the audio pipeline","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"title":{"type":"string"},"text":{"type":"string"}}}}}},"responses":{"200":{"description":"{ ok, transcript_id, transcript }"}}}},"/api/agent/grok/audio":{"post":{"summary":"Grok Boost: create + approve a podcast job and start ElevenLabs generation in the background. One source required: transcript_id | text | turns.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"transcript_id":{"type":"string","format":"uuid"},"text":{"type":"string"},"title":{"type":"string"},"turns":{"type":"array","items":{"type":"object"},"description":"[{speaker:\"HOST\"|\"NATALIE\", text}]"},"with_natalie":{"type":"boolean"}}}}}},"responses":{"200":{"description":"{ ok, job_id, run_id, status, credits_estimate }"}}}},"/api/agent/grok/stitch":{"post":{"summary":"Grok Boost: poll a podcast job status; once chunks exist, re-stitch with intro/outro bookends and return the audio path","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string","format":"uuid"},"intro_path":{"type":"string"},"outro_path":{"type":"string"}}}}}},"responses":{"200":{"description":"{ ok, stitched, status, audio_path, episode_id, normalized }"}}}},"/api/agent/grok/video":{"post":{"summary":"Grok Boost: start a video render via the connector registry (default hyperframes). Optional narration via audio_job_id or audio_path; renders in the background.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["brief"],"properties":{"brief":{"type":"string"},"style":{"type":"string"},"connector":{"type":"string","description":"Provider id — default \"hyperframes\""},"audio_job_id":{"type":"string","format":"uuid"},"audio_path":{"type":"string"},"transcript_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"{ ok, render_id, run_id, status, connector }"}}}},"/api/agent/grok/renders/{id}":{"get":{"summary":"Grok Boost: video render status — row + signed URL when done","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok, render, url }"}}}},"/api/agent/grok/youtube":{"post":{"summary":"Grok Boost: publish a finished render to the connected YouTube channel. Real outbound publish; visibility defaults private.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"render_id":{"type":"string","format":"uuid"},"video_path":{"type":"string"},"description":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"visibility":{"type":"string","enum":["private","unlisted","public"]}}}}}},"responses":{"200":{"description":"{ ok, video_id, url }"}}}},"/api/agent/grok/pipeline":{"post":{"summary":"Grok Boost: orchestrated run — transcript → audio → video → optional YouTube publish. Returns a run_id; stages advance in the background.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["brief"],"properties":{"transcript_id":{"type":"string","format":"uuid"},"text":{"type":"string"},"turns":{"type":"array","items":{"type":"object"}},"title":{"type":"string"},"with_natalie":{"type":"boolean"},"brief":{"type":"string"},"style":{"type":"string"},"publish":{"type":"object","description":"{title, description?, tags?, visibility?}"}}}}}},"responses":{"200":{"description":"{ ok, run_id, status, step }"}}}},"/api/agent/openapi.json":{"get":{"summary":"This document","responses":{"200":{"description":"OpenAPI 3 spec"}}}}}}