SolarDialer

Lead API

Send leads straight into your SolarDialer account, and into a list, from your website form, your CRM or your lead seller. One HTTPS request per lead.

Your API key

On your Account page, under API, press Create API key. The key starts with sdk_ and is shown once: copy it then. Keep it secret, like a password: anyone with it can add leads to your account. Replace key gives a new one and stops the old one at once; Turn off stops it.

Each account has its own key, and a key only ever adds leads to its own account.

Send a lead

POST https://solardialer.net/api/v1/leads
Authorization: Bearer sdk_your_key
Content-Type: application/json

{
  "first_name": "Dana",
  "last_name": "Rivera",
  "phone": "215-555-0147",
  "state": "PA",
  "zip": "19103",
  "list": "Website leads"
}

The key can also be sent as X-API-Key: sdk_your_key, and the fields as an ordinary form (application/x-www-form-urlencoded) instead of JSON.

Fields

The same columns as the CSV upload's template, so a lead sent here is checked exactly like an uploaded one. Required: first_name, phone, and for a US number state.

FieldWhat it is
first_name requiredThe lead's first name: the agent asks for them by it.
phone requiredTheir phone number. US numbers in any common form (215-555-0147, (215) 555-0147); other countries with the + code (+44 20 7946 0958).
lead_idYour own id for the lead. Send the same id again to update the lead. Without it, the phone number identifies the lead.
middle_name, last_nameThe rest of their name.
state required for US numbersTheir US state, two letters (PA): it decides the calling hours and rules that apply.
zip, city, addressWhere they live.
countryTwo letters (US, GB…), when the number alone doesn't say.
second_phone, third_phoneOther numbers for them. Calls ring phone first; when nobody answers, the next call rings the second number, then the third. Once one reaches them, that one is called from then on. A number given twice is kept once.
utility, source, notesTheir electric company, where the lead came from, anything else.
best_time_to_callIn words (evenings); or best_call_start and best_call_end as times (17:00, 20:00), in their own time.
say_nameHow to say their name, if it's unusual (Shivon for Siobhan).
consent_captured_at, consent_source_url, consent_ip, consent_user_agent, consent_disclosure_text, consent_vendor, consent_proof_refThe record of their consent to be called: when, on which page, from which address, what they agreed to, and your proof (e.g. a TrustedForm or Jornaya id). Send them when you have them.
listThe name of one of your lists to add the lead to. A new name makes the list.

Other fields are ignored.

Answers

CodeMeaning
201A new lead was added. If part of it was left out, warnings says what (e.g. a consent_ip that isn't an IP address: the lead is added without its consent record).
200The lead was already in your account (same lead_id, or the same phone without one): it was updated.
400The lead was refused; errors says why (e.g. a missing first name or state, a number that can't be a phone).
401No API key, or not a valid one.
403The account is suspended.
429More than 1000 leads in an hour: try again later.
{"ok": true, "id": "u3-W1047", "lead_id": "W1047", "created": true, "list": "Website leads"}

{"ok": false, "errors": ["missing required field: first_name"]}

Examples

curl

curl https://solardialer.net/api/v1/leads \
  -H "Authorization: Bearer sdk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"first_name": "Dana", "phone": "215-555-0147", "state": "PA", "list": "Website leads"}'

JavaScript (your server)

const answer = await fetch("https://solardialer.net/api/v1/leads", {
  method: "POST",
  headers: {"Authorization": "Bearer " + process.env.SOLARDIALER_KEY,
            "Content-Type": "application/json"},
  body: JSON.stringify({first_name: "Dana", phone: "215-555-0147", state: "PA"}),
});
console.log(answer.status, await answer.json());

Python

import os, requests

answer = requests.post(
    "https://solardialer.net/api/v1/leads",
    headers={"Authorization": "Bearer " + os.environ["SOLARDIALER_KEY"]},
    json={"first_name": "Dana", "phone": "215-555-0147", "state": "PA"},
)
print(answer.status_code, answer.json())

PHP

<?php
$lead = ["first_name" => "Dana", "phone" => "215-555-0147", "state" => "PA"];
$curl = curl_init("https://solardialer.net/api/v1/leads");
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("SOLARDIALER_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode($lead),
    CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_RESPONSE_CODE), " ", $body, "\n";
curl_close($curl);

Java (11 or later)

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class SendLead {
    public static void main(String[] args) throws Exception {
        String lead = "{\"first_name\": \"Dana\", \"phone\": \"215-555-0147\", \"state\": \"PA\"}";
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://solardialer.net/api/v1/leads"))
            .header("Authorization", "Bearer " + System.getenv("SOLARDIALER_KEY"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(lead))
            .build();
        HttpResponse<String> answer = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(answer.statusCode() + " " + answer.body());
    }
}

C# (.NET 6 or later)

using System.Net.Http.Headers;
using System.Net.Http.Json;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("SOLARDIALER_KEY"));

var lead = new { first_name = "Dana", phone = "215-555-0147", state = "PA" };
var answer = await client.PostAsJsonAsync("https://solardialer.net/api/v1/leads", lead);
Console.WriteLine($"{(int)answer.StatusCode} {await answer.Content.ReadAsStringAsync()}");

Each example reads the key from the SOLARDIALER_KEY environment variable, so it never sits in your code.

Send leads from your server, never from code in a web page: a key in a page's code can be read by anyone who opens it.

Good to know

Call a lead now

Send a new lead (from your web form, Facebook lead ads or a lead seller) and the agent calls it right away, as the Call button would:

POST https://solardialer.net/api/v1/calls
Authorization: Bearer YOUR_KEY
Content-Type: application/json

{"first_name": "Dana", "phone": "215-555-0147", "state": "PA", "list": "Web leads"}

The same fields as Send a lead: the lead is added (or updated), then called. The answer is the lead's, plus called (true or false), call_id and, when it was not called, reason: outside its calling hours, called too recently, on the do-not-call list... The lead stays on its list, so a running campaign on that list calls it when it can. A problem your account must fix first (the agent's script not checked yet, no calls left) answers 409 with what to do. Up to 300 calls an hour.

A call's recording

GET https://solardialer.net/api/v1/calls/{call_id}/recording
Authorization: Bearer YOUR_KEY

The audio file itself (MP3 or WAV), for any of your calls: the call_id and recording_url in every call event point here. A call that isn't yours, or has no recording, answers 404. Up to 600 an hour. In Zapier, the call triggers give it as a file a step can save to Drive or attach to a CRM record.

Find a lead

GET https://solardialer.net/api/v1/leads?phone=2155550147
GET https://solardialer.net/api/v1/leads?lead_id=W1047
Authorization: Bearer YOUR_KEY

A list with the lead (its lead fields below, plus status and url), or [] when you have none with that number (any of its three) or id.

Events and hooks

What happens on your calls, for Zapier, your CRM or your own server. Each event is JSON with its id, event, created_at and the fields below.

EventWhenFields
call.endedEvery call, when it endscall_id, outcome (talked, voicemail, transferred, transfer_failed, no_answer...), ended_reason, started_at, seconds, campaign_id, campaign, disposition, call_url (the call's page), recording_url (the audio, with your key), transcript, summary (a line about the call, when there is one), answers (what the lead answered: homeowner, monthly_bill, roof...), summary (an AI summary of the call in 2-3 sentences), objections (the concerns they raised, short tags such as "too expensive"), interest (1 to 5; these three only when the call reached a person), lead
call.transferredA transfer to your closer connectedAs call.ended
lead.interestedThe lead said yes to your closer: the transfer connected, did not connect, or your closer's callback was booked insteadAs call.ended
callback.bookedThe agent booked a callbackat, when_text (their words), note, set_by, caller (closer: your advisor calls them; agent: the agent calls them again), lead
lead.status_changedYou gave a lead a statusold, new, lead
lead.removedA number went on the do-not-call listcall_id, lead
lead.createdA lead was added to your account (uploaded, typed in, sent by the API or given on a call); an update of a lead you have sends nonelead, list (its list's name, or null), source (upload, form, dial, api, call, import)
campaign.finishedA campaign is done with every lead, or was stopped campaign_id, campaign, how (done or stopped), leads, calls, talked (conversations, transfers included), transferred, appointments, finished_at

lead is {"lead_id", "first_name", "last_name", "phone", "phones", "email", "state", "source_id"}; source_id is the id the lead came in with.

Read them

GET https://solardialer.net/api/v1/events?event=call.ended&limit=25
Authorization: Bearer YOUR_KEY

Newest first, up to 100. Leave out event for every kind.

Have them sent to you (hooks)

POST https://solardialer.net/api/v1/hooks
Authorization: Bearer YOUR_KEY
Content-Type: application/json

{"event": "call.ended", "target_url": "https://example.com/solardialer"}

Answers 201 with the hook's id and secret. From then on each event of that kind is POSTed to your URL (https only), in order, within a minute or so, with the header X-SolarDialer-Signature: sha256=<HMAC-SHA256 of the body with the secret, in hex>. Answer with any 2xx. Anything else is tried again after 1, 5 and 30 minutes, 2 and 12 hours, then the hook stops (your Integrations page shows it); a 410 removes it.

DELETE https://solardialer.net/api/v1/hooks/{id}
Authorization: Bearer YOUR_KEY

Lists, campaigns, account

Every request needs your key. A missing or wrong key gets 401.