Documentation

Table of contents

Getting started

A tutorial to get you started.

Notes about usage

It is recommended to gain a general understanding of HeroBase Outbound product before using this api.

The API is only accessible via HTTPS.

Client examples + libraries

In General

If the Accept header is not set the response content-type defaults to application/json.

Raw HTTP

On windows we recommend using Fiddler for making direct HTTP requests. There are also extension for Firefox and Chrome which provides similar functionality, Invoke-RestMethod for PowerShell v4 and of course cURL and wget for *nix.

Importing a lead:


POST https://{yoursubdomain}.herobase.com/api/leads HTTP/1.1
User-Agent: ExampleAgent
Content-Type: application/json
Accept: application/json
Host: {yoursubdomain}.herobase.com
Authorization: Basic dXNlckBjdXN0b21lci5jb206U29tZVBhc3N3b3Jk
{
    "CampaignCode": "ExampleCampaignCode",
    "data": {
        "FirstName": "James S. A.",
        "LastName": "Corey",
        "Phone": "7777777"
    }
}
            

Exporting leads:


GET https://{yoursubdomain}.herobase.com/api/simpleleads?Projects=*&ModifiedFrom={todaysdate}&Statuses=UserProcessed&LeadClosures=Success HTTP/1.1
User-Agent: ExampleAgent
Accept: application/json
Host: {yoursubdomain}.herobase.com
Authorization: Basic dXNlckBjdXN0b21lci5jb206U29tZVBhc3N3b3Jk
            

C#

Importing a lead:


static void Run()
{
    var client = new JsonServiceClient( "https://{yoursubdomain}.herobase.com/api/" );
    client.AlwaysSendBasicAuthHeader = true;
    client.UserName = "user@example.com";
    client.Password = "examplepassword";
    // client.Headers.Add( "X-Rate-Limit-Fair-Use-Policy", "Minute rated" );

    try {
        var lead = new Actimizer.LRM.Api.ServiceModel.ImportLead {
            CampaignCode = "ExampleCampaignCode",
            Data = new Dictionary<string, string> {
                { "FirstName", "Alastair" },
                { "LastName", "Reynolds" },
                { "Phone", "44444444" }
            }
        };
        Actimizer.LRM.Contracts.LeadImportResult result = client.Post( lead );
        // System.Threading.Thread.Sleep( 250 ); // For when X-Rate-Limit-Fair-Use-Policy is used
        if ( !res.Success ) {
            // Handle failure conditions
        }
    }
    catch( WebServiceException ex ) {
        // Handle errors
    }
}
            

Exporting leads:


static public void Run()
{
    var client = new JsonServiceClient( "https://{yoursubdomain}.herobase.com/api/" );
    client.AlwaysSendBasicAuthHeader = true;
    client.UserName = "user@example.com";
    client.Password = "examplepassword";

    try {
        var leads = client.Get( new Actimizer.LRM.Api.ServiceModel.ExportSimpleLeads {
            ModifiedFrom = DateTime.Today,
            Statuses = new [] { Actimizer.LRM.Contracts.LeadStatus.UserProcessed },
            LeadClosures = new [] { Actimizer.LRM.Contracts.LeadClosure.Success }
        } );
        foreach( var lead in leads ) {
            //Process leads
        }
    }
    catch( WebServiceException ex ) {
        // Handle error
    }
}
            

Downloads:

To compile the examples you should:

  1. Download all three zip files.
  2. Unzip and include all the .cs files in a new VS project.
  3. Add a reference to System.Runtime.Serialization
  4. Install the latest, major version 3, NuGet package ServiceStack.Common. Link to latest at time of writing: https://www.nuget.org/packages/ServiceStack.Common/3.9.71

Please note that this is example, not demo code. It will fail if you try to run it without changes.

VB.Net and other .Net languages

We do not have native examples for any .Net languages other than C# at the moment. We suggest that you follow the C# instructions and create a class library which can then be accessed from other .Net languages.

PHP

Importing a lead:


<?php
$lead = array(
    'CampaignCode' => 'ExampleCampaignCode',
    'Data' => array(
        'FirstName' => 'Ian M.',
        'LastName' => 'Banks',
        'Phone' => '55555555'
    )
);
$jsonlead = json_encode ( $lead );
$ch = curl_init( "https://{yoursubdomain}.herobase.com/api/leads" );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
curl_setopt( $ch, CURLOPT_USERPWD, "user@example.com:examplepassword" );
//curl_setopt( $ch, CURLOPT_HTTPHEADER, array ( "Content-Type: application/json; charset=utf-8", "X-Rate-Limit-Fair-Use-Policy: Minute rated" ) );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array ( "Content-Type: application/json; charset=utf-8" ) );
curl_setopt( $ch, CURLOPT_POST, 1 );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $jsonlead );
$output = curl_exec( $ch );
$errno = curl_errno( $ch );
// Handle errors
$output = json_decode( $output, true );
if ( !$output['success'] )
{
    // Handle failure conditions
}
curl_close($ch);
//usleep(250); // For when X-Rate-Limit-Fair-Use-Policy is used
?>
            

Exporting leads:


<?php
$ch = curl_init("https://{yoursubdomain}.herobase.com/api/simpleleads?Projects=*&ModifiedFrom={todaysdate}&Statuses=UserProcessed&LeadClosures=Success");
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
curl_setopt( $ch, CURLOPT_USERPWD, "user@example.com:examplepassword" );
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json"]);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
$output = curl_exec($ch);
$errno  = curl_errno($ch);
?>
            

Downloads:

Please note that this is example, not demo code. It will fail if you try to run it without changes.

Contact us if you need other examples.

Python

Importing a lead:


import requests
import json
url = 'https://{yoursubdomain}.herobase.com/api/leads'
lead = {
    'campaignCode': 'ExampleCampaignCode',
    'data': {
        'FirstName': 'Charles',
        'LastName': 'Stross',
        'Phone': , '6666666'
    }
}
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
# headers = {'Content-type': 'application/json', 'Accept': 'application/json', 'X-Rate-Limit-Fair-Use-Policy': 'Minute rated'}
                
res = requests.post(url, data=json.dumps(lead), headers=headers, auth=('user@example.com','examplepassword'))
if res.status_code == 200:
    res = res.json()
    if not(res['success']):
        pass # Handle validation errors
elif res.status_code == 400:
    res = res.json()
    # handle request errors
else:
    pass # Handle other erros
# time.sleep(0.25) # For when X-Rate-Limit-Fair-Use-Policy is used
			

Exporting leads:


import requests
url = 'https://{yoursubdomain}.herobase.com/api/simpleleads?Projects=*&ModifiedFrom={todaysdate}&Statuses=UserProcessed&LeadClosures=Success'
headers = {'Accept': 'application/json'}
res = requests.get( url, headers=headers, auth=('user@example.com','examplepassword'))
if res.status_code == 200:
    res = res.json()
else:
    pass # Handle other erros
			

Please note that requests is not in the standard library, but you can get it by running pip install requests.

PowerShell v4

Older versions of PowerShell doesn't support setting the Accept header, which is needed for content negotiation.

Importing a lead:


$leads = @( @{
    CampaignCode = 'ExampleCampaignCode';
    Data = @{
        FirstName = 'Peter F.';
        LastName = 'Hamilton';
        Phone = '33333333';
    }
} );
try {
    $leads | %{ $_ | ConvertTo-Json -Compress | `
    Invoke-RestMethod -Method Post `
        -ContentType application/json `
        -Uri https://{yoursubdomain}.herobase.com/api/leads `
        -Headers @{
            Authorization = "Basic $([Text.Encoding]::UTF8.GetBytes('user@example.com:examplepassword') | ConvertTo-Base64)";
            Accept = 'application/json';
            # 'X-Rate-Limit-Fair-Use-Policy' = 'Minute rated';
        } | %{
            if ( !$_.Success )
            {
                # Handle failure conditions
            }
        };
    # sleep -Milliseconds 250; # For when X-Rate-Limit-Fair-Use-Policy is used
    }
}
catch [Net.WebException]
{
    $resp = $_.Exception.Response;
    if ( $resp.StatusCode -eq [Net.HttpStatusCode]::BadRequest ) {
        $result = (New-Object IO.StreamReader($resp.GetResponseStream())).ReadToEnd() | ConvertFrom-Json;
        # Handle errors
    } else {
        # Handle errors
    }
}
            

Exporting leads:


Invoke-RestMethod -Method Get `
    -Uri "https://{yoursubdomain}.herobase.com/api/simpleleads?Projects=*&ModifiedFrom=$([datetime]::Today.ToString('yyyy-MM-dd'))&Statuses=UserProcessed&LeadClosures=Success"
    -Headers @{
        Authorization = "Basic $([Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('user@example.com:examplepassword')))";
        Accept = 'application/json'
} | %{
    # Process lead
    echo $_.uniqueId
}
            

or from saved searches


Invoke-RestMethod -Method Get `
    -Uri "https://{yoursubdomain}.herobase.com/api/leads?searchName=ExampleSearchName&modifiedFrom=$([datetime]::Today.ToString('yyyy-MM-dd'))" `
    -Headers @{
        Authorization = "Basic $([Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('user@example.com:examplepassword')))";
        Accept = 'application/json'
} | %{
    # Process lead
    echo $_.uniqueId
}
            

or as csv


Invoke-RestMethod -Method Get `
    -Uri "https://{yoursubdomain}.herobase.com/api/leads/csv?searchName=ExampleSearchName&modifiedFrom=$([datetime]::Today.ToString('yyyy-MM-dd'))" `
    -Headers @{
        Authorization = "Basic $([Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('user@example.com:examplepassword')))";
        Accept = 'application/json'
} -OutFile "path\to\somefilename.csv"
            

About authentication

Currently only Basic authentication is supported.

Basic authentication via Authorization header

Basic authentication is implemented as per the standard described here and here. This standard is supported by almost all clients and browsers, but is also relatively simple to implement if your client doesn't support it.

Example of request using the username: user@customer.com and password: SomePassword


GET https://{yoursubdomain}.herobase.com/api/users HTTP/1.1
User-Agent: ExampleAgent
Accept: application/json
Host: {yoursubdomain}.herobase.com
Authorization: Basic dXNlckBjdXN0b21lci5jb206U29tZVBhc3N3b3Jk
                

About access rights

Access rights for webservice accounts are controlled on three levels. Project rights, resource rights and lead definition entry access.

Project rights

The project rights consists of a list of simple wildcard patterns, controlling which projects this account has access to. Supported wildcard characters are *, which matches zero or more arbitrary characters, and ? which matches exactly one arbitrary character.

Having "B2B*" in the list of project rights would give access rights to any campaign in where the project name starts with B2B.

Resource rights

There are currently five resource types:
Account, Calls, Campaigns, Leads, Organization

For each resource type a webservice account can be granted one of more of the following method rights (verbs):
Get, Post, Put, Delete

Not all resource types support every method.

Some services may require a access to a different verb, than what it should be called with. See the individual services for details.

Lead definition entry access

Some services limits the output based on the LeadDefinitionEntryAccess property of your account.

There are three levels: None, Partner and Full

About the include query parameter

For some requests, complex properties are only returned when they are explicitly asked for by the requester.

Complex properties are usually properties that require additional database lookups, may be secondary to the actual object and/or takes up a lot of bandwidth.

To include these properties list them in the 'include' query parameter in a comma separated string or specify the 'include' parameter multiple times.

Ex.

?include=parent, children
or
?include=parent&include=children

Specified properties are not included if it leads to loops in the object graph or if the same object(s) would be included multiple times.

Property names of nested objects are valid, but only when all properties necessary to reach the nested property have been listed.

Ex.

GET /orgunits/{orgCode}?include=campaigns
is valid, but wont have any effect unless 'users' are listed as well:
GET /orgunits/{orgCode}?include=users,campaigns

Unknown properties are ignored.

Look under the relevant resource to see which properties can be included.

There is currently no way to disambiguate properties with the same name but on different types. The current solution is just to include both. For instance user.parent and orgunit.parent should both be referred to as just 'parent' in the include parameter. There is also no way of specifying how deep in the nesting hierarchy the inclusion is desired, mostly this is handled automatically by the loop detection. All of this may change in the future.

About org codes

The org codes are used as a means to uniquely identify a user or organizational unit. The uniqueness of the org codes is enforced upon user / org unit creation.

Often the org code for a user is simply the username or email and the org code for an org unit is the unit name. In other cases the org code is an external id, from an economy system or something similar.

About lead definitions

A lead definition describe the fields on a lead.

Each field is described with a name, import name, type, sort order, editablity, position on dialing page and many other properties.

Lead definitions also describe inter-field dependencies and associated actions.

There can be multiple lead definitions.

Lead definitions are typically very long lived.

Typically multiple campaigns are associated with the same lead definition.

About campaigns

A campaign describes a dialing activity, such as a sale of a specific product, booking of meetings or similar.

All leads are linked to exactly one campaign.

Campaign can both be long and short lived. The recommended approach is to keep the number of campaigns as low as possible.

Campaigns are grouped into projects.

A campaign is linked to a lead definition.

About lead pools

Lead pools offer a way to group uploaded leads within a given campaign. Leads are always related to a lead pool.

Creating lead pools

Currently there are 4 different ways lead pools can be created:

  1. Upload of leads via the UI.
  2. Manually creating a lead in the UI.
  3. Upload of leads via the import web service without specifying a lead pool.
  4. Upload of leads via the import web service to a named lead pool.

Upload of leads via the UI

Uploading leads via the UI causes a new lead pool to be created and all the leads in the batch are grouped in that pool. The lead pool can be named before the upload commences.

Manually creating a lead in the UI

Leads created directly in the UI are saved in a 'default' lead pool. The system takes care of finding a relevant default pool or creating one if no relevant pool was found. Default pools currently follow a naming scheme like: "Manually created leads yyyy-MM". Where "Manually created leads" may differ depending on the user language. The yyyy-MM component has the effect that a new lead pool is created every month.

Upload of leads via the import web service without specifying a lead pool

If no lead pool is specified when uploading leads via the lead import web service, then the system looks for a lead pool following the naming scheme: "(auto) yyyy-MM-dd". The yyyy-MM-dd component has the effect that a new lead pool is created every day. This means that if the time passes midnight (CET) during a lead upload operation, the leads uploaded before and after midnight will end up in 2 different pools.

Upload of leads via the import web service to a named lead pool

Specifying a lead pool name when uploading leads via the lead import web service will cause the uploaded leads to be put in that lead pool. If no lead pool with the given name was found, then a new pool with that name will be created. It is recommended to adopt a lead pool naming scheme which includes an incremental component, like full date or year-month, to group batches in different lead pools.

There are three ways of exporting leads via this api:

The SimpleLeads api

The SimpleLeads api is the newest, and recommended, way of exporting leads.

The leads can be filtered on basic attributes and are returned as LeadForExport object in one the the supported streamable formats.

Security is implicitly handled via the project and lead definition entry access rights

Saved search export

The lead search services are the web service counterparts to the lead search UI. The search web services do NOT enable the caller to perform an arbitrary search. Instead the caller has to configure a search and save it in the UI and the saved search can then be executed and the result downloaded via these web services.

All web service accounts are linked to a HeroBase user and it is only searches saved by this linked user, which can be executed by a given web service account.

It is possible to override the campaign selection in the search by specifying the project parameter when executing the search.

The results of the search are limited based on the webservice accounts project rights.

This type of export allows for very fine-grained and explicit control over the exports, but can require manual adjustment if conditions change.

The RawLeads api

This api works in much the same was as SimpleLeads, except that the leads are returned as a CSV stream, where each row consists of three fields:UniqueLeadId, FieldName and FieldValue.

About basic types

DateTime

DateTime objects are encoded as ISO 8601 combined date and time representations.

TimeSpan

Time spans/periods/durations are encoded as ISO 8601 durations. Syntax: PnYnMnDTnHnMnS, where nY represents the number of years, nM the number of months, nD the number of days, 'T' is the date/time separator, nH the number of hours, nM the number of minutes and nS the number of seconds.

Note that the format is case sensitive.

About resources and related types

Calls

Represents a call made to a lead through HeroBases systems.

Since users can be moved between different organizational units, it is important to keep the full organizational hierarchy with the call in order to be able to do consistent historical statistics over time.

Lead definition

Lead definition entry

Campaigns

Lead pools

Leads

Org units

Users

SimpleLeadFilter

LeadStatus

This enum contains the statuses that can be set on leads.

If a lead changes status as the result of a call, the resulting status is also registered on the call.

Some statuses cannot happen as the result of a call and are therefore unique to leads.

        /// New lead. Never before dialed.
        New = 0,

        /// This status is set if a call ended with NoResponse, Busy, VoiceMail.
        /// This status is only set if the previous lead state was New or
        /// RedialAutomatic. Common and private redials are never set to this
        /// state.
        RedialAutomatic = 1,

        /// This status is set when an agent schedules a redial and makes it
        /// available to all agents.
        RedialManualCommon = 2,

        /// This status is set when an agent schedules a redial and makes it
        /// private.
        RedialManualPrivate = 3,

        /// This status is set when an agent schedules a redial and makes it
        /// VIP.
        VIPRedial = 10,

        /// This status is set when an agent doesn't save a called lead on the
        /// contact page. The state is not set immediately, but rather next
        /// time the agent tries to call a lead, on logout, on session timeout
        /// or during nightly cleanup cycle. This status is unique to leads.
        Unresolved = 150,

        /// This status is set when the agent closes lead normally.
        UserProcessed = 200,

        /// If the lead has been called a given amount of times, but with no
        /// contact, the lead is set to Depleted.
        Depleted = 210,

        /// If an Unresolved lead hasn't been resolved within a given amount of
        /// time it is set to Abandoned.
        Abandoned = 300,

        /// If the system detects that a lead is unreachable for other reasons
        /// than the lead phone never being answered, the lead status is set to
        /// Failed.
        Failed = 400,

        /// If a lead hasn't been closed within a given time limit, set on the
        /// campaign, it is set to Expired.
        /// If no time limit is set on the campaign, its leads are never expired.
        /// New, auto and manual redials are expired according to the same
        /// setting. Private redials are expired according to a separate setting.
        /// VIP redials are never expired.
        Expired = 500,

        /// This status can be set by administrators to signal that the lead
        /// should no longer be used. This status is unique to leads.
        Removed = 600,

        /// User request to clear info about him, all lead data is cleared from the system according
        Anonymized = 610,
		
        /// This status can be set by administrators to signal that the lead
        /// should not be called, since it in customers DoNotCall list.
        DoNotCall = 700,

        /// This status can be set by superadministrators to signal that the lead
        /// should not be called, since it in Global DoNotCall list.
        GlobalDoNotCall = 750,
                        

LeadClosure

This enum contains system closures which can be set on leads.

The closure is not selected directly by the agent, but rather inferred from whatever lead data entry that has been mapped to system closures.

// The closure has not yet been set.
NotSet = 0,
// The lead was closed as a success.
Success = 1
// The lead was closed as not interested.
NotInterested = 2
// The was closed as invalid. An example would be because if
// phonenumber was to a fax or to the wrong person.
InvalidLead = 3
// The lead was closed as unqualified. An example could be that the
// lead was a truck driver, but the campaign is about calling
// carpenters.
Unqualified = 4
						

CallStatus

This enum contains the statuses that can be set on calls.

A calls status is basically set to whatever the leads status is set to during wrap up, so most of these are similar to the statuses which can be set on leads.

There are a few lead statuses which can not be set as the result of a call, so they are not included here.

Since a call might end up not resulting in a lead status change, there are special call statuses for those cases.

// No status set. Usually for call in progress, otherwise might be the
// result of an error.
NotSet = 0
// The lead status was set to automatic redial after this call.
// Probable causes are: NoAnswer, Busy, VoiceMail.
RedialAutomatic = 1
// The lead status was set to common redial after this call.
RedialManualCommon = 2
// The lead status was set to private redial after this call.
RedialManualPrivate = 3
// This call was succeeded by a call to an alternative number and so,
// didn't result in a lead status change. This status is unique to calls.
AlternativeNumberDialed = 199
// The lead status was set to user processed after this call.
UserProcessed = 200
// The lead status was set to depleted after this call.
Depleted = 210
// When a lead call is transferred it is marked as disconnected and the
// status is set as usual. To keep track of what happens after the
// transfer, new calls are created and they are always set to status
// Transferred. This status is unique to calls.
Transferred = 220
// If an agent closes the contact page without saving the lead, the
// lead status is set to Unresolved and if the lead is not later
// edited and set to a proper status it is eventually set to Abandoned.
// The Unresolved status is not used for calls, instead the call
// status is set to Abandoned.
Abandoned = 300
// If the system detects that a lead is unreachable for other reasons
// than the lead phone never being answered, the lead status is set to
// Failed.
Failed = 400
						

CallEndCause

// The call is still in progress or the proper end cause could not be determined.
NotApplicable = 0
// The call was disconnected normally, by either end.
NormalDisconnect = 1
// There was no response to the outgoing call.
NoResponse = 2
// The dialed number was busy.
Busy = 3
// The agent marked this call as voice mail.
VoiceMail = 4
// The system hung up this call without connecting it to an agent.
DroppedCall = 5
// The agent cancelled the call during the dialing / ringing phase.
DialingCancelled = 6
						

What about {Insert favourite web service protocol here (SOAP, XML-RPC, JSON-RPC, etc.)}

Going forward HeroBases API will be based on REST over HTTP. The primary content type is JSON, but other content types may be added later. A few services also supports exporting to CSV.

Rate limiting

All services are rate limited. Currently the limits refer to number of request, but limits on amount of content returned may be introduced at some point.

The limits for the various services can be inspected here: /api/myaccount/request/limits

The current request counts for the services can be inspected here: /api/myaccount/request/counts

In general, usage is counted for 24 hour periods, for each service individually, starting at first request to a given service.

Additional rules apply for services with high limits (currently defined as > 10000 allowed request per day).

If used naively, request counters are incremented by 4 outside production hours (currently defined as 8:00-21:00), and by 8 inside production hours.

Request counters are incremented by 1 outside production hours (currently defined as 8:00-21:00), and by 8 inside production hours.

To be able to utilize the full amount of requests, during production hours, callers must opt in to a fair use policy. Opting in means that request counters are only incremented by 1, but the caller has to limit number of requests per minute.

Opting in to the fair use policy is done by including the header:

X-Rate-Limit-Fair-Use-Policy: Minute rated
            

Per minute limits are calculated as the daily limit divided by minutes of the day, though no less than 240 request. Max(Ceiling(daily limit/(24*60)),240)

Daily limits still apply when fair use policy is in effect. This means that 429 (Too many request) is returned if either daily limit or current minute limit is exceeded.

All responses include information about current limits and counts:

X-Rate-Limit-Limit - The number of allowed requests in the current period
X-Rate-Limit-Remaining - The number of remaining requests in the current period
X-Rate-Limit-Reset - The number of seconds left in the current period
            

When fair use policy is in effect, the response headers refer to the current minute period or, if 249 is returned, the period in which limits was exceeded (daily or minute).

About pagination

None of the services will support any kind of pagination. Clients are encouraged to implement their own pagination if required and when possible.

To implement pagination when using the calls service, simply make more requests on smaller time periods, rather than one large request covering the full period.

About streamable formats

Most of the services can respond with text/html and application/json formats, but the services which can potentially return large amounts of data are limited to application/json. In the future more formats may be added, but only the formats where the serializer supports direct streaming to the network, rather than buffering the full response, will be usable in those services.

API documentation

This API exploration page uses swagger.