Skip navigation

Code It

6 Posts authored by: Lou Patrick

The Eloqua Release 18D New Feature Summary is now available - Eloqua Release 18D New Feature Summary.

 

Here is an exert of all the Developer Updates:

NEW FEATURES

 

Application API

  • You can now use the Landing Pages Application API 2.0 endpoints to create, update, retrieve, and delete landing pages.
  • You can now use the Forms Application API 2.0 endpoints to create, update, retrieve, and delete forms.
  • You can now use the Form Data Application API 2.0 endpoints to create, retrieve, and delete form data.

 

PLATFORM NOTICES

 

App Developer Framework

  • There is now a Scheduling option available for app action steps on Campaign and Program Canvases. If a user sets certain days and hours under Scheduling, records that enter the step outside of the selected days and hours, will remain in an “Awaiting action” status until within the selected days and hours, at which time the Notification URL call will then be sent to the app.
  • The ability to mark forms as internal so that form submissions are dropped, will be in Controlled Availability in Eloqua Release 18D and 19A. This feature includes the addition of a new property to Form API endpoints. You can request access to this feature by submitting a request to My Oracle Support.
  • Oracle Eloqua will be deprecating TLS 1.1 on January 18, 2019. Learn more

 

RECENT CHANGES

 

Authentication

  • Resolved an issue where calls to Eloqua's OAuth 2.0 token endpoint would return an empty response body if there was an error with the request. Error requests made to Eloqua's OAuth 2.0 token endpoint will now return a detailed message. The token endpoint is https://login.eloqua.com/auth/oauth2/token.
  • We modified the Eloqua OAuth 2.0 authorization flow initiation to only accept one initiation per minute for any given user of an app. For more information, see the product notice on Topliners.

 

Application API

  • The processingStepErrors property has been added to the response to submitting a form using the Application 1.0 and 2.0endpoints. This property was previously in Early Preview status in Release 18C. This property provides more detailed information about form processing step errors. For more information, see the product notice on Topliners.
  • A new form field validation property has been added to the Application 2.0 Form endpoints called PreventXSSCondition. This field validation is being added to prevent form data from being saved if HTML is present in a field. For more information, see the product notice on Topliners.
  • The requirement property has been added to the response when submitting form data with invalid values using the Application 1.0 and 2.0 endpoints. This property provides more information about invalid form data being submitted to a form field. See the Eloqua Help Center for more information about form field validation.
  • Resolved an issue where a campaign import could modify the end date of a campaign that is Completed or Active, causing campaigns to end before the intended end date. Campaign imports will no longer be able to modify the end date of campaigns that are Completed or Active.
  • As mentioned in the Eloqua 18C changelog, the resendLimit property introduced in 18A was removed from the processingSteps type FormStepSendEmail for Application API Form endpoints. For more information, see the product notice on Topliners.
  • As mentioned in the Eloqua 18C changelog, the Create an external activity Application API endpoint will no longer create External Asset Types or External Activity Types if they do not exist. A new Action Permission, "Register External Activities", is required to use the Create an external activity Application API endpoint. Learn more

 

Bulk API

  • You can now include Contact.Id for Bounceback, Subscribe, and Unsubscribe activity export definitions. This enhancement enables developers to include Contact.Id on export definitions for all activity types.
  • You can now include user fields for EmailOpen, EmailClickthrough, and EmailSend activity export definitions. One use case this enhancement enables, is allowing including sender and user attributes on email activities exported via the Bulk API, so that the activity can be properly assigned to the correct user in CRM. Discover user fields using the Retrieve a list of user fields endpoint: GET /api/Bulk/2.0/users/fields. User fields can be added with the following statement: {{Activity.User.Field(<Field Name>)}}

With the Oracle Eloqua 18B release Opportunities are being added to the Bulk API. I am going to walk-through an end to end scenario with examples, but before I do that here are some of the highlights:

  • Opportunity fields will be discoverable via the Bulk API
  • There are two sets of endpoints, one set to import Opportunities, and the other set to link Opportunities to Contacts
  • Opportunities can be linked directly to Contacts, or via Accounts

 

With the key takeaways highlighted, let's now take a look at this new functionality in action. I'm going to walk-through discovering Opportunity fields, using those fields to import Opportunities, and completing the scenario by linking the Opportunities to Contacts. Along the way we'll cover some requirements and notes as well.

 

Let's start by retrieving Opportunity fields:

 

     Request

GET /api/Bulk/2.0/opportunities/fields

     Response

{

    "items": [

        {

            "name": "Opportunity ID",

            "internalName": "RemoteOpportunityID",

            "dataType": "string",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": true,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Id}}",

            "uri": "/opportunities/fields/38"

        },

        {

            "name": "Opportunity Name",

            "internalName": "OpportunityName",

            "dataType": "string",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": true,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(Name)}}",

            "uri": "/opportunities/fields/39"

        },

        {

            "name": "Created Date",

            "internalName": "CreatedDate",

            "dataType": "date",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": true,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.CreatedAt}}",

            "uri": "/opportunities/fields/40"

        },

        {

            "name": "Stage",

            "internalName": "OpportunityStageID",

            "dataType": "string",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": true,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(Stage)}}",

            "uri": "/opportunities/fields/41"

        },

        {

            "name": "Amount",

            "internalName": "OpportunityAmount",

            "dataType": "number",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": true,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(Amount)}}",

            "uri": "/opportunities/fields/42"

        },

        {

            "name": "Currency",

            "internalName": "OpportunityCurrencyID",

            "dataType": "string",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": false,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(Currency)}}",

            "uri": "/opportunities/fields/43"

        },

        {

            "name": "Close Date",

            "internalName": "CloseDate",

            "dataType": "date",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": false,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(CloseDate)}}",

            "uri": "/opportunities/fields/44"

        },

        {

            "name": "Forecast To Close Date",

            "internalName": "ForecastToCloseDate",

            "dataType": "date",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": false,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(ForecastToCloseDate)}}",

            "uri": "/opportunities/fields/45"

        },

        {

            "name": "Account Name",

            "internalName": "AccountName",

            "dataType": "string",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": false,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(AccountName)}}",

            "uri": "/opportunities/fields/46"

        },

        {

            "name": "Territory",

            "internalName": "Territory",

            "dataType": "string",

            "hasReadOnlyConstraint": false,

            "hasNotNullConstraint": false,

            "hasUniquenessConstraint": false,

            "statement": "{{Opportunity.Field(Territory)}}",

            "uri": "/opportunities/fields/47"

        }

    ],

    "totalResults": 10,

    "limit": 1000,

    "offset": 0,

    "count": 10,

    "hasMore": false

}

 

Now that we have the statements for the Opportunity fields, let's create an Opportunity import definition:

 

Before creating the definition, here are some requirements for the Opportunity import definition:

  • The following fields are required:
    • {{Opportunity.Id}}

    • {{Opportunity.Field(Name)}}

    • {{Opportunity.Field(Stage)}}

    • {{Opportunity.Field(Amount)}}

  • The identifierFieldName must be set to the {{Opportunity.Id}} field within fields

 

     Request

POST /api/Bulk/2.0/opportunities/imports

Content-Type: application/json

     Request - Body

{

  "name": "Opportunity Import",

  "fields": {

    "OpportunityID": "{{Opportunity.Id}}",

    "OpportunityName": "{{Opportunity.Field(Name)}}",

    "AccountName": "{{Opportunity.Field(AccountName)}}",

    "CreatedDate": "{{Opportunity.CreatedAt}}",

    "Amount": "{{Opportunity.Field(Amount)}}",

    "CloseDate": "{{Opportunity.Field(CloseDate)}}",

    "Currency": "{{Opportunity.Field(Currency)}}",

    "ForecastToCloseDate": "{{Opportunity.Field(ForecastToCloseDate)}}",

    "Stage": "{{Opportunity.Field(Stage)}}",

    "Territory": "{{Opportunity.Field(Territory)}}"

  },

  "identifierFieldName": "OpportunityID",

  "isIdentifierFieldCaseSensitive": false,

  "isSyncTriggeredOnImport": true

}

     Response

201 Created

{

    "isIdentifierFieldCaseSensitive": false,

    "name": "Opportunity Import",

    "fields": {

        "OpportunityID": "{{Opportunity.Id}}",

        "OpportunityName": "{{Opportunity.Field(Name)}}",

        "AccountName": "{{Opportunity.Field(AccountName)}}",

        "CreatedDate": "{{Opportunity.CreatedAt}}",

        "Amount": "{{Opportunity.Field(Amount)}}",

        "CloseDate": "{{Opportunity.Field(CloseDate)}}",

        "Currency": "{{Opportunity.Field(Currency)}}",

        "ForecastToCloseDate": "{{Opportunity.Field(ForecastToCloseDate)}}",

        "Stage": "{{Opportunity.Field(Stage)}}",

        "Territory": "{{Opportunity.Field(Territory)}}"

    },

    "identifierFieldName": "OpportunityID",

    "isSyncTriggeredOnImport": true,

    "dataRetentionDuration": "P7D",

    "uri": "/opportunities/imports/18819",

    "createdBy": "API.User",

    "createdAt": "2018-04-30T18:05:26.9420890Z",

    "updatedBy": "API.User",

    "updatedAt": "2018-04-30T18:05:26.9420890Z"

}

 

Now that we have our definition created we can upload data to the definition:

 

     Request

POST /api/Bulk/2.0/opportunities/imports/18819/data

Content-Type: application/json

     Request - Body

[

  {

    "OpportunityID": "1ABC",

    "OpportunityName": "ABC Company",

    "AccountName": "ABC",

    "CreatedDate": "2018-04-15 1:15",

    "Amount": "1000000",

    "CloseDate": "",

    "Currency": "USD",

    "ForecastToCloseDate": "",

    "Stage": "Prospecting",

    "Territory": "West"

  },

  {

    "OpportunityID": "2XYZ",

    "OpportunityName": "XYZ Company",

    "AccountName": "XYZ",

    "CreatedDate": "2018-04-18 5:10",

    "Amount": "1000000",

    "CloseDate": "",

    "Currency": "USD",

    "ForecastToCloseDate": "",

    "Stage": "Prospecting",

    "Territory": "West"

  }

]

     Response

201 Created

{

    "syncedInstanceUri": "/opportunities/imports/18819",

    "status": "pending",

    "createdAt": "2018-04-30T18:19:51.4928305Z",

    "createdBy": "EveryOne.Tests",

    "uri": "/syncs/27418"

}

As I knew I could upload all data in one request to the data endpoint, I set the isSyncTriggeredOnImport property to true, so the response to the data upload is the created sync. Now I'll retrieve the sync logs to confirm the Opportunities were created:

 

     Request

GET /api/Bulk/2.0/syncs/27418/logs

     Response

{

    "items": [

        {

            "syncUri": "/syncs/27418",

            "count": 2,

            "severity": "information",

            "statusCode": "ELQ-00130",

            "message": "Total records staged for import.",

            "createdAt": "2018-04-30T18:19:53.5400000Z"

        },

        {

            "syncUri": "/syncs/27418",

            "count": 0,

            "severity": "information",

            "statusCode": "ELQ-00137",

            "message": "Ready for data import processing.",

            "createdAt": "2018-04-30T18:19:53.5530000Z"

        },

        {

            "syncUri": "/syncs/27418",

            "count": 0,

            "severity": "information",

            "statusCode": "ELQ-00101",

            "message": "Sync processed for sync , resulting in Success status.",

            "createdAt": "2018-04-30T18:20:56.0730000Z"

        },

        {

            "syncUri": "/syncs/27418",

            "count": 2,

            "severity": "information",

            "statusCode": "ELQ-00001",

            "message": "Total records processed.",

            "createdAt": "2018-04-30T18:19:53.0800000Z"

        },

        {

            "syncUri": "/syncs/27418",

            "count": 2,

            "severity": "information",

            "statusCode": "ELQ-00041",

            "message": "Opportunities created.",

            "createdAt": "2018-04-30T18:19:57.0530000Z"

        },

        {

            "syncUri": "/syncs/27418",

            "count": 0,

            "severity": "information",

            "statusCode": "ELQ-00042",

            "message": "Opportunities updated.",

            "createdAt": "2018-04-30T18:19:57.0530000Z"

        }

    ],

    "totalResults": 6,

    "limit": 1000,

    "offset": 0,

    "count": 6,

    "hasMore": false

}

With the count of 2 for the message "Opportunities created." I know the Opportunities in the data upload were successfully imported. If you'd like to see the Opportunities in Eloqua, follow these instructions. To be sure, I searched in Eloqua for the Opportunities I uploaded:

 

Now that we have Opportunities created in Eloqua, let's create an Opportunity Contact linkage import definition to link them to Contacts:

 

Before creating the definition, here are some requirements and notes for the Opportunity Contact linkage import definition:

  • The {{Opportunity.Id}} field is required within fields
  • At least one Contact or Account field is required within fields
  • For linking by Account, the Account field set for Account Linkage must be used to match
  • There is a maximum of two fields allowed
  • identifierFieldName is a read only field set to the linkOpportunitiesMatchFieldName value, and should not specified in definition

 

     Request

POST /api/bulk/2.0/opportunities/contacts/imports

Content-Type: application/json

     Request - Body

{

  "name": "Opportunity Contact Linkage Import",

  "fields": {

    "EmailAddress": "{{Opportunity.Contact.Field(C_EmailAddress)}}",

    "OpportunityID": "{{Opportunity.Id}}"

  },

  "linkOpportunitiesCaseSensitiveMatchField": false,

  "linkOpportunitiesCaseSensitiveSourceField": false,

  "linkOpportunitiesEntityType": "Contact",

  "linkOpportunitiesMatchFieldName": "OpportunityID",

  "linkOpportunitiesMultipleSourceMatches": true,

  "linkOpportunitiesSourceField": "EmailAddress",

  "isSyncTriggeredOnImport": true

}

     Response

201 Created

{

    "linkOpportunitiesMatchFieldName": "OpportunityID",

    "linkOpportunitiesSourceField": "EmailAddress",

    "linkOpportunitiesEntityType": "Contact",

    "linkOpportunitiesCaseSensitiveSourceField": false,

    "linkOpportunitiesCaseSensitiveMatchField": false,

    "linkOpportunitiesMultipleSourceMatches": true,

    "name": "Opportunity Contact Linkage Import",

    "fields": {

        "EmailAddress": "{{Opportunity.Contact.Field(C_EmailAddress)}}",

        "OpportunityID": "{{Opportunity.Id}}"

    },

    "identifierFieldName": "OpportunityID",

    "isSyncTriggeredOnImport": true,

    "dataRetentionDuration": "P7D",

    "uri": "/opportunities/contacts/imports/18820",

    "createdBy": "API.User",

    "createdAt": "2018-04-30T19:15:39.6474055Z",

    "updatedBy": "API.User",

    "updatedAt": "2018-04-30T19:15:39.6474055Z"

}

In our import definition, we are stating that we want to link Contacts by their email address to specific Opportunities, by OpportunityID. Once documentation is published, I will provide a link here. (Documentation now published: API documentation and tutorial) In the mean time, here are descriptions for all the new properties:

 

PropertyTypeDescription
linkOpportunitiesCaseSensitiveMatchFieldbooleanWhether or not to perform a case sensitive search on the match field.
linkOpportunitiesCaseSensitiveSourceFieldbooleanWhether or not to perform a case sensitive search on the source field.
linkOpportunitiesEntityTypestringSpecifies the entity of the contact linkage import. Allowed values are "Contact" or "Account".
linkOpportunitiesMatchFieldNamestringSpecifies the field name for matching.
linkOpportunitiesMultipleSourceMatchesbooleanWhether or not imported data will be mapped to multiple matching records.
linkOpportunitiesSourceFieldstringSpecifies the source field name for matching.

 

Now that we have our definition created we can upload data to the definition to link Opportunities to Contacts:

 

Note: All Contacts were confirmed created prior to upload, except "notacontact@xyzcompany.com", to demonstrate what happens if the Contact does not exist.

 

     Request

POST /api/Bulk/2.0/opportunities/contacts/imports/18820/data

Content-Type: application/json

     Request - Body

[

  {

    "OpportunityID": "1ABC",

    "EmailAddress": "contact@abccompany.com"

  },

  {

    "OpportunityID": "1ABC",

    "EmailAddress": "contact2@abccompany.com"

  },

  {

    "OpportunityID": "2XYZ",

    "EmailAddress": "contact@xyzcompany.com"

  },

  {

    "OpportunityID": "2XYZ",

    "EmailAddress": "notacontact@xyzcompany.com"

  }

]

     Response

{

    "syncedInstanceUri": "/opportunities/contacts/imports/18820",

    "status": "pending",

    "createdAt": "2018-04-30T19:47:34.6272339Z",

    "createdBy": "API.User",

    "uri": "/syncs/27421"

}

As I knew I could upload all data in one request to the data endpoint, I set the isSyncTriggeredOnImport property to true, so the response to the data upload is the created sync. Now I'll retrieve the sync logs to confirm the Opportunities were linked:

 

     Request

GET /api/Bulk/2.0/syncs/27421/logs

     Response

{

    "items": [

        {

            "syncUri": "/syncs/27421",

            "count": 4,

            "severity": "information",

            "statusCode": "ELQ-00130",

            "message": "Total records staged for import.",

            "createdAt": "2018-04-30T19:48:03.0570000Z"

        },

        {

            "syncUri": "/syncs/27421",

            "count": 0,

            "severity": "information",

            "statusCode": "ELQ-00137",

            "message": "Ready for data import processing.",

            "createdAt": "2018-04-30T19:48:03.0800000Z"

        },

        {

            "syncUri": "/syncs/27421",

            "count": 0,

            "severity": "information",

            "statusCode": "ELQ-00101",

            "message": "Sync processed for sync , resulting in Warning status.",

            "createdAt": "2018-04-30T19:48:32.6700000Z"

        },

        {

            "syncUri": "/syncs/27421",

            "count": 4,

            "severity": "information",

            "statusCode": "ELQ-00001",

            "message": "Total records processed.",

            "createdAt": "2018-04-30T19:48:02.3930000Z"

        },

        {

            "syncUri": "/syncs/27421",

            "count": 1,

            "severity": "warning",

            "statusCode": "ELQ-00085",

            "message": "Contact does not exist.",

            "createdAt": "2018-04-30T19:48:07.9070000Z"

        },

        {

            "syncUri": "/syncs/27421",

            "count": 3,

            "severity": "information",

            "statusCode": "ELQ-00058",

            "message": "Opportunities mapped to contacts.",

            "createdAt": "2018-04-30T19:48:07.9070000Z"

        }

    ],

    "totalResults": 6,

    "limit": 1000,

    "offset": 0,

    "count": 6,

    "hasMore": false

}

As expected we see a count of 3 with the message of "Opportunities mapped to contacts.", and a count of 1 with the message "Contact does not exist." Now to see the details on which record referenced a Contact that did not exist I make a request to the rejects endpoint:

 

     Request

GET /api/Bulk/2.0/syncs/27421/rejects

     Response

{

    "items": [

        {

            "fieldValues": {

                "EmailAddress": "notacontact@xyzcompany.com",

                "OpportunityID": "2XYZ"

            },

            "message": "Contact does not exist.",

            "statusCode": "ELQ-00085",

            "recordIndex": 4,

            "invalidFields": []

        }

    ],

    "totalResults": 1,

    "limit": 1000,

    "offset": 0,

    "count": 1,

    "hasMore": false

}

As expected we see notacontact@xyzcompany.com appear with the message "Contact does not exist." If an Opportunity doesn't exist the message is "Opportunity does not exist." with a statusCode of "ELQ-00084".

 

We've retrieved Opportunity fields, used those fields to import Opportunities, then completed the scenario by linking the Opportunities to Contacts, and with that we've completed the walk-through of the Opportunities endpoints coming to the Bulk API.

 

When will I receive the 18B release? Visit the Oracle Eloqua Release Center to view roll out dates.

 

How about documentation? On May 18, 2018, the applicable Oracle Eloqua Developer Help Center reference and tutorial pages will be published. (Documentation now published: API documentation and tutorial)

 

Interested in more related to the 18B release?

With the Oracle Eloqua 491 release, Contact fields will be available on all Bulk API activity exports, and a Dream will be partially implemented with SMTP fields being added to Bulk API hard Bounceback exports.

 

Contact Fields on Bulk API Activity Exports

  • Up to 10 Contact fields will be available to add in an activity export definition
    • If more than 10 Contact fields are included, Eloqua will respond with a 400 validation error
    • There should be an expected addition to export time when adding Contact fields to an activity export
  • Any Contact field returned via the Retrieve a list of contact field definitions endpoint will be available
  • Including Contact fields on activity exports enables two common fields for matching activities to Contacts to be available for all activity types: Contact ID Ext and Email Address
  • Contact attributes (e.g. Id) and special fields (e.g. IsBounced, IsSbuscribed, Format) are not available with this addition
    • We are planning to add Contact Id to the remaining activity types it's not currently available (Subscribe, Unsubscribe, Bounceback) in the future
    • There are no plans to add special fields, if there are use cases for these fields, please share
  • The syntax for a Contact field statement in a Bulk API activity export definition will be:
{{Activity.Contact.Field(<contact_field_name>)}}
  • Example Email Open activity export definition with a Contact field:

POST /api/bulk/2.0/activities/exports

{

  "filter": "'{{Activity.Type}}'='EmailOpen'",

  "name": "Bulk Activity Export - Email Open",

  "fields": {

    "ActivityId": "{{Activity.Id}}",

    "ActivityType": "{{Activity.Type}}",

    "ActivityDate": "{{Activity.CreatedAt}}",

    "ContactId": "{{Activity.Contact.Id}}",

    "IpAddress": "{{Activity.Field(IpAddress)}}",

    "VisitorId": "{{Activity.Visitor.Id}}",

    "VisitorExternalId": "{{Activity.Visitor.ExternalId}}",

    "EmailRecipientId": "{{Activity.Field(EmailRecipientId)}}",

    "AssetType": "{{Activity.Asset.Type}}",

    "AssetName": "{{Activity.Asset.Name}}",

    "AssetId": "{{Activity.Asset.Id}}",

    "SubjectLine": "{{Activity.Field(SubjectLine)}}",

    "EmailWebLink": "{{Activity.Field(EmailWebLink)}}",

    "CampaignId": "{{Activity.Campaign.Id}}",

    "ExternalId": "{{Activity.ExternalId}}",

    "DeploymentId": "{{Activity.Field(EmailDeploymentId)}}",

    "EmailSendType": "{{Activity.Field(EmailSendType)}}",

    "EmailAddress": "{{Activity.Field(EmailAddress)}}",

    "ContactIdExt": "{{Activity.Contact.Field(ContactIDExt)}}"

  }

}

 

SMTP Fields on Bulk API Hard Bounceback Exports

 

Here is an example Bounceback export definition as a preview of the field statements:

POST /API/Bulk/2.0/activities/exports

{

  "filter": "'{{Activity.Type}}'='Bounceback'",

  "name": "Bulk Activity Export - Bounceback",

  "fields": {

    "ActivityId": "{{Activity.Id}}",

    "ActivityType": "{{Activity.Type}}",

    "ActivityDate": "{{Activity.CreatedAt}}",

    "EmailAddress": "{{Activity.Field(EmailAddress)}}",

    "AssetType": "{{Activity.Asset.Type}}",

    "AssetName": "{{Activity.Asset.Name}}",

    "AssetId": "{{Activity.Asset.Id}}",

    "CampaignId": "{{Activity.Campaign.Id}}",

    "ExternalId": "{{Activity.ExternalId}}",

    "EmailRecipientId":"{{Activity.Field(EmailRecipientId)}}",

    "DeploymentId": "{{Activity.Field(EmailDeploymentId)}}",

    "SmtpErrorCode": "{{Activity.Field(SmtpErrorCode)}}",

    "SmtpStatusCode": "{{Activity.Field(SmtpStatusCode)}}",

    "SmtpMessage": "{{Activity.Field(SmtpMessage)}}"

  }

}

 

SMTP Activity field details:

Field typeData typeMax lengthDescription
{{Activity.Field(SmtpErrorCode)}}String9The SMTP Status Code for the email bounceback.
{{Activity.Field(SmtpStatusCode)}}String3The SMTP Response Code for the email bounceback.
{{Activity.Field(SmtpMessage)}}String510The SMTP message for the email bounceback.

And one more addition! In the above Bounceback example export definition, there are two additional fields available: EmailRecipientId and EmailDeploymentId. These fields enable tying a hard Bounceback to an email send.

 

When will I receive the 491 release? Visit the Oracle Eloqua Release Center to view roll out dates.

 

How about documentation? When version 491 is rolled out to POD2, the applicable Oracle Eloqua Developer Help Center reference and tutorial pages will be updated.

 

Interested in more related to the 491 release? When version 491 is rolled out to POD2:

I was recently asked if you could build an Eloqua Campaign including the steps using the REST API. The Developer Help Center includes details and an example on creating an Eloqua Campaign using this REST 2.0 API endpoint - POST /assets/campaign; however, there are not details for creating the steps, which can be done using the elements array, within the Request parameters tab or within the Example. We are in the process of updating our documentation to indicate all the Request parameters and include a more extensive Example.

 

While our official documentation is being updated, I wanted to provide an example to demonstrate creating an Eloqua Campaign including the steps using the REST 2.0 API endpoint - POST /assets/campaign. Here is a screenshot of the resulting Eloqua Campaign created using the REST API Request below:

create_campaign_example.png

 

Request

POST /API/REST/2.0/assets/campaign

 

Request - Body

{

  "name": "API Example Campaign",

  "elements": [

    {

      "type": "CampaignSegment",

      "id": "-1",

      "name": "Segment members",

      "segmentId": "2",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "connectedId": "-2",

          "connectedType": "CampaignWaitAction",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "39"

      },

      "isFinished": "false",

      "isRecurring": "false"

    },

    {

      "type": "CampaignWaitAction",

      "id": "-2",

      "name": "Wait",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "connectedId": "-3",

          "connectedType": "CampaignEmail",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "131"

      },

      "waitFor": "3600"

    },

    {

      "type": "CampaignEmail",

      "emailId": "98",

      "id": "-3",

      "name": "Email 1",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "connectedId": "-4",

          "connectedType": "CampaignWaitAction",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "222"

      },

      "includeListUnsubscribeHeader": "false",

      "isAllowingResend": "false",

      "isAllowingSentToMasterExclude": "false",

      "isAllowingSentToUnsubscribe": "false",

      "sendTimePeriod": "sendAllEmailAtOnce"

    },

    {

      "type": "CampaignWaitAction",

      "id": "-4",

      "name": "Wait",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "connectedId": "-5",

          "connectedType": "CampaignEmail",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "316"

      },

      "waitFor": "259200"

    },

    {

      "type": "CampaignEmail",

      "emailId": "99",

      "id": "-5",

      "name": "Email 2",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "connectedId": "-6",

          "connectedType": "CampaignMoveToContactListAction",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "409"

      },

      "includeListUnsubscribeHeader": "true",

      "isAllowingResend": "false",

      "isAllowingSentToMasterExclude": "false",

      "isAllowingSentToUnsubscribe": "false",

      "sendTimePeriod": "sendAllEmailAtOnce"

    },

    {

      "type": "CampaignEmailClickthroughRule",

      "emailId": "99",

      "id": "-6",

      "name": "Clicked Email?",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "-7",

          "connectedId": "-9",

          "connectedType": "CampaignMoveToContactListAction",

          "terminalType": "no"

        },

        {

          "type": "CampaignOutputTerminal",

          "id": "-8",

          "connectedId": "-10",

          "connectedType": "CampaignMoveToContactListAction",

          "terminalType": "yes"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "497"

      },

      "evaluateNoAfter": "604800",

      "numberOfClicks": "1",

      "withinLast": "604800"

    },

    {

      "type": "CampaignMoveToContactListAction",

      "listId": "64",

      "id": "-9",

      "name": "Move to Shared List 1",

      "position": {

        "type": "Position",

        "x": "233",

        "y": "614"

      }

    },

    {

      "type": "CampaignMoveToContactListAction",

      "listId": "65",

      "id": "-10",

      "name": "Move to Shared List 2",

      "position": {

        "type": "Position",

        "x": "503",

        "y": "614"

      }

    }

  ]

}

 

Response

{

  "type": "Campaign",

  "currentStatus": "Draft",

  "id": "22",

  "createdAt": "1463284937",

  "createdBy": "11",

  "depth": "complete",

  "folderId": "308",

  "name": "API Example Campaign",

  "permissions": [

    "Retrieve",

    "SetSecurity",

    "Delete",

    "Update",

    "Activate"

  ],

  "updatedAt": "1463284937",

  "updatedBy": "11",

  "elements": [

    {

      "type": "CampaignSegment",

      "id": "337",

      "initialId": "-1",

      "name": "Segment members",

      "memberCount": "0",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "320",

          "connectedId": "338",

          "connectedType": "CampaignWaitAction",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "39"

      },

      "isFinished": "false",

      "isRecurring": "false",

      "segmentId": "2"

    },

    {

      "type": "CampaignWaitAction",

      "id": "338",

      "initialId": "-2",

      "name": "Wait",

      "memberCount": "0",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "321",

          "connectedId": "339",

          "connectedType": "CampaignEmail",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "131"

      },

      "waitFor": "3600"

    },

    {

      "type": "CampaignEmail",

      "id": "339",

      "initialId": "-3",

      "name": "Email 1",

      "memberCount": "0",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "322",

          "connectedId": "340",

          "connectedType": "CampaignWaitAction",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "222"

      },

      "emailId": "98",

      "includeListUnsubscribeHeader": "false",

      "isAllowingResend": "false",

      "isAllowingSentToMasterExclude": "false",

      "isAllowingSentToUnsubscribe": "false",

      "sendTimePeriod": "sendAllEmailAtOnce"

    },

    {

      "type": "CampaignWaitAction",

      "id": "340",

      "initialId": "-4",

      "name": "Wait",

      "memberCount": "0",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "323",

          "connectedId": "341",

          "connectedType": "CampaignEmail",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "316"

      },

      "waitFor": "259200"

    },

    {

      "type": "CampaignEmail",

      "id": "341",

      "initialId": "-5",

      "name": "Email 2",

      "memberCount": "0",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "324",

          "connectedId": "342",

          "connectedType": "CampaignEmailClickthroughRule",

          "terminalType": "out"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "409"

      },

      "emailId": "99",

      "includeListUnsubscribeHeader": "true",

      "isAllowingResend": "false",

      "isAllowingSentToMasterExclude": "false",

      "isAllowingSentToUnsubscribe": "false",

      "sendTimePeriod": "sendAllEmailAtOnce"

    },

    {

      "type": "CampaignEmailClickthroughRule",

      "id": "342",

      "initialId": "-6",

      "name": "Clicked Email?",

      "memberCount": "0",

      "outputTerminals": [

        {

          "type": "CampaignOutputTerminal",

          "id": "325",

          "initialId": "-7",

          "connectedId": "343",

          "connectedType": "CampaignMoveToContactListAction",

          "terminalType": "no"

        },

        {

          "type": "CampaignOutputTerminal",

          "id": "326",

          "initialId": "-8",

          "connectedId": "344",

          "connectedType": "CampaignMoveToContactListAction",

          "terminalType": "yes"

        }

      ],

      "position": {

        "type": "Position",

        "x": "365",

        "y": "497"

      },

      "emailId": "99",

      "evaluateNoAfter": "604800",

      "numberOfClicks": "1",

      "withinLast": "604800"

    },

    {

      "type": "CampaignMoveToContactListAction",

      "id": "343",

      "initialId": "-9",

      "name": "Move to Shared List 1",

      "memberCount": "0",

      "position": {

        "type": "Position",

        "x": "233",

        "y": "614"

      },

      "listId": "64"

    },

    {

      "type": "CampaignMoveToContactListAction",

      "id": "344",

      "initialId": "-10",

      "name": "Move to Shared List 2",

      "memberCount": "0",

      "position": {

        "type": "Position",

        "x": "503",

        "y": "614"

      },

      "listId": "65"

    }

  ],

  "isReadOnly": "false",

  "actualCost": "0",

  "budgetedCost": "0",

  "campaignCategory": "contact",

  "campaignType": "",

  "fieldValues": [

    {

      "type": "FieldValue",

      "id": "4",

      "value": ""

    },

    {

      "type": "FieldValue",

      "id": "5",

      "value": ""

    },

    {

      "type": "FieldValue",

      "id": "6",

      "value": ""

    },

    {

      "type": "FieldValue",

      "id": "7",

      "value": ""

    }

  ],

  "isEmailMarketingCampaign": "false",

  "isIncludedInROI": "false",

  "isMemberAllowedReEntry": "false",

  "isSyncedWithCRM": "false",

  "product": "",

  "region": ""

}

 

If you've made it this far, I bet you are wondering about the negative numbers used in the Request - Body. These are reference ids and they must be unique negative numbers. Eloqua will set these ids when the Campaign is created; therefore, you cannot know what they are prior. The negative id is a placeholder that allows you to connect the steps within the output terminals. For the output terminals, the unique negative number reference id is only needed for the output terminal itself if there is more than one output terminal, i.e. a yes / no decision step.

 

This is a simple example, but should help as a starting point for creating more complex flows. To see how you'd build more complex flows using a REST API call, and how other steps look within the elements array, retrieve an existing Campaign you already created using this REST 2.0 API endpoint - GET /assets/campaign/{id}?depth=complete (do not forget the "?depth=complete"!).

 

Happy coding with the Eloqua APIs and see you around Code It!

Before diving into the flowchart for exporting all Eloqua activities using the the Bulk API, let's cover some best practices using the Bulk API focused on exporting activities:

  • Use filters to ensure fewer than 5,000,000 records are exported per Bulk API sync
    • A common method of filtering is to use the Activity Date to export a finite time period of activity, such as one month (use larger or smaller time periods based on volume of activity generation)
  • Export one Activity Type at a time
    • Do not run syncs for all Activity Types simultaneously
  • Make multiple export requests sequentially
    • Allow the sync to finish before executing the next sync

 

Here are the main resources related to exporting activities using the Bulk API on the Developer Help Center:

 

Exporting All Eloqua Activities Using the Bulk API Flowchart

(click to enlarge)

Exporting All Activities Using the Bulk API Flow

 

Notes and Resources by Flowchart Step

Determine Bulk API Base URL and Select Authentication

Select Activity Type to Export

Create an Activity Export Definition for the selected Activity Type

Create the Sync with the Activity Export Definition URI

Retrieve Sync Logs with the Sync URI's Logs Endpoint

    • Syncs Logs Endpoint
    • If exporting to CSV:
      • The total number of records returned can only be retrieved using the Syncs Logs Endpoint
    • If exporting to JSON:
      • When retrieving data with the Sync URI's Data Endpoint in JSON, the following parameters are returned along with the data, either of which could be used to determine how many calls are necessary to retrieve the remaining data:
        • totalResults
        • hasMore
    • When retrieving the count of total records exported from the Syncs Logs endpoint, it's important to note the "message" within that item will be "Successfully exported members to csv file."
    • Example Syncs Logs Response with items "count" and "message" highlighted:

              Example Sync Logs Response

Retrieve the Data with the Sync URI's Data Endpoint

Retrieve the Remaining Data with the Sync URI's Data Endpoint Using Offset

    • Example with URL parameters: GET /syncs/{id}/data?limit=50000&offset=50000
    • Example calls to retrieve all data if there were exactly 150,000 activity records:
      • GET /syncs/{id}/data?limit=50000&offset=0 (This is part of "Retrieve the Data with the Sync URI's Data Endpoint" step)
      • GET /syncs/{id}/data?limit=50000&offset=50000
      • GET /syncs/{id}/data?limit=50000&offset=100000
    • Data returned in JSON unless Accept header specifics CSV (API Call Format)
      • Example: Accept: text/csv
    • A validation check could also be added here.

Create an Activity Export Definition Filtering on Activity Created Date

With the Oracle Eloqua 478/479 release, lead scoring models and fields are coming to the Bulk API. I am going to walk through an end to end scenario with examples, but before I do that here are some of the highlights:

  • Lead scoring models and their corresponding lead scoring fields will be discoverable via the Bulk API
  • Lead scoring fields will be available to be used in Bulk API contact export definitions
    • There could only be one lead scoring model used per contact export definition
  • Each lead scoring model has three lead scoring fields available:
    • Rating
    • Profile Score
    • Engagement Score
  • Lead scoring fields can be used in contact export filter statements

 

With the key takeaways highlighted, let's now take a look at this new functionality in action. I'm going to walk through finding a lead scoring model, using those lead scoring fields in a contact export definition, and completing the scenario by retrieving some contacts. Along the way we'll also use a lead scoring field in a filter statement and, as a bonus, I'll be highlighting an additional improvement in regards to contact exports. Total FOMO should now be in place!

 

Let's start by retrieving two lead scoring models:

 

Request

GET /API/Bulk/2.0/contacts/scoring/models?limit=2

Response

200 OK

 

{

  "items": [

    {

      "name": "Test 1",

      "status": "Draft",

      "id": 1,

      "fields": [

        {

          "name": "Rating",

          "statement": "{{Contact.LeadScore.Model[1].Rating}}",

          "dataType": "string"

        },

        {

          "name": "ProfileScore",

          "statement": "{{Contact.LeadScore.Model[1].ProfileScore}}",

          "dataType": "number"

        },

        {

          "name": "EngagementScore",

          "statement": "{{Contact.LeadScore.Model[1].EngagementScore}}",

          "dataType": "number"

        }

      ],

      "uri": "/contacts/scoring/models/1",

      "createdBy": "Lou.Patrick",

      "updatedBy": "Lou.Patrick",

      "createdAt": "2015-01-15T18:44:58.9930000Z",

      "updatedAt": "2015-07-02T18:03:19.1930000Z"

    },

    {

      "name": "Test 2",

      "status": "Draft",

      "id": 2,

      "fields": [

        {

          "name": "Rating",

          "statement": "{{Contact.LeadScore.Model[2].Rating}}",

          "dataType": "string"

        },

        {

          "name": "ProfileScore",

          "statement": "{{Contact.LeadScore.Model[2].ProfileScore}}",

          "dataType": "number"

        },

        {

          "name": "EngagementScore",

          "statement": "{{Contact.LeadScore.Model[2].EngagementScore}}",

          "dataType": "number"

        }

      ],

      "uri": "/contacts/scoring/models/2",

      "createdBy": "Lou.Patrick",

      "updatedBy": "Lou.Patrick",

      "createdAt": "2015-01-15T18:45:09.9930000Z",

      "updatedAt": "2015-07-02T18:18:01.6570000Z"

    }

  ],

  "totalResults": 6,

  "limit": 2,

  "offset": 0,

  "count": 2,

  "hasMore": true

}

 

I do not see the lead scoring model I'm looking for; however, I see there are four more lead scoring models. I could remove the limit and return all lead scoring models but I know the name of the lead scoring model I want so let's use a query parameter to retrieve a lead scoring model by name and, because I'm not sure on the exact name, we'll use some wildcards:

 

Request

GET /API/Bulk/2.0/contacts/scoring/models?q="name=*Oscar*"

Response

200 OK

 

{

  "items": [

    {

      "name": "Oscar Cleaning",

      "status": "Active",

      "id": 6,

      "fields": [

        {

          "name": "Rating",

          "statement": "{{Contact.LeadScore.Model[6].Rating}}",

          "dataType": "string"

        },

        {

          "name": "ProfileScore",

          "statement": "{{Contact.LeadScore.Model[6].ProfileScore}}",

          "dataType": "number"

        },

        {

          "name": "EngagementScore",

          "statement": "{{Contact.LeadScore.Model[6].EngagementScore}}",

          "dataType": "number"

        }

      ],

      "uri": "/contacts/scoring/models/6",

      "createdBy": "Lou.Patrick",

      "updatedBy": "Lou.Patrick",

      "createdAt": "2016-03-22T17:20:54.6100000Z",

      "updatedAt": "2016-03-22T18:20:39.3000000Z"

    }

  ],

  "totalResults": 1,

  "limit": 1000,

  "offset": 0,

  "count": 1,

  "hasMore": false

}

 

There's the one I'm looking for. Now let's create a contact export definition using the lead scoring fields for the Oscar Cleaning lead scoring model:

250_fields.png

Request

POST /API/Bulk/2.0/contacts/exports

Request - Body

{

  "name": "Contact Lead Score Export - Oscar Cleaning",

  "fields": {

    "EmailAddress": "{{Contact.Field(C_EmailAddress)}}",

    "FirstName": "{{Contact.Field(C_FirstName)}}",

    "LastName": "{{Contact.Field(C_LastName)}}",

    "Rating": "{{Contact.LeadScore.Model[6].Rating}}",

    "Profile": "{{Contact.LeadScore.Model[6].ProfileScore}}",

    "Engagement": "{{Contact.LeadScore.Model[6].EngagementScore}}",

    "AcademyAwards": "{{Contact.Field(C_Academy_Awards1)}}"

  }

}

Response

201 Created

 

{

  "name": "Contact Lead Score Export - Oscar Cleaning",

  "fields": {

    "EmailAddress": "{{Contact.Field(C_EmailAddress)}}",

    "FirstName": "{{Contact.Field(C_FirstName)}}",

    "LastName": "{{Contact.Field(C_LastName)}}",

    "Rating": "{{Contact.LeadScore.Model[6].Rating}}",

    "Profile": "{{Contact.LeadScore.Model[6].ProfileScore}}",

    "Engagement": "{{Contact.LeadScore.Model[6].EngagementScore}}",

    "AcademyAwards": "{{Contact.Field(C_Academy_Awards1)}}"

  },

  "dataRetentionDuration": "PT12H",

  "uri": "/contacts/exports/5",

  "createdBy": "Lou.Patrick",

  "createdAt": "2016-03-22T19:22:05.2099774Z",

  "updatedBy": "Lou.Patrick",

  "updatedAt": "2016-03-22T19:22:05.2099774Z"

}

 

With our uri in hand, we are now ready to create the sync:

 

Request

POST /API/Bulk/2.0/syncs

Request - Body

{

  "syncedInstanceUri": "/contacts/exports/5"

}

Response

201 Created

 

{

  "syncedInstanceUri": "/contacts/exports/5",

  "status": "pending",

  "createdAt": "2016-03-22T19:34:44.7980550Z",

  "createdBy": "Lou.Patrick",

  "uri": "/syncs/2"

}

 

Ideally we'd be using the callbackUrl parameter to allow Eloqua to alert us when the sync is complete. For simplicity of demonstration, I'll GET the sync details to confirm it was successful:

 

Request

GET /API/Bulk/2.0/syncs/2

Response

200 OK

 

{

  "syncedInstanceUri": "/contacts/exports/5",

  "syncStartedAt": "2016-03-22T19:34:47.2570000Z",

  "syncEndedAt": "2016-03-22T19:34:48.5000000Z",

  "status": "success",

  "createdAt": "2016-03-22T19:34:45.0030000Z",

  "createdBy": "Lou.Patrick",

  "uri": "/syncs/2"

}

 

Success! Now it's time to retrieve the data:

 

Request

GET /API/Bulk/2.0/syncs/2/data

Response

200 OK

 

{

  "totalResults": 13,

  "limit": 1000,

  "offset": 0,

  "count": 13,

  "hasMore": false,

  "items": [

    {

      "EmailAddress": "test1234@test.com",

      "FirstName": "",

      "LastName": "",

      "Rating": "D4",

      "Profile": "0",

      "Engagement": "0",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "lou.patrick@oracle.com",

      "FirstName": "Lou",

      "LastName": "Patrick",

      "Rating": "D4",

      "Profile": "0",

      "Engagement": "0",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "test12@test.com",

      "FirstName": "Test12",

      "LastName": "",

      "Rating": "D4",

      "Profile": "0",

      "Engagement": "0",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "test1234@test1234.com",

      "FirstName": "",

      "LastName": "",

      "Rating": "D4",

      "Profile": "0",

      "Engagement": "0",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "12321321312test@test.com",

      "FirstName": "",

      "LastName": "",

      "Rating": "D4",

      "Profile": "0",

      "Engagement": "0",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "123456@test.com",

      "FirstName": "",

      "LastName": "",

      "Rating": "D4",

      "Profile": "0",

      "Engagement": "0",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "whoopi@egot.com",

      "FirstName": "Whoopi",

      "LastName": "Goldberg",

      "Rating": "B1",

      "Profile": "70",

      "Engagement": "100",

      "AcademyAwards": "1.0000"

    },

    {

      "EmailAddress": "streep@gmail.com",

      "FirstName": "Meryl",

      "LastName": "Streep",

      "Rating": "A3",

      "Profile": "100",

      "Engagement": "30",

      "AcademyAwards": "3.0000"

    },

    {

      "EmailAddress": "thanks@yahoo.com",

      "FirstName": "Tom",

      "LastName": "Hanks",

      "Rating": "A4",

      "Profile": "80",

      "Engagement": "0",

      "AcademyAwards": "2.0000"

    },

    {

      "EmailAddress": "cruise@gmail.com",

      "FirstName": "Tom",

      "LastName": "Cruise",

      "Rating": "D1",

      "Profile": "0",

      "Engagement": "100",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "arnold@schawrz.com",

      "FirstName": "Arnold",

      "LastName": "Schwarzenegger",

      "Rating": "D2",

      "Profile": "0",

      "Engagement": "70",

      "AcademyAwards": ""

    },

    {

      "EmailAddress": "jack@gmail.com",

      "FirstName": "Jack",

      "LastName": "Nicholson",

      "Rating": "A1",

      "Profile": "100",

      "Engagement": "100",

      "AcademyAwards": "3.0000"

    },

    {

      "EmailAddress": "nats@yahoo.com",

      "FirstName": "Natalie",

      "LastName": "Portman",

      "Rating": "B4",

      "Profile": "70",

      "Engagement": "0",

      "AcademyAwards": "1.0000"

    }

  ]

}

 

There are not many contacts in this test instance but there are some clear test contacts and also some contacts we'd want to remove as they do not have any Academy Awards. Next, we'll create a new contact export definition and filter on the Profile lead scoring field, removing all contacts from our export with a Profile value of "0":

 

Request

POST /API/Bulk/2.0/contacts/exports

Request - Body

{

  "name": "Contact Lead Score Export - Oscar Cleaning - Filtered",

  "fields": {

    "EmailAddress": "{{Contact.Field(C_EmailAddress)}}",

    "FirstName": "{{Contact.Field(C_FirstName)}}",

    "LastName": "{{Contact.Field(C_LastName)}}",

    "Rating": "{{Contact.LeadScore.Model[6].Rating}}",

    "Profile": "{{Contact.LeadScore.Model[6].ProfileScore}}",

    "Engagement": "{{Contact.LeadScore.Model[6].EngagementScore}}",

    "AcademyAwards": "{{Contact.Field(C_Academy_Awards1)}}"

  },

  "filter": "'{{Contact.LeadScore.Model[6].ProfileScore}}' > '0'"

}

Response

201 Created

 

{

  "name": "Contact Lead Score Export - Oscar Cleaning - Filtered",

  "fields": {

    "EmailAddress": "{{Contact.Field(C_EmailAddress)}}",

    "FirstName": "{{Contact.Field(C_FirstName)}}",

    "LastName": "{{Contact.Field(C_LastName)}}",

    "Rating": "{{Contact.LeadScore.Model[6].Rating}}",

    "Profile": "{{Contact.LeadScore.Model[6].ProfileScore}}",

    "Engagement": "{{Contact.LeadScore.Model[6].EngagementScore}}",

    "AcademyAwards": "{{Contact.Field(C_Academy_Awards1)}}"

  },

  "filter": "'{{Contact.LeadScore.Model[6].ProfileScore}}' > '0'",

  "dataRetentionDuration": "PT12H",

  "uri": "/contacts/exports/6",

  "createdBy": "Lou.Patrick",

  "createdAt": "2016-03-22T20:16:32.6099108Z",

  "updatedBy": "Lou.Patrick",

  "updatedAt": "2016-03-22T20:16:32.6099108Z"

}

 

We'll skip over showing examples for creating the sync and confirming it was successful, as it's identical to the examples above. From creating the sync the resulting uri is "/syncs/3". Let's jump to retrieving data from our filtered contact export definition sync:

 

Request

GET /API/Bulk/2.0/syncs/3/data

Response

200 OK

 

{

  "totalResults": 5,

  "limit": 1000,

  "offset": 0,

  "count": 5,

  "hasMore": false,

  "items": [

    {

      "EmailAddress": "whoopi@egot.com",

      "FirstName": "Whoopi",

      "LastName": "Goldberg",

      "Rating": "B1",

      "Profile": "70",

      "Engagement": "100",

      "AcademyAwards": "1.0000"

    },

    {

      "EmailAddress": "streep@gmail.com",

      "FirstName": "Meryl",

      "LastName": "Streep",

      "Rating": "A3",

      "Profile": "100",

      "Engagement": "30",

      "AcademyAwards": "3.0000"

    },

    {

      "EmailAddress": "thanks@yahoo.com",

      "FirstName": "Tom",

      "LastName": "Hanks",

      "Rating": "A4",

      "Profile": "80",

      "Engagement": "0",

      "AcademyAwards": "2.0000"

    },

    {

      "EmailAddress": "jack@gmail.com",

      "FirstName": "Jack",

      "LastName": "Nicholson",

      "Rating": "A1",

      "Profile": "100",

      "Engagement": "100",

      "AcademyAwards": "3.0000"

    },

    {

      "EmailAddress": "nats@yahoo.com",

      "FirstName": "Natalie",

      "LastName": "Portman",

      "Rating": "B4",

      "Profile": "70",

      "Engagement": "0",

      "AcademyAwards": "1.0000"

    }

  ]

}

 

Now we have filtered results including only contacts that have at least one Academy Award. That completes the walk through of the lead scoring capabilities coming to the Bulk API. So now I bet everyone wants to mark their calendars with the date 478/479 will arrive for them!

 

When will I receive the 478/479 release? Visit the Oracle Eloqua Release Center to view roll out dates.

 

How about documentation? When version 478/479 is rolled out to POD2, the Oracle Eloqua Developer Help Center will be updated with the new endpoints and examples. (Documentation now updated: Lead scoring models)

 

Interested in more related to Eloqua APIs and the 478/479 release? Take a look at the Developer Release Notes - 478/479.

 

Happy coding with the Eloqua APIs and see you around Code It!