Strongly-Typed .NET API for Ontraport (Marketing Automation System)
Fully supports .NET Core and Dependency Injection.
If you want to support this project, subscribe to Ontraport via my affiliate link.
Ontraport is essentially the engine that powers all the interactions between you and your customers online — in ways that wouldn’t be possible manually.
It does everything related to email marketing and automation for your business, just like InfusionSoft/Keap, but it's cheaper and more user-friendly.
Their API documentation is available here, but it is very complex and difficult to use manually. This library makes it very simple, allowing you to focus on your .NET web application while letting Ontraport manage the business-side of it and all email communications campaigns.
Return the name and birthday of a contact by email.
public async Task<string> GetCustomerNameAndBirthday(string email)
{
var customer = await _ontraContacts.SelectAsync(email);
return $"{customer.FirstName} {customer.LastName} - {customer.Birthday}";
}
Add or merge a contact
public async Task AddOrMergeContact(string email, string firstName, string lastName)
{
var contact = new ApiContact()
{
Email = email,
FirstName = firstName,
LastName = lastName
};
await _ontraContacts.CreateOrMergeAsync(contact.GetChanges());
}
Edit contacts
public async Task EditCompanyField(string oldName, string newName)
{
var contacts = await _ontraContacts.SelectMultipleAsync(
new ApiSearchOptions().AddCondition(ApiContact.CompanyKey, "=", oldName));
var tasks = contacts.Select(async x =>
{
x.Company = newName;
return await _ontraContacts.UpdateAsync(x.Id.Value, x.GetChanges());
});
await Task.WhenAll(tasks);
}
Log a transaction manually
public async Task LogTransaction(string email, string productName, int quantity)
{
var contact = await _ontraContacts.CreateOrMergeAsync(new ApiContact()
{
Email = email
}.GetChanges());
var product = await _ontraProducts.SelectAsync(productName);
await _ontraTransactions.LogTransactionAsync(contact.Id.Value,
new ApiTransactionOffer().AddProduct(product.Id.Value, quantity, product.Price.Value));
}
Fully-typed API and classes for all main documented classes (and a few more), with very good documentation for Intellisense.
- CampaignBuilderItems
- Companies
- Contacts
- CouponCodes
- CouponProducts
- Coupons
- CreditCards
- CustomObjects
- Deals
- Forms
- LandingPages
- Messages
- Objects
- Offers
- Products
- Rules
- Tasks
- Transactions
- Webhooks
Each typed ApiObject has integrated changes-tracking support. You can return a dictionary of edited field keys and values with GetChanges().
All data formatting and parsing, such as Unix Epoch date time format to DateTimeOffset, is done automatically.
Ontraport supports many other (undocumented) objects which can be used via IOntraportObjects.
Add OntraportApi and OntraportApi.AspNetCore to your project via NuGet.
Add this to ConfigureServices in Startup.cs
services.Configure<OntraportConfig>(options => Configuration.Bind("Ontraport", options));
services.AddOntraportApi();
Add this to appsettings.json
"Ontraport": {
"AppId": "your-app-id",
"ApiKey": "your-api-key"
}
For better reliability of communication, you can use Polly to automatically retry API requests on timeout or failure.
Add Polly and Microsoft.Extensions.Http.Polly to your project via NuGet.
Add something like this just before services.AddOntraportApi();
services.AddHttpClient<OntraportHttpClient>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
No problem, this is the only class that depends on .NET Core so you can easily rewrite it for whatever technology you use.
In many cases, a simpler way to send data to Ontraport is to simply submit a SmartForm. Then, you can perform additional actions in your form via Ontraport. You can obtain the form id and custom field names (that look like f0000) by clicking Publish and looking at the HTML view.
Advantages: simpler, and it gives you form fillout statistics.
Disadvantages: it doesn't have any kind of security so don't use this for important management data.
You can use this to provide forms to the user that perform additional server-side actions, such as uploading files and resizing pictures.
To post forms, use IOntraportPostForms. It supports posting via the client's browser or via the server.
You do not need an API key to submit forms. If you wish to only post forms without using the rest of the API, you can register it with services.AddOntraportPostForms()
// Post and don't wait.
_ontraPostForms.ServerPost("my-form-id", new ApiContact()
{
Email = email,
FirstName = firstName
}.GetChanges());
Simple way: you can access all custom properties using the Data property of the object returned by the API. It exposes all raw data returned from Ontraport.
To add strongly-typed support for your custom fields for Contact, Company and Deal objects, create a class defining your extra fields.
You can get the list of custom field keys using the GetCustomFieldsAsync method.
public class ApiCustomContact : ApiContact
{
public ApiPropertyString Custom1Field => _custom1Field ?? (_custom1Field = new ApiPropertyString(this, Custom1Key));
private ApiPropertyString _custom1Field;
public const string Custom1Key = "f1234";
public string Custom1 { get => Custom1Field.Value; set => Custom1Field.Value = value; }
public ApiPropertyDateTime Custom2Field => _custom2Field ?? (_custom2Field = new ApiPropertyDateTime(this, Custom2Key));
private ApiPropertyDateTime _custom2Field;
public const string Custom2Key = "f2222";
public DateTimeOffset? Custom2 { get => Custom2Field.Value; set => Custom2Field.Value = value; }
}
Then, use OntraportContacts<ApiCustomContact> instead of OntraportContacts. You may want to create this class for convenience.
public class OntraportContacts : OntraportContacts<ApiCustomContact>, IOntraportContacts
{
public OntraportContacts(OntraportHttpClient apiRequest, IOntraportObjects ontraObjects) :
base(apiRequest, ontraObjects)
{ }
}
public interface IOntraportContacts : IOntraportContacts<ApiCustomContact>
{ }
Don't forget to register your new class in Startup.cs
services.AddTransient<IOntraportContacts, OntraportContacts>();
Supprted ApiProperty types (and you can easily implement your own parser):
- ApiProperty<int>
- ApiProperty<decimal>
- ApiProperty<float>
- ApiPropertyString
- ApiPropertyBool ("true", "false" parsed as Boolean)
- ApiPropertyDateTime (Unix Epoch seconds date parsed as DateTimeOffset)
- ApiPropertyIntBool ("1", "0", parsed as Boolean)
- ApiPropertyIntEnum<T> (Numeric field parsed as enumeration of type T)
- ApiPropertyStringEnum<T> (string parsed as enumeration of type T)
Simple way: use OntraportObject with the ObjectTypeId of your custom object. It takes an ObjectType parameter of type ApiCustomObject but you can pass any integer like this: (ApiObjectType)10000. Custom Objects have an ObjectTypeId above 10000.
Custom Objects behave like Contacts. They have their standard fields, custom fields, campaigns, tags, rules and messages.
To add strongly-typed support for a custom object:
- Create a class to expose all API methods related to custom objects. All methods are implemented through the base class.
You can obtain ObjectTypeId in Ontraport by clicking on the custom object section. It's ID will appear in the address bar.
public class OntraportRecordings : OntraportBaseCustomObject<ApiRecording>, IOntraportRecordings
{
public OntraportRecordings(OntraportHttpClient apiRequest, IOntraportObjects ontraObjects) :
base(apiRequest, ontraObjects, "Recording", "Recordings", ObjectTypeId, "name")
{ }
public static int ObjectTypeId = 10000;
}
public interface IOntraportRecordings : IOntraportBaseCustomObject<ApiRecording>
{ }
public class ApiRecording : ApiCustomObjectBase
{ }
- Register it in ConfigureServices in Startup.cs
services.AddTransient<IOntraportRecordings, OntraportRecordings>();
- Add all custom fields to your custom object. Your class inherits from ApiCustomObjectBase.
Obtain your list of custom fields using the OntraportRecordings.GetCustomFieldsAsync() method. The parent field is of type Int.
public class ApiRecording : ApiCustomObjectBase
{
public ApiProperty<int> Custom1Field => _custom1Field ?? (_custom1Field = new ApiProperty<int>(this, Custom1Key));
private ApiProperty<int> _custom1Field;
public const string Custom1Key = "f3333";
public int? Custom1 { get => Custom1Field.Value; set => Custom1Field.Value = value; }
}
That's it.
DO NOT RUN TESTS ON YOUR LIVE ONTRAPORT ACCOUNT
Ask for a SandBox account here.
We can't control the server environment and thus must run Integration Tests. Current integration tests are sufficient to show it's working, but more work could be done so they can run reliably and test more in-depth.
To run Unit Tests, Ontraport API credentials must be set in your User Secret Manager. Open the command-line tool and navigate to the OntraportApi.IntegrationTests project directory.
Use the following commands to set your keys to your sandbox account
dotnet user-secrets set OntraportAppId ""your-app-id-here""
dotnet user-secrets set OntraportApiKey ""your-api-key-here""");
Etienne Charland, known as the Emergence Guardian, helps starseeds reconnect with their soul power to accomplish the purpose they came here to do. You can read his book at Satrimono Publishing. Warning: non-geek zone.
You may also be interested in the Natural Grounding Player, Yin Media Encoder, 432hz Player, Powerliminals Player, and Audio Video Muxer.