V3 - Starter .NET Project

MetroMattress
Campaign Contributor

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?

15 REPLIES 15
David_B.
Employee
0 Votes

Hello,

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!

Regards,
David Bornstein
Tier II API Support Engineer

SteveP245
Marketing Legend

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.

raleighb3
Marketing Legend
0 Votes

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.   

FirstNameL86527
Campaign Expert
0 Votes

Raleigh,

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.

raleighb3
Marketing Legend
0 Votes

Hi;

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?   

Thanks.

SteveP245
Marketing Legend
0 Votes

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.

FirstNameL86527
Campaign Expert

"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

SteveP245
Marketing Legend

Hi,

 

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
                Doit()
        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
         OpenConnection()
  try
   dim SQL as string
   sql = "DELETE FROM NameValuePairs WHERE Category ='ConstantContact' AND KeyName = 'AuthorizationCode'"
   executeSQL(sql)
   SQL = "INSERT INTO NameValuePairs (Category,KeyName,KeyValue) VALUES ('ConstantContact','AuthorizationCode','" + code + "')"
   executeSQL(sql)
   txtEMail.text = code 'debug
   
         Catch ex As Exception
                 txtEMail.text = "An error occured while processing your request."
  finally
                 Con.Close()
         End Try
 else
  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
            Next
        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
            'cleanup
            Try
                IO.File.Delete(DN.FileName)
            Catch ex As Exception
            End Try
            SQL = "DELETE FROM NameValuePairs WHERE Category='ConstantContact' AND KeyName='RefreshToken'"
            db.ExecuteSQL(SQL)
            SQL = "INSERT INTO NameValuePairs (Category,KeyName,KeyValue) VALUES ('ConstantContact','RefreshToken','" + CCRefreshToken + "')"
            db.ExecuteSQL(SQL)
        End If
        Return r
    End Function
 
raleighb3
Marketing Legend
0 Votes

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.

SteveP245
Marketing Legend
0 Votes

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.

ARRT
Campaign Collaborator
0 Votes

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?

FirstNameL86527
Campaign Expert

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:  

https://api.cc.email/v3/idfed?client_id=<redacted>&redirect_uri=https%3A%2F%2Flocalhost&response_type=code&scope=account_read+account_update+contact_data

 

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). 

ARRT
Campaign Collaborator
0 Votes

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?

raleighb3
Marketing Legend

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

SteveP245
Marketing Legend
0 Votes

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.

Resources
Developer Portal

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

Visit Page

Announcements

API Updates

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

Sign Up