Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

194 Commits

Repository files navigation

sendwithus_sharp

sendwithus C# Client

status

Build status

requirements

none

.NET Framework Support

Target framework is .NET Standard 2.0

API Coverage

With one exception, this client covers all of the sendwithus API calls documented at: https://www.sendwithus.com/docs/api#overview

The exception is the Multi-Langauge API calls; those API calls are not supported in this client. If you require support for the Multi-Language API, please contact sendwithus: https://www.sendwithus.com/contact

Install via NuGet Package Manager

If you are using Visual Studio 2015:

  • In the Solution Explorer window, right click on your solution and select "Manage NuGet Packages for Solution..."
  • Search for "SendwithusClient"
    • Be sure to use the one that's by sendwithus. There's another one called SendWithUs.Client by Mimeo, but that is not supported by sendwithus
  • Select the "SendwithusClient" package and choose "Install" for your solution/project.

Getting started

usingsendwithus;// Set the API KeySendwithusClient.ApiKey=<your_api_key>// Test or Production// Configure API settings (optional)SendwithusClient.SetTimeoutInMilliseconds(your_preferred_timeout);// Default is 30000 (30s). This is the timeout for an individual API call attemptSendwithusClient.RetryCount=your_preferred_retryCount;// Default is 3. This is the number of times that each API call will be retried if it fails due to a potentially transient eventSendwithusClient.RetryIntervalMilliseconds=your_preferred_retryInterval;// Default is 100ms. This is the amount of time to wait between retry attempts.

Notes on Retries and Exceptions

The API will perform a retry in the following cases:

Retry CausesException Thrown
API Call TimeoutTaskCanceledException
Received HTTP Status 502: BadGatewaySendwithusException
Received HTTP Status 503: ServiceUnavailableSendwithusException
Received HTTP Status 505: GatewayTimeoutSendwithusException

A SendwithusException is a regular Exception with a StatusCode property added

All exceptions will be part of an AggregateException, regardless of whether a retry was attempted or not.

Some examples:

  • An API call that fails with a status code 403: Forbidden (not a retriable status code) will throw an AggregateException with one InnerException of type SendwithusException
  • An API call that repeatedly times out will throw an AggregateException with InnerExceptions of type TaskCanceledException
  • An API call that times out once, then fails with a status code of 503: Service Unavailable, and then fails again with a status code 400: Bad Request will throw an AggregateException with InnerExceptions, in order, of: { TaskCanceledException, SendwithusException, SendwithusException}

Other Exceptions

The API Client will also throw the following other exceptions:

  • An InvalidOperationException will be thrown when adding a new API call to a queue of Batched API calls when the limit of maximum API calls per batch has already been met

API Calls

Templates

Get a list of templates

GET /templates

try{vartemplates=awaitTemplate.GetTemplatesAsync();}catch(AggregateExceptionexception){// Exception handling}

Get a specific template (all versions)

GET /templates/(:template_id)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";try{varresponse=awaitTemplate.GetTemplateAsync(templateId);}catch(AggregateExceptionexception){// Exception handling}

GET /templates/(:template_id)/versions

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";try{vartemplate=awaitTemplate.GetTemplateVersionsAsync(templateId);}catch(AggregateExceptionexception){// Exception handling}

Get a list of template versions (with HTML/text)

GET /templates/(:template_id)/versions

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="en-US";try{vartemplate=awaitTemplate.GetTemplateAsync(templateId,locale);}catch(AggregateExceptionexception){// Exception handling}

GET /templates/(:template_id)/locales/(:locale)/versions

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="en-US";try{vartemplateVersions=awaitTemplate.GetTemplateVersionsAsync(templateId,locale);}catch(AggregateExceptionexception){// Exception handling}

Get a specific version (with HTML/text)

GET /templates/(:template_id)/versions/(:version_id)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varversionId="ver_ET3j2snkKhqsjRjtK6bXJE";try{vartemplateVersion=awaitTemplate.GetTemplateVersionAsync(templateId,versionId);}catch(AggregateExceptionexception){// Exception handling}

GET /templates/(:template_id)/locales/(:locale)/versions/(:version_id)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="en-US";varversionId="ver_ET3j2snkKhqsjRjtK6bXJE";try{vartemplateVersion=awaitTemplate.GetTemplateVersionAsync(templateId,locale,versionId);}catch(AggregateExceptionexception){// Exception handling}

Update a template version

Note: at least one of "html" or "text" must be specified in the updated template version object

PUT /templates/(:template_id)/versions/(:version_id)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varversionId="ver_ET3j2snkKhqsjRjtK6bXJE";varupdatedTemplateVersion=newTemplateVersion();vartemplateVersionName="New Version";vartemplateSubject="edited!";// Create the template datavartemplate_data=newDictionary<string,object>();template_data.Add("amount","$12.00");varupdatedTemplateVersion=newTemplateVersion(templateVersionName,templateSubject);updatedTemplateVersion.html="<html><head></head><body><h1>UPDATE</h1></body></html>";// optionalupdatedTemplateVersion.text="sometext";// optionalupdatedTemplateVersion.preheader="some preheader";// optionalupdatedTemplateVersion.template_data=template_data;// optionaltry{vartemplateVersion=awaitTemplate.UpdateTemplateVersionAsync(templateId,versionId,updatedTemplateVersion);}catch(AggregateExceptionexception){// Exception handling}

PUT /templates/(:template_id)/locales/(:locale)/versions/(:version_id)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="en-US"varversionId="ver_ET3j2snkKhqsjRjtK6bXJE";varupdatedTemplateVersion=newTemplateVersion();vartemplateVersionName="New Version";vartemplateSubject="edited!";varupdatedTemplateVersion=newTemplateVersion(templateVersionName,templateSubject);updatedTemplateVersion.html="<html><head></head><body><h1>UPDATE</h1></body></html>";// optionalupdatedTemplateVersion.text="sometext";// optionalupdatedTemplateVersion.preheader="some preheader";// optionaltry{vartemplateVersion=awaitTemplate.UpdateTemplateVersionAsync(templateId,versionId,updatedTemplateVersion);}catch(AggregateExceptionexception){// Exception handling}

Create a New Template

POST /templates

vartemplateVersionName="New Template Version";vartemplateSubject="New Version!";vartemplate_data=newDictionary<string,object>();template_data.Add("amount","$12.00");varupdatedTemplateVersion=newTemplateVersion(templateVersionName,templateSubject);updatedTemplateVersion.html="<html><head></head><body><h1>NEW TEMPLATE VERSION</h1></body></html>";// optionalupdatedTemplateVersion.text="some text";// optionalupdatedTemplateVersion.preheader="some preheader";// optionalupdatedTemplateVersion.locale="en-US";// optionalupdatedTemplateVersion.template_data=template_data;// optionaltry{vartemplate=awaitTemplate.CreateTemplateAsync(updatedTemplateVersion);}catch(AggregateExceptionexception){// Exception handling}

Add locale to existing template

POST /templates/(:template_id)/locales

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="fr-FR";vartemplateVersionName="Published French Version";vartemplateSubject="Ce est un nouveau modèle!";varupdatedTemplateVersion=newTemplateVersion(templateVersionName,templateSubject);updatedTemplateVersion.html="<html><head></head><body><h1>Nouveau modèle!</h1></body></html>";// optionalupdatedTemplateVersion.text="un texte";// optionalupdatedTemplateVersion.preheader="some preheader";// optionaltry{vartemplate=awaitTemplate.AddLocaleToTemplate(templateId,locale,updatedTemplateVersion);}catch(AggregateExceptionexception){// Exception handling}

Create a new template version

POST /templates/(:template_id)/versions

NOTE – At least one of html or text must be specified

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";vartemplateVersionName="New Template Version";vartemplateSubject="New Version!";vartemplate_data=newDictionary<string,object>();template_data.Add("amount","$12.00");varupdatedTemplateVersion=newTemplateVersion(templateVersionName,templateSubject);updatedTemplateVersion.html="<html><head></head><body><h1>NEW TEMPLATE VERSION</h1></body></html>";// optionalupdatedTemplateVersion.text="some text";// optionalupdatedTemplateVersion.preheader="some preheader";// optionalupdatedTemplateVersion.template_data=template_data;// optionaltry{vartemplateVersion=awaitTemplate.CreateTemplateVersion(templateId,updatedTemplateVersion);}catch(AggregateExceptionexception){// Exception handling}

POST /templates/(:template_id)/locales/(:locale)/versions

NOTE – At least one of html or text must be specified

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="en-US";vartemplateVersionName="New Template Version";vartemplateSubject="New Version!";varupdatedTemplateVersion=newTemplateVersion(templateVersionName,templateSubject);updatedTemplateVersion.html="<html><head></head><body><h1>NEW TEMPLATE VERSION</h1></body></html>";// optionalupdatedTemplateVersion.text="some text";// optionalupdatedTemplateVersion.preheader="some preheader";// optionaltry{vartemplateVersion=awaitTemplate.CreateTemplateVersion(templateId,locale,updatedTemplateVersion);}catch(AggregateExceptionexception){// Exception handling}

Delete a specific template

DELETE /templates/(:template_id)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";try{vargenericApiCallStatus=awaitTemplate.DeleteTemplate(templateId);}catch(AggregateExceptionexception){// Exception handling}

DELETE /templates/(:template_id)/locales/(:locale)

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";varlocale="en-US";try{vargenericApiCallStatus=awaitTemplate.DeleteTemplate(templateId,locale);}catch(AggregateExceptionexception){// Exception handling}

Sending Emails

Send an email

We validate all HTML content

POST /send

Example with only the required parameters:

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";// Construct the template data// The content of the template data is all optional and is based on the template being usedvartemplateData=newDictionary<string,object>();templateData.Add("first_name","Chuck");templateData.Add("last_name","Norris");templateData.Add("img","http://placekitten.com/50/60");varlink=newDictionary<string,string>();link.Add("url","https://www.sendwithus.com");link.Add("text","sendwithus!");templateData.Add("link",link);// Construct the recipientvarrecipient=newEmailRecipient(DEFAULT_RECIPIENT_EMAIL_ADDRESS);// Construct the email objectvaremail=newEmail(templateId,templateData,recipient);// Send the emailtry{varemailResponse=awaitemail.Send();}catch(AggregateExceptionexception){// Exception handling}

Example with all parameters:

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";// Construct the template data// The content of the template data is all optional and is based on the template being usedvartemplateData=newDictionary<string,object>();templateData.Add("first_name","Chuck");templateData.Add("last_name","Norris");templateData.Add("img","http://placekitten.com/50/60");varlink=newDictionary<string,string>();link.Add("url","https://www.sendwithus.com");link.Add("text","sendwithus!");templateData.Add("link",link);// Construct the recipientvarrecipient=newEmailRecipient(DEFAULT_RECIPIENT_EMAIL_ADDRESS);// Construct the email objectvaremail=newEmail(templateId,templateData,recipient);email.cc.Add(newEmailRecipient("cc_one@email.com","CC One"));email.cc.Add(newEmailRecipient("cc_two@email.com","CC Two"));email.bcc.Add(newEmailRecipient("bcc_one@email.com","BCC One"));email.bcc.Add(newEmailRecipient("bcc_two@email.com","BCC Two"));email.sender.address="company@company.com";email.sender.reply_to="info@company.com";email.sender.name="Company";email.tags.Add("tag1");email.tags.Add("tag2");email.tags.Add("tag3");email.headers.Add("X-HEADER-ONE","header-value");email.inline.id="cat.png";email.inline.data="{BASE_64_ENCODED_FILE_DATA}";email.files.Add(newEmailFileData("doc.txt","{BASE_64_ENCODED_FILE_DATA}"));email.files.Add(newEmailFileData("stuff.zip","{BASE_64_ENCODED_FILE_DATA}"));email.version_name="this version";email.locale="en-US";email.esp_account="esp_EsgkbqQdDg7F3ncbz9EHW7";// Send the emailtry{varemailResponse=awaitemail.Send();}catch(AggregateExceptionexception){// Exception handling}

Logs

Get a specific log + metadata

GET /logs/(:log_id)

varlogId="log_88be2c0f8b5c6d3933dd578b6a0f13e5";try{varlog=awaitLog.GetLogAsync(logId);}catch(AggregateExceptionexception){// Exception handling}

Retrieve events for a specific log_id

GET /logs/(:log_id)/events

varlogId="log_88be2c0f8b5c6d3933dd578b6a0f13e5";try{varlogEvents=awaitLog.GetLogEventsAsync(logId);}catch(AggregateExceptionexception){// Exception handling}

Resend an existing Log

POST /resend

varlogId="log_88be2c0f8b5c6d3933dd578b6a0f13e5";try{varlogResendResponse=awaitLog.ResendLogAsync(logId);}catch(AggregateExceptionexception){// Exception handling}

Snippets

Get all snippets

GET /snippets

try{varsnippets=awaitSnippet.GetSnippetsAsync();}catch(AggregateExceptionexception){// Exception handling}

Get specific snippet

GET /snippets/(:id)

varsnippetId="snp_bn8c87iXuFWdtYLGJrBAWW";try{varsnippets=awaitSnippet.GetSnippetAsync(snippetId);}catch(AggregateExceptionexception){// Exception handling}

Creating a new snippet

POST /snippets

varsnippetName="My First Snippet";varsnippetBody="<h1>Welcome!</h1>";try{varsnippetResponse=awaitSnippet.CreateSnippetAsync(snippetName,snippetBody);}catch(AggregateExceptionexception){// Exception handling}

Update an existing snippet

PUT /snippets/(:id)

varsnippetId="snp_bn8c87iXuFWdtYLGJrBAWW";varsnippetName="Updated Snippet";varsnippetBody="<h1>Welcome Again!</h1>";try{varresponse=awaitSnippet.UpdateSnippetAsync(snippetId,snippetName,snippetBody);}catch(AggregateExceptionexception){// Exception handling}

Delete an existing snippet

DELETE /snippets/(:id)

varsnippetId="snp_bn8c87iXuFWdtYLGJrBAWW";try{vargenericApiCallStatus=awaitSnippet.DeleteSnippetAsync(snippetId);}catch(AggregateExceptionexception){// Exception handling}

Render templates

Render a template with data

POST /render

vartemplateId="tem_SxZKpxJSHPbYDWRSQnAQUR";// Create the template datavartemplateData=newDictionary<string,object>();templateData.Add("amount","$12.00");// Create the render objectvarrenderTemplate=newRender(templateId,templateData);renderTemplate.version_id="ver_ET3j2snkKhqsjRjtK6bXJE";// optional. Can use either version_id or version_name to specify a version, but not bothrenderTemplate.locale="en-US";// optionalrenderTemplate.strict=true;// optional. Strict defaults to false if not settry{varrenderTemplateResponse=awaitrenderTemplate.RenderTemplateAsync();}catch(AggregateExceptionexception){// Exception handling}

Customers

Get a specific customer

GET /customers/customer@example.com

varcustomerEmailAddress="customer@example.com";try{varcustomerResponse=awaitCustomer.GetCustomerAsync(customerEmailAddress);}catch(AggregateExceptionexception){// Exception handling}

Creating/updating a new customer

POST /customers

If a Customer already exists with the specified email address, then a data merge is performed. Merge operations will:

  • replace existing attributes with new values
  • add any new attributes to the Customer Merge operations will never remove attributes from a Customer. Note that customer data can only be simple data types like strings and integers.
// Build the customervarcustomer=newCustomer("customer@example.com");customer.data.Add("first_name","Matt");// optionalcustomer.data.Add("city","San Francisco");// optionalcustomer.locale="en-US";// optional// Make the API calltry{vargenericApiCallStatus=awaitCustomer.CreateOrUpdateCustomerAsync(customer);}catch(AggregateExceptionexception){// Exception handling}

Delete a customer

DELETE /customers/(:email)

varcustomerEmailAddress="customer@example.com";try{vargenericApiCallStatus=awaitCustomer.DeleteCustomerAsync(customerEmailAddress);}catch(AggregateExceptionexception){// Exception handling}

Get email logs for a customer

GET /customers/matt@sendwithus.com/logs?count={count}&created_lt={timestamp}&created_gt={timestamp}

With no query parameters to filter the logs:

varcustomerEmailAddress="customer@example.com";try{varcustomerEmailLogsResponse=awaitCustomer.GetCustomerEmailLogsAsync(customerEmailAddress);}catch(AggregateExceptionexception){// Exception handling}

With all query parameters to filter the logs:

varcustomerEmailAddress="customer@example.com";varqueryStartTime=123456789;varqueryEndTime=987654321;// Build the query parameters. All of these are optionalvarqueryParameters=newDictionary<string,object>();queryParameters.Add("count",2);queryParameters.Add("created_gt",queryStartTime);queryParameters.Add("created_lt",queryEndTime);// Make the API calltry{varcustomerEmailLogsResponse=awaitCustomer.GetCustomerEmailLogsAsync(customerEmailAddress,queryParameters);}catch(AggregateExceptionexception){// Exception handling}

Drip Campaigns

Activate campaign for a customer

This will add the specified customer to the first step of the specified drip campaign. If the first step has a delay on it, then it will send the first email once that delay has elapsed.

POST /drip_campaigns/(drip_campaign_id)/activate

vardripCampaignId="dc_VXKGx85NmwHnRv9FZv88TW";// Build the drip campaign objectvarrecipient=newEmailRecipient("user@email.com","John");// The email name is optionalvardripCampaign=newDripCampaign(recipient);dripCampaign.cc.Add(newEmailRecipient("cc_one@email.com","Suzy Smith"));// OptionaldripCampaign.cc.Add(newEmailRecipient("cc_two@email.com","Joe"));// OptionaldripCampaign.bcc.Add(newEmailRecipient("bcc_one@email.com","Fake Name"));// OptionaldripCampaign.bcc.Add(newEmailRecipient("bcc_one@email.com","Matt Damon"));// OptionaldripCampaign.sender.address="company@company.com";// OptionaldripCampaign.sender.name="Company";// OptionaldripCampaign.sender.reply_to="info@company.com";// OptionaldripCampaign.tags.Add("tag1");// OptionaldripCampaign.tags.Add("tag2");// OptionaldripCampaign.tags.Add("tag3");// OptionaldripCampaign.locale="en-US";// OptionaldripCampaign.esp_account="esp_1a2b3c4d5e";// OptionaldripCampaign.email_data.Add("amount","$12.00");// Optional// Make the API calltry{varresponse=awaitdripCampaign.ActivateAsync(dripCampaignId);}catch(AggregateExceptionexception){// Exception handling}

Deactivate a campaign for customer

POST /drip_campaigns/(drip_campaign_id)/deactivate

vardripCampaignId="dc_VXKGx85NmwHnRv9FZv88TW";varcustomerEmailAddress="user@email.com";try{vardripCampaignResponse=awaitDripCampaign.DeactivateAsync(dripCampaignId,customerEmailAddress);}catch(AggregateExceptionexception){// Exception handling}

Deactivate a customer from all campaigns

If a user unsubscribes, changes email addresses, or cancels, call this endpoint to remove the specified email address from all active drip campaigns.

POST /drip_campaigns/deactivate

varcustomerEmailAddress="user@email.com";try{vardripCampaignDeactivateAllResponse=awaitDripCampaign.DeactivateFromAllCampaignsAsync(customerEmailAddress);}catch(AggregateExceptionexception){// Exception handling}

Get a list of campaigns

GET /drip_campaigns

try{vardripCampaignDetails=awaitDripCampaign.GetDripCampaignsAsync();}catch(AggregateExceptionexception){// Exception handling}

Get the details on a specific drip campaign

GET /drip_campaigns/(drip_campaign_id)

vardripCampaignId="dc_VXKGx85NmwHnRv9FZv88TW";try{vardripCampaignDetails=awaitDripCampaign.GetDripCampaignAsync(dripCampaignId);}catch(AggregateExceptionexception){// Exception handling}

Batch API Calls

The sendwithus batch endpoint enables multiple API calls to be made in a single HTTP request. NOTE – Batch sizes over 10 requests are not recommended.

  • By default, batch API calls are limited to 10 per batch.
  • Any additional calls beyond 10 will throw an InvalidOperationException.
  • This limit can be increased by calling BatchApiRequest.OverrideMaximumBatchRequests(int newMaximum)

The process to making a batch API call is:

  1. Call BatchApiRequest.StartNewBatchRequest()
  • After making this call, all subsequent API calls will queued up in a new batch request.
  1. Make all the API calls as you normally would. Instead of being sent, these calls will be queued.
  2. Call BatchApiRequest.SendBatchApiRequest(). This will send the batch request with all of the queued requests, clear the queue, return the response (which will contain the response for each API call in the queue), and exit batch mode.
  • After this call, all subsequent API calls will be sent out as soon as they are called, instead of being queued.
  1. Access the response to each batch command by calling

Additional Features:

  • PauseBatchRequest() and ResumeBatchRequest(): Respectively exist and then re-enter batch mode without clearing the list of batched calls. Allows other API calls to be sent immediately (not batched) while building a list of batched API calls.
  • AbortBatchRequest(): Allows a batch API calls can be aborted without sending any of the batched calls. This will exit batch mode and clear the list of batched API calls.

Send batch request

POST /batch

Example using 5 commands:

// Start the batch requestBatchApiRequest.StartNewBatchRequest();// Make the API calls to be batchedvarcustomerEmailAddress="customer@example.com";varsnippetId="snp_bn8c87iXuFWdtYLGJrBAWW";varsnippetName="Updated Snippet";varsnippetBody="<h1>Welcome Again!</h1>";try{// Discard the response to the API calls as it will just be an empty object (since the requests aren't actually sent yet)awaitSnippet.GetSnippetsAsync();awaitLog.GetLogsAsync();awaitSnippet.UpdateSnippetAsync(snippetId,snippetName,snippetBody);awaitDripCampaign.GetDripCampaignsAsync();awaitCustomer.DeleteCustomerAsync(customerEmailAddress);// Make the batch API RequestvarbatchResponses=awaitBatchApiRequest.SendBatchApiRequest();// Get the response to the individual API callsvarsnippets=response[0].GetBody<List<Snippet>>();varlogs=response[1].GetBody<List<Log>>();varsnippetResponse=response[2].GetBody<SnippetResponse>();vardripCampaignDetails=response[3].GetBody<List<DripCampaignDetails>>();vargenericApiCallStatus=response[4].GetBody<GenericApiCallStatus>();}catch(AggregateExceptionexception){// Exception handling}catch(InvalidOperationExceptionexception){// Exception handling}

Example sending 11 commands without overriding the limit (to show when the exception is thrown):

varcustomerEmailAddress="customer@example.com";varsnippetId="snp_bn8c87iXuFWdtYLGJrBAWW";varsnippetName="Updated Snippet";varsnippetBody="<h1>Welcome Again!</h1>";// Start the batch requestBatchApiRequest.StartNewBatchRequest();// Make the API calls to be batchedtry{// Make the first 10 API calls// Discard the response to the API calls as it will just be an empty object (since the requests aren't actually sent yet)awaitSnippet.GetSnippetsAsync();awaitLog.GetLogsAsync();awaitSnippet.UpdateSnippetAsync(snippetId,snippetName,snippetBody);awaitDripCampaign.GetDripCampaignsAsync();awaitCustomer.DeleteCustomerAsync(customerEmailAddress);awaitSnippet.GetSnippetsAsync();awaitLog.GetLogsAsync();awaitSnippet.UpdateSnippetAsync(snippetId,snippetName,snippetBody);awaitDripCampaign.GetDripCampaignsAsync();awaitCustomer.DeleteCustomerAsync(customerEmailAddress);// Make the 11th API call. This is when the InvalidOperationException will be thrownawaitSnippet.GetSnippetsAsync();// Make the batch API Request. This won't be reached.varbatchResponses=awaitBatchApiRequest.SendBatchApiRequest();// Handle the responses}catch(AggregateExceptionexception){// Exception handling}catch(InvalidOperationExceptionexception){// Exception handling}

Example sending 12 commands after overriding the limit:

varcustomerEmailAddress="customer@example.com";varsnippetId="snp_bn8c87iXuFWdtYLGJrBAWW";varsnippetName="Updated Snippet";varsnippetBody="<h1>Welcome Again!</h1>";// Start the batch requestBatchApiRequest.StartNewBatchRequest();// Override the maximum number of API calls that can be included in this batchBatchApiRequest.OverrideMaximumBatchRequests(12);// Make the API calls to be batchedtry{// Make the first 10 API calls// Discard the response to the API calls as it will just be an empty object (since the requests aren't actually sent yet)awaitSnippet.GetSnippetsAsync();awaitLog.GetLogsAsync();awaitSnippet.UpdateSnippetAsync(snippetId,snippetName,snippetBody);awaitDripCampaign.GetDripCampaignsAsync();awaitCustomer.DeleteCustomerAsync(customerEmailAddress);awaitSnippet.GetSnippetsAsync();awaitLog.GetLogsAsync();awaitSnippet.UpdateSnippetAsync(snippetId,snippetName,snippetBody);awaitDripCampaign.GetDripCampaignsAsync();awaitCustomer.DeleteCustomerAsync(customerEmailAddress);// Make the 11th and 12th API calls. This is when the InvalidOperationException will be thrownawaitSnippet.GetSnippetsAsync();awaitLog.GetLogsAsync();// Make the batch API Request.varbatchResponses=awaitBatchApiRequest.SendBatchApiRequest();// Handle the responses}catch(AggregateExceptionexception){// Exception handling}catch(InvalidOperationExceptionexception){// Exception handling}finally{// Return the max batch request limit to its default value (optional)BatchApiRequest.SetMaximumBatchRequestsToDefault();}

Example pausing and resuming a batch request

// Start the batch requestBatchApiRequest.StartNewBatchRequest();try{// Make the API call to be batchedawaitTemplate.GetTemplatesAsync();// Pause the batch requestBatchApiRequest.PauseBatchRequest();// Make another API call which will be sent immediatelyvarsnippets=awaitSnippet.GetSnippetsAsync();// Resume the batch request and add another API call to itBatchApiRequest.ResumeBatchRequest();awaitCustomer.GetCustomerAsync('foo@bar.com');// Make the final batch request, containing the Get Templates and Get Customer API callsvarbatchResponses=awaitBatchApiRequest.SendBatchApiRequest();}catch(AggregateExceptionexception){Assert.Fail(exception.ToString());}catch(InvalidOperationExceptionexception){// Exception handling}

Example aborting a batch request

// Start the batch requestBatchApiRequest.StartNewBatchRequest();try{// Make the API call to be batchedawaitTemplate.GetTemplatesAsync();// Abort the batch requestBatchApiRequest.AbortBatchRequest();// Make another API call which will be sent immediatelyvarsnippets=awaitSnippet.GetSnippetsAsync();// For demonstration, make the aborted batch API Reqeust anyways// This will be an empty request as the list of batched API calls was cleared by the Abort callvarbatchResponses=awaitBatchApiRequest.SendBatchApiRequest();}catch(AggregateExceptionexception){Assert.Fail(exception.ToString());}catch(InvalidOperationExceptionexception){// Exception handling}

Managing the API

Versioning

The build version is set by the Sendwithus_csharp/appveyor.yml file. It is set so that the 3rd digit in the build number is automatically incremented whenever a new build is made. To change the major or minor build revision, simply edit the line at the top of the file accordingly:

# version format
version: 1.0.{build}

The way the version settings for the final package are set is:

  • "version" variable set in appveyor.yml file, as shown above
  • appveyor.yml sets the C# project's "assembly_version", "assembly_file_version", and "assembly_informational_version" to this "version"
  • the sendwithus_csharp/Sendwithus/SendwithusClient.nuspec sets the NuGet version to the assembly version

Continuous Integration

This project uses AppVeyor for its CI. AppVeyor is configured to automatically run all of the unit tests whenever a new commit is pushed to GitHub, regardless of the branch. All of the AppVeyor settings are configured in the Sendwithus_csharp/appveyor.yml file. All unused settings are simply commented out, so all available settings can be identified in that file.

Continuous Deployment

The appveyor.yml file is configured to automatically deploy new commits to NuGet. It is configured so that only new commits on the master branch will be deployed. Therefore, please develop all features on a feature branch and only integrate with master when ready for deployment. This setting can be changed under the "build:" settings in the appveyor.yml file. It is also possible to manually build and deploy the solution from www.appveyor.com.

Settings for the NuGet deployment can be edited in the sendwithus_csharp/Sendwithus/SendwithusClient.nuspec file.

CLS Compliance - Using this Client in Other .NET Languages

The project is CLS compliant, so the package can be used in any .NET language that supports CLS compliant packages. For example, this includes VB.NET and might also include F# and Visual C++. The lattter two haven't been tested, but support for VB.NET has been. To add the package to a solution in a different language, simply follow the same procedure that you would for C#:

  • In the Solution Explorer window, right click on your solution and select "Manage NuGet Packages for Solution..."
  • Search for "SendwithusClient"
    • Be sure to use the one that's by sendwithus. There's another one called SendWithUs.Client by Mimeo, but that is not supported by sendwithus and might not be CLS compliant.
  • Select the "SendwithusClient" package and choose "Install" for your solution/project.

Tests

Running Unit Tests

The tests are run using Visual Studio's standard unit-testing libaries and built in test runner. Simply select "Test->Run->All Tests" to run the unit tests.

Response Ranges

Sendwithus' API typically sends responses back in these ranges:

  • 2xx – Successful Request
  • 4xx – Failed Request (Client error)
  • 5xx – Failed Request (Server error)

If you're receiving an error in the 400 response range follow these steps:

  • Double check the data and ID's getting passed to sendwithus
  • Ensure your API key is correct
  • Make sure there's no extraneous spaces in the id's getting passed

About

sendwithus_csharp

Resources

Stars

3 stars

Watchers

13 watching

Forks

Releases

Packages

Used by

Contributors

Languages