Skip to content

agoodway/goodleads_ex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoodleadsEx

Elixir client for the GoodLeads API. Generated at compile time from the OpenAPI specification.

Installation

Add goodleads_ex to your dependencies in mix.exs:

def deps do
  [
    {:goodleads_ex, "~> 0.1.0"}
  ]
end

Configuration

Application config

# config/config.exs
config :goodleads_ex,
  base_url: "http://localhost:4000",
  api_key: "your-api-key"

Runtime / per-request

client = GoodleadsEx.client(
  base_url: "http://localhost:4000",
  api_key: "sk_your_secret_key"
)

You can also pass req_options to customize the underlying Req HTTP client:

client = GoodleadsEx.client(
  api_key: "sk_...",
  req_options: [receive_timeout: 30_000]
)

Usage

Every function takes a %GoodleadsEx.Client{} as the first argument, followed by path parameters, and returns {:ok, struct} or {:error, reason}.

client = GoodleadsEx.client(api_key: "sk_...")
account = "my-account"

Leads

# List all leads for an account
{:ok, %{data: leads, meta: %{"total_count" => count}}} =
  GoodleadsEx.list_leads(client, account)

# Create a lead — returns an id and a JWT token for lead-scoped operations
{:ok, %{id: lead_id, token: jwt}} =
  GoodleadsEx.create_lead(client, account, %{
    first_name: "Jane",
    last_name: "Doe",
    email: "jane@example.com",
    phone: "+15551234567",
    city: "Denver",
    state: "CO",
    zip: "80202",
    data: %{service_type: "hvac_install", sqft: 2400},
    metadata: %{utm_source: "google", fbclid: "abc123"},
    campaign_id: "campaign-uuid",
    questionnaire_id: "questionnaire-uuid"
  })

# Update a lead
{:ok, %{id: ^lead_id, first_name: "Janet"}} =
  GoodleadsEx.update_lead(client, account, lead_id, %{
    first_name: "Janet",
    data: %{service_type: "hvac_repair"}
  })

# Phone verification flow
{:ok, %{message: "Verification code sent"}} =
  GoodleadsEx.verify_lead_phone(client, account, lead_id)

{:ok, %{phone_verified: true}} =
  GoodleadsEx.confirm_lead_phone(client, account, lead_id, %{code: "123456"})

# Qualify a lead — triggers distribution and returns buyer match if found
{:ok, %{lead: qualified_lead, buyer: buyer}} =
  GoodleadsEx.qualify_lead(client, account, lead_id)

# buyer is a %BuyerData{company_id: "...", company_name: "..."} or nil

# Export leads as CSV
:ok = GoodleadsEx.export_leads(client, account)

Companies

# List companies
{:ok, %{data: companies}} = GoodleadsEx.list_companies(client, account)

# Create a company
{:ok, company} =
  GoodleadsEx.create_company(client, account, %{
    name: "ACME HVAC Services",
    email: "info@acmehvac.com",
    phone: "+15559876543",
    status: "active"
  })

company.id   #=> "550e8400-..."
company.name #=> "ACME HVAC Services"

# Get / update / delete
{:ok, company} = GoodleadsEx.get_company(client, account, company.id)

{:ok, updated} =
  GoodleadsEx.update_company(client, account, company.id, %{
    name: "ACME HVAC Pro"
  })

:ok = GoodleadsEx.delete_company(client, account, company.id)

# Export leads for a specific company
:ok = GoodleadsEx.export_company_leads(client, account, company.id)

Orders

# List orders for a company
{:ok, %{data: orders}} = GoodleadsEx.list_orders(client, account, company_id)

# Create an order with lead-matching criteria
{:ok, order} =
  GoodleadsEx.create_order(client, account, company_id, %{
    quantity: 10,
    criteria: "service_type == 'hvac_install'"
  })

order.status           #=> "active"
order.quantity         #=> 10
order.distributed_count #=> 0

# Get / update an order
{:ok, order} = GoodleadsEx.get_order(client, account, company_id, order.id)

{:ok, order} =
  GoodleadsEx.update_order(client, account, company_id, order.id, %{
    quantity: 20
  })

# Pause and reactivate
{:ok, %{status: "paused"}} =
  GoodleadsEx.pause_order(client, account, company_id, order.id)

{:ok, %{status: "active"}} =
  GoodleadsEx.activate_order(client, account, company_id, order.id)

Campaigns

# List campaigns
{:ok, %{data: campaigns}} = GoodleadsEx.list_campaigns(client, account)

# Create a campaign
{:ok, campaign} =
  GoodleadsEx.create_campaign(client, account, %{
    name: "Summer HVAC Push",
    slug: "summer-hvac",
    description: "Summer 2026 lead gen campaign",
    status: "active"
  })

campaign.slug       #=> "summer-hvac"
campaign.lead_count #=> 0

# Get / update by slug
{:ok, campaign} = GoodleadsEx.get_campaign(client, account, "summer-hvac")

{:ok, campaign} =
  GoodleadsEx.update_campaign(client, account, "summer-hvac", %{
    description: "Updated description"
  })

Questionnaires

# List questionnaires
{:ok, %{data: questionnaires}} = GoodleadsEx.list_questionnaires(client, account)

# Create a questionnaire
{:ok, questionnaire} =
  GoodleadsEx.create_questionnaire(client, account, %{
    name: "HVAC Service Form",
    slug: "hvac-service",
    questions: [%{type: "text", label: "What service do you need?"}]
  })

# Get / update by slug
{:ok, q} = GoodleadsEx.get_questionnaire(client, account, "hvac-service")

{:ok, q} =
  GoodleadsEx.update_questionnaire(client, account, "hvac-service", %{
    name: "Updated Form Name"
  })

# Get a questionnaire via its campaign
{:ok, q} = GoodleadsEx.get_campaign_questionnaire(client, account, "summer-hvac", "hvac-service")

# Get the questionnaire JSON schema
{:ok, _schema} = GoodleadsEx.get_questionnaire_schema(client)

Distributions

# List all distributions
{:ok, %{data: distributions}} = GoodleadsEx.list_distributions(client, account)

# Each distribution links a lead to an order
# distribution.lead => %Lead{}, distribution.order => %Order{}

# Get a single distribution
{:ok, dist} = GoodleadsEx.get_distribution(client, account, distribution_id)

# List leads that haven't been distributed yet
{:ok, %{data: undistributed}} = GoodleadsEx.list_undistributed_leads(client, account)

Sites and Landing Pages

# List sites
{:ok, %{data: sites}} = GoodleadsEx.list_sites(client, account)

# Get site config (colors, fonts, logos, analytics)
{:ok, site} = GoodleadsEx.get_site(client, account, "my-site")
site.site_name          #=> "Helpful Henry"
site.ga_measurement_id  #=> "G-XXXXXXXXXX"
site.colors             #=> %{"primary" => "#2563eb", ...}

# List / get landing pages
{:ok, %{data: pages}} = GoodleadsEx.list_landing_pages(client, account)
{:ok, page} = GoodleadsEx.get_landing_page(client, account, "free-quote")
page.campaign_slug      #=> "summer-hvac"
page.questionnaire_slug #=> "hvac-service"

Account Members

# List users
{:ok, %{data: members}} = GoodleadsEx.list_users(client, account)

# Create a user
{:ok, member} =
  GoodleadsEx.create_user(client, account, %{
    email: "technician@acmehvac.com",
    role: "member"
  })

# Get / update / delete
{:ok, member} = GoodleadsEx.get_user(client, account, member_id)

{:ok, member} =
  GoodleadsEx.update_user(client, account, member_id, %{role: "admin"})

:ok = GoodleadsEx.delete_user(client, account, member_id)

Error handling

API errors return {:error, %{status: integer, body: map}}:

case GoodleadsEx.create_lead(client, "my-account", params) do
  {:ok, result} ->
    # handle success

  {:error, %{status: 422, body: body}} ->
    # validation error

  {:error, %{status: 401}} ->
    # invalid API key

  {:error, %{status: 429}} ->
    # rate limited

  {:error, %Req.TransportError{reason: reason}} ->
    # connection error (:econnrefused, :timeout, etc.)
end

Response types

All responses are typed structs under GoodleadsEx.Schemas. Schemas are generated at compile time from openapi.json and recompile automatically when the spec changes.

Function Response struct
Leads
list_leads/2 ListLeadsResponse (data: [Lead], meta)
create_lead/3 CreateLeadResponse (id, token)
update_lead/4 UpdateLeadResponse (Lead fields)
qualify_lead/3 QualifyLeadResponse (lead, buyer)
verify_lead_phone/3 VerifyPhoneResponse (message)
confirm_lead_phone/4 ConfirmPhoneResponse (Lead fields)
export_leads/2 :ok
export_company_leads/3 :ok
list_undistributed_leads/2 UndistributedLeadListResponse (data: [Lead])
Companies
list_companies/2 CompanyListResponse (data: [Company])
create_company/3 CompanyResponse (Company fields)
get_company/3 CompanyResponse (Company fields)
update_company/4 CompanyResponse (Company fields)
delete_company/3 :ok
Orders
list_orders/3 OrderListResponse (data: [OrderSummary])
create_order/4 OrderResponse (Order fields)
get_order/4 OrderResponse (Order fields)
update_order/5 OrderResponse (Order fields)
activate_order/4 OrderResponse (Order fields)
pause_order/4 OrderResponse (Order fields)
Campaigns
list_campaigns/2 CampaignListResponse (data: [Campaign])
create_campaign/3 CampaignResponse (Campaign fields)
get_campaign/3 CampaignResponse (Campaign fields)
update_campaign/4 CampaignResponse (Campaign fields)
Questionnaires
list_questionnaires/2 ListQuestionnairesResponse (data: [Questionnaire])
create_questionnaire/3 QuestionnaireResponse (Questionnaire fields)
get_questionnaire/3 QuestionnaireResponse (Questionnaire fields)
update_questionnaire/4 QuestionnaireResponse (Questionnaire fields)
get_campaign_questionnaire/4 QuestionnaireResponse (Questionnaire fields)
get_questionnaire_schema/1 :ok
Distributions
list_distributions/2 DistributionListResponse (data: [Distribution])
get_distribution/3 DistributionResponse (Distribution fields)
Sites & Landing Pages
list_sites/2 SiteListResponse (data: [Site])
get_site/3 SiteResponse (site config fields)
list_landing_pages/2 LandingPageListResponse (data: [LandingPage])
get_landing_page/3 LandingPageResponse (landing page fields)
Account Members
list_users/2 AccountMemberListResponse (data: [AccountMember])
create_user/3 AccountMemberResponse (AccountMember fields)
get_user/3 AccountMemberResponse (AccountMember fields)
update_user/4 AccountMemberResponse (AccountMember fields)
delete_user/3 :ok

Testing

mix test

Regenerating

Replace openapi.json and recompile — structs update automatically.

License

See LICENSE for details.

About

An Elixir client for goodleads.dev

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages