V3 - Starter .NET Project

Occasional Participant

I have used V2 in the past and I am looking to see if V3 has a starter project, like V2 has on GitHub? Also does V3 now support tags, which V2 didn't?



Thank you for reaching out to Constant Contact API Developer Support.

Unfortunately we do not have any SDK libraries for our new V3 API at this time. Right now all of our focus is on finishing additional endpoints to expand on the feature set of the V3 API. You can find our complete V3 API documentation at https://v3.developer.constantcontact.com/ and the API Reference section will have all of the necessary schemas you can expect. You can make calls to our API in .NET using something like HttpClient with the information showing in our documentation.

Please let me know if you have any other questions!

David Bornstein
Tier II API Support Engineer

Constant Contact -- you really need a .net library for this.  For many of us, OAuth is insanely confusing and seems like a really odd choice for an API that is mostly used for internal tools (like uploading lists to Contact Contact) rather than a user-facing system.  It's great for Facebook but weird and unnecessarily complex for making IT-class apps.  For example, we use .net and we simply want a way to create lists and then bulk-add from CSV files.  Easy, right?  Is it possible to get a .net example, soup to nuts, for something like this where the app we're making an NOT a web app but simply a desktop app (WinForms or even Console is fine).  It needs to clearly show, just using native .net objects, how to authenticate (including getting an activation code) then calling the Create List and then Bulk Upload calls.  This really should be just a few lines of code.

Hey SteveP.   Did you ever get any response/feedback from CC on this?  Maybe it is just me....but they appear to totally clam up when queried about anything .NET related.  Especially when it involves a desktop/windows application.

Anyways....i wonder if you( or anybody ) have had success establishing the OAuth2.0 Server Flow?   I can get as far as the CC "Allow/Don't Allow" page...but nothing comes back to my app when clicking "Allow".  It doesn't navigate to my redirect, just stay on "Allow/Don't Allow"..  This is in a .Net windows app using the webBrowser control.   


What is your use case?  I am fighting the API to run "unattended" batch processes.  If yours is similar, I've gotten to the point where I can get an access token and create a list. But it requires I include a manual step to pull the code from the redirect url in order to get the access token.


I need to use the OAuth2.0 Server Flow.  This is a .NET windows application that uses a WebBrowser control during the OAuth processes.   The problem i am having is that our WebBrowser control does not receive the URL containing our Redirect and the Authorization Code that we could use to obtain an Access and Refresh token.  Ordinarily, we would parse the Authorization Code value from the URL in the WebBrowser's DocumentCompleted or even Navigated event.  But all we receive when the "Allow" button is clicked is "_javascript:void(0)".

If you are using the Server Flow and are able to obtain the Authorization Code, maybe you can message me your email and we can discuss via email?   


I don’t remember if I used server flow or what. I found the whole thing insanely confusing. I just know my code works as I used it about 20 times for doing Black Friday email blasts. One thing – you do NEED a public web server to get the code that CC sends back – ONCE! From there, you don’t need any web server and you can run things from a desktop app totally automated.


See my .aspx code for how to capture the first auth code. There is no need for a webcontrol.

"you do NEED a public web server to get the code that CC sends back"


Not necessarily.  I used https://localhost as my redirectURL.  It sends back the URL that I then paste into my browser.  It attempts to redirect to the localhost URL and fails (page cannot be found), but shows you the auth code in the "failing" URL


e.g.  https://localhost/?code=0zucYcwmhnq3EhCImXXXXXXXXXXXXXXXXXKTgEt



No, no help whatsoever from them about this.  But I did get something working.  In essence, you have to manually trigger the Auth ONCE then use a web page to capture the authentication code (once) then use that code in your desktop app where the desktop app uses that code OR the "refresh" token.  In fact, you only use the original token once then, from there on, you simply use the last refresh token. 


(note: the code below was modified by the CC post tool so HTML references may not be quite right)


In other words, the work flow is:


One time:

Write a one-time-use web page to capture the auth code response and store it somewhere, like in a DB.


Trigger an AUTH call manually via a web browser.  That calls the web page you wrote above and stores the original auth token.


Then, and you only have a few seconds to do this before the token expires, run a desktop app that reads the auth token and logins in.  This causes the system to send you back a Refresh token.


General use:

Once you have a refresh token, you're golden because you can login from the desktop with that.  Doing so provides a new refresh token for next use.


Some code, not all of which is relevant or complete but you'll get the idea.


ASPX page to capture the original auth and store it in a DB:


      Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If Not Page.IsPostBack Then
        End If
    End Sub
    Private Sub DoIt()
        Dim Code As String = ""
 If Not Request.Params.Item("code") Is Nothing Then
  Code  = Request.Params.Item("code").ToString()
 end if
 if code <>"" then
   dim SQL as string
   sql = "DELETE FROM NameValuePairs WHERE Category ='ConstantContact' AND KeyName = 'AuthorizationCode'"
   SQL = "INSERT INTO NameValuePairs (Category,KeyName,KeyValue) VALUES ('ConstantContact','AuthorizationCode','" + code + "')"
   txtEMail.text = code 'debug
         Catch ex As Exception
                 txtEMail.text = "An error occured while processing your request."
         End Try
  txtEMail.text = "no code"
 end if
 exit sub
    End Sub
Then … on the desktop side.....
    Private Const CCBaseURL As String = "https://api.cc.email/v3"
    Private Const CCAuthenticateURL As String = "https://idfed.constantcontact.com/as/token.oauth2?"
Private Function CCAuthorize() As Boolean
        Dim dn As New Downloader
        LogIt(gLogFile, "Gettting ConstantContact token...")
        Dim SQL As String = "SELECT * FROM NameValuePairs WHERE Category='ConstantContact'"
        Dim DS As DataSet = db.GetDataset(SQL)
        Dim AuthorizationCode As String = ""
        Dim r As Boolean = False
        Dim FileName As String = IO.Path.Combine(Helper.GetSrcXDrive, "SrcX\temp\" + NewGUID() + ".txt")
        If Database.IsDatasetValid(DS) Then
            For Each dr As DataRow In DS.Tables(0).Rows
                Select Case Helper.GetDBString(dr, "KeyName")
                    Case "AuthorizationCode"
                        AuthorizationCode = GetDBString(dr, "KeyValue")
                    Case "RefreshToken"
                        CCRefreshToken = GetDBString(dr, "KeyValue")
                End Select
        End If
        If CCRefreshToken <> "" Then
            'Great.  We'll use that.
            Dim URL As String = CCAuthenticateURL + "refresh_token=" + CCRefreshToken + "&grant_type=refresh_token"
            If CCGetAccessToken(URL, FileName) Then
                LogIt(gLogFile, "Gettting ConstantContact token OK")
                Return True
            End If
        End If
        'If RefreshFailed or was not provided...
        If AuthorizationCode <> "" Then
            'In theory, this should only be needed ONCE!
            Dim URL As String = CCAuthenticateURL + "code=" + AuthorizationCode + "&redirect_uri=" + CCRedirectURL + "&grant_type=authorization_code&scope=contact_data"
            If CCGetAccessToken(URL, FileName) Then
                LogIt(gLogFile, "Gettting ConstantContact token OK")
                Return True
            End If
        End If
        LogIt(gLogFile, "Gettting ConstantContact token FAILED")
        Return False
    End Function
    Private Function CCGetAccessToken(URL As String, FileName As String) As Boolean
        Dim DN As New Downloader
        Dim r As Boolean = False
        Dim SQL As String
        DN.URL = URL
        DN.FileName = FileName
        Dim credentials As String = CCAPIKey + ":" + CCSecret
        Dim plain As Byte() = System.Text.Encoding.UTF8.GetBytes(credentials)
        Dim base64cred As String = Convert.ToBase64String(plain)
        Dim base64auth As String = "Basic " + base64cred
        DN.Headers.Add("Authorization", base64auth)
        DN.ContentType = ""
        r = DN.DownloadFilePOST
        If r Then
            Dim dict As Dictionary(Of String, Object) = ReadJSON(FileName)
            CCAccessToken = dict("access_token").ToString
            CCRefreshToken = dict("refresh_token").ToString
            Catch ex As Exception
            End Try
            SQL = "DELETE FROM NameValuePairs WHERE Category='ConstantContact' AND KeyName='RefreshToken'"
            SQL = "INSERT INTO NameValuePairs (Category,KeyName,KeyValue) VALUES ('ConstantContact','RefreshToken','" + CCRefreshToken + "')"
        End If
        Return r
    End Function

Hey Steve;

very nice....thank you!   i'm aware that i can also use Postman to get Authorization Code and then the Access and Refresh tokens.   And i would be fine doing it that way.   But the integration to CC is part of our software.  So, any number of our Users will have to go through the process to grant our app access to their CC accounts.  Thus the need for the more 'traditional' UI.  Or maybe i am missing something?   Thanks again.

Basically what puzzles me is this:   if i use the Client Flow, clicking "Allow" redirects to our page and the URL has the Access Token embedded in it.    But, using the Server Flow, the redirect doesn't occur.  So we cannot get the Auth Code.    And they tell me it is a browser issue.  But in one instance it works.  In the other it does not.

You may be able to automated that if you make the user simply go to some web  page you create (once) and use a modified version of the code I posted to store auth and refresh tokens on a per-user basis rather than globally, as I do.

Regular Participant

Has anyone got this to work in an unattended process? The only OAuth flows they provide appear to require user interaction to get the code, which completely eliminates batch jobs that run at 1AM to upload contacts and send out emails. Or am I missing something?

You only need to do the manual process once.  From then on, it works without any further manual interaction. 


Step 1 (manual-one time):  Call the URL to get an authorization code.  I have it respond to local host, which errors, but you can get the authorization code from the response URL:  



Step 2 (only necessary the first time):  Calls return both an authorization code and a refresh_token.  Save the refresh_token in a file and use the authorization code for any API calls:   

https://idfed.constantcontact.com/as/token.oauth2?code=' + self.authorization_code + '&redirect_uri=https://localhost&grant_type=authorization_code


Step 3:  Get a new authorization code and refresh_token (saving to a file) once the authorization_code from step 2 expires:  

https://idfed.constantcontact.com/as/token.oauth2?refresh_token=' + refresh_token + '&grant_type=refresh_token



So, I do step 1 and step 2 once.

I do step 3 every time I run my app from then on.


(Note, It's been several months since I last worked on my code, so I hope I've responded accurately). 

Regular Participant

Doesn't work unfortunately. I am able to get a authorization code / refresh token interactively using both the browser and postman. But I am unable to do it from my program.


Our program only runs once every few days, and the token retrieved would have expired long before I would be able to use it.


Unless Refresh tokens live forever?

the refresh token is long lived.   use it, it is going to work in getting you the next pair of auth code/ refresh token

Yes.  The RefreshToken is what you use as it lives forever ... or so it seems.  Simply be sure to ask for and store the new RefreshToken for use next time.

Developer Portal

View API documentation, code samples, get your API key.

Visit Page


API Updates

Join our list to be notified of new features and updates to our V3 API.

Sign Up