CampaignFlow Client

View Source

An Elixir client library for the Campaign Flow API, built with the Req HTTP client.

⚠️ AI Generated! ⚠️

Full disclosure, this repo was almost completely generated by Claude Code. Use at your own risk.

Features

  • OAuth2 client credentials authentication
  • Automatic token management and refresh
  • Full API coverage for all Campaign Flow endpoints
  • Type-safe function signatures with @spec
  • Comprehensive error handling
  • Support for both production and test environments
  • Configurable via application config or runtime options

Installation

Add campaign_flow to your list of dependencies in mix.exs:

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

Configuration

Application Config

Configure the client in your config/config.exs:

config :campaign_flow,
  client_id: System.get_env("CAMPAIGNFLOW_CLIENT_ID"),
  client_secret: System.get_env("CAMPAIGNFLOW_CLIENT_SECRET")

Environment Selection

Use the environment option to select between production and test APIs:

# Production (default) - uses https://app.campaignflow.com.au/api/v2
config :campaign_flow,
  environment: :prod,
  client_id: "your_client_id",
  client_secret: "your_client_secret"

# Test - uses https://test.campaignflow.com.au/api/v2
config :campaign_flow,
  environment: :test,
  client_id: "your_client_id",
  client_secret: "your_client_secret"

You can also override with a custom base_url if needed:

config :campaign_flow,
  base_url: "https://custom.example.com/api/v2",
  client_id: "your_client_id",
  client_secret: "your_client_secret"

Runtime Config

For production, use config/runtime.exs:

import Config

if config_env() == :prod do
  config :campaign_flow,
    environment: :prod,
    client_id: System.get_env("CAMPAIGNFLOW_CLIENT_ID"),
    client_secret: System.get_env("CAMPAIGNFLOW_CLIENT_SECRET")
end

Environment Variables

Set the following environment variables:

export CAMPAIGNFLOW_CLIENT_ID="your_client_id"
export CAMPAIGNFLOW_CLIENT_SECRET="your_client_secret"

Usage

Creating a Client

# Using application config (environment determined by config)
client = CampaignFlow.Client.new()

# Pass credentials directly (defaults to production)
client = CampaignFlow.Client.new(
  client_id: "your_client_id",
  client_secret: "your_client_secret"
)

# Specify test environment
client = CampaignFlow.Client.new(
  client_id: "your_client_id",
  client_secret: "your_client_secret",
  environment: :test
)

# Or use the convenience function for test environment
client = CampaignFlow.Client.test(
  client_id: "your_client_id",
  client_secret: "your_client_secret"
)

Campaigns

# List campaigns
{{:ok, campaigns}, client} = CampaignFlow.Client.Campaigns.list(client)

# Get a specific campaign
{{:ok, campaign}, client} = CampaignFlow.Client.Campaigns.get(client, 123)

# Create a new campaign
{{:ok, campaign}, client} = CampaignFlow.Client.Campaigns.create(client, %{
  name: "Summer Campaign 2024",
  agency_id: 1,
  property_id: 2
})

# Update a campaign
{{:ok, campaign}, client} = CampaignFlow.Client.Campaigns.update(client, 123, %{
  name: "Updated Campaign Name"
})

# Add a comment to a campaign
{{:ok, response}, client} = CampaignFlow.Client.Campaigns.add_comment(client, 123, %{
  comment: "Campaign approved by client"
})

# Set campaign status
{{:ok, response}, client} = CampaignFlow.Client.Campaigns.set_status(client, 123, %{
  status: "approved"
})

# Send approved email
{{:ok, response}, client} = CampaignFlow.Client.Campaigns.send_approved_email(client, 123)

Campaign Vendors

# List campaign vendors
{{:ok, vendors}, client} = CampaignFlow.Client.Campaigns.list_vendors(client, 123)

# Get a specific vendor
{{:ok, vendor}, client} = CampaignFlow.Client.Campaigns.get_vendor(client, 123, 456)

# Add a vendor to a campaign
{{:ok, vendor}, client} = CampaignFlow.Client.Campaigns.add_vendor(client, 123, %{
  vendor_id: 456
})

# Update a campaign vendor
{{:ok, vendor}, client} = CampaignFlow.Client.Campaigns.update_vendor(client, 123, 456, %{
  status: "approved"
})

# Remove a vendor from a campaign
{{:ok, response}, client} = CampaignFlow.Client.Campaigns.remove_vendor(client, 123, 456)

# Send campaign to vendor
{{:ok, response}, client} = CampaignFlow.Client.Campaigns.send_campaign_to_vendor(client, 123, 456)

# Verify vendor contact
{{:ok, response}, client} = CampaignFlow.Client.Campaigns.verify_vendor_contact(client, 123, 456)

Agencies

# List agencies
{{:ok, agencies}, client} = CampaignFlow.Client.Agencies.list(client)

# Get a specific agency
{{:ok, agency}, client} = CampaignFlow.Client.Agencies.get(client, 123)

Invoices

# List invoices
{{:ok, invoices}, client} = CampaignFlow.Client.Invoices.list(client)

# Get a specific invoice
{{:ok, invoice}, client} = CampaignFlow.Client.Invoices.get(client, 123)

# Create an invoice
{{:ok, invoice}, client} = CampaignFlow.Client.Invoices.create(client, %{
  campaign_id: 123,
  amount: 1000.00
})

# Update an invoice
{{:ok, invoice}, client} = CampaignFlow.Client.Invoices.update(client, 123, %{
  amount: 1200.00
})

Campaign Budgets

# List campaign budgets
{{:ok, budgets}, client} = CampaignFlow.Client.CampaignBudgets.list(client)

# Get a specific budget
{{:ok, budget}, client} = CampaignFlow.Client.CampaignBudgets.get(client, 123)

# Create a campaign budget
{{:ok, budget}, client} = CampaignFlow.Client.CampaignBudgets.create(client, %{
  campaign_id: 123,
  amount: 10000.00
})

# Update a campaign budget
{{:ok, budget}, client} = CampaignFlow.Client.CampaignBudgets.update(client, 123, %{
  amount: 12000.00
})

# List finance options
{{:ok, options}, client} = CampaignFlow.Client.CampaignBudgets.list_finance_options(client, 123)

# Get a finance quote
{{:ok, quote}, client} = CampaignFlow.Client.CampaignBudgets.get_finance_quote(client, 123, "OPTION_CODE")

Finance Applications

# List finance applications
{{:ok, applications}, client} = CampaignFlow.Client.FinanceApplications.list(client)

# Get a specific application
{{:ok, application}, client} = CampaignFlow.Client.FinanceApplications.get(client, 123)

# Set application status
{{:ok, response}, client} = CampaignFlow.Client.FinanceApplications.set_status(client, 123, %{
  status: "approved"
})

# Submit an application
{{:ok, response}, client} = CampaignFlow.Client.FinanceApplications.submit(client, 123)

Users, Tenants, Properties

# Users
{{:ok, users}, client} = CampaignFlow.Client.Users.list(client)
{{:ok, user}, client} = CampaignFlow.Client.Users.get(client, 123)

# Tenants
{{:ok, tenants}, client} = CampaignFlow.Client.Tenants.list(client)
{{:ok, tenant}, client} = CampaignFlow.Client.Tenants.get(client, 123)

# Properties
{{:ok, properties}, client} = CampaignFlow.Client.Properties.list(client)
{{:ok, property}, client} = CampaignFlow.Client.Properties.get(client, 123)

Error Handling

The client returns tuples with {:ok, result} or {:error, reason}:

case CampaignFlow.Client.Campaigns.get(client, 123) do
  {{:ok, campaign}, updated_client} ->
    # Process campaign
    IO.inspect(campaign)
    updated_client

  {{:error, :not_found}, client} ->
    # Handle not found
    IO.puts("Campaign not found")
    client

  {{:error, :unauthorized}, client} ->
    # Handle authentication error
    IO.puts("Authentication failed")
    client

  {{:error, {:validation_error, details}}, client} ->
    # Handle validation errors
    IO.inspect(details)
    client

  {{:error, reason}, client} ->
    # Handle other errors
    IO.inspect(reason)
    client
end

Pagination

Most list endpoints support pagination:

# Get page 2 with 50 items per page
{{:ok, campaigns}, client} = CampaignFlow.Client.Campaigns.list(client,
  page: 2,
  per_page: 50
)

Authentication

The client automatically handles OAuth2 authentication using the client credentials flow:

  1. When you make your first API request, the client automatically obtains an access token
  2. The token is cached and reused for subsequent requests
  3. When the token expires, a new one is automatically obtained

You don't need to manually manage authentication - it's handled transparently.

Client State Management

Note that the client struct is updated with each request to maintain the current access token. You should use the updated client returned from each function call:

# Initial client
client = CampaignFlow.Client.new(client_id: "...", client_secret: "...")

# Client is updated after each request
{{:ok, campaigns}, client} = CampaignFlow.Client.Campaigns.list(client)
{{:ok, campaign}, client} = CampaignFlow.Client.Campaigns.get(client, 123)

# Use the updated client for the next request
{{:ok, agencies}, client} = CampaignFlow.Client.Agencies.list(client)

Available Resources

The following resource modules are available:

Development

# Get dependencies
mix deps.get

# Run tests
mix test

# Generate documentation
mix docs

# Format code
mix format

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.