Develop an Oracle Eloqua app decision service

Decisions are steps on a campaign or program canvas that directly control the path a contact or custom object takes as they flow through a canvas. Decision steps delegate the decision making to an external system, which responds with a yes or no for each object flowing through the canvas, determining which path the contact or custom object should take.

Decisions follow the instantiation-execution model. The following sections describe decision-specific details and provide the endpoints needed to develop a decision service. If you are not familiar with the general flow for the instantiation-execution model, you should read that first.

Eloqua signs all outgoing calls with OAuth 1.0a so the receiving system can validate that the call was sent by Eloqua. Refer to the OAuth 1.0a spec or OAuth 1.0 RFC for more information.

If you prefer a more visual representation of the flow for decision services, check out the following flow diagram:

Create URL

Eloqua's call to the CreateURL:

POST https://example.com/awesomeapp/decide/create?instance=9347bfe1-9c72-409c-a5cd-402ff74f0caa

{}

AwesomeApp’s response is a DTO describing the fields Eloqua should transmit when the service in executed. You can include a maximum of 249 fields in your record definition. For more details, see: bulk API limits.

Note: The "Content-Type" header must be set to "application/json" for the response to the Create URL call.

Example response for contacts:

HTTP/1.1 200 application/json; charset=utf-8

{
  "recordDefinition": {
    "ContactID": "{{Contact.Id}}",
    "EmailAddress": "{{Contact.Field(C_EmailAddress)}}"
  },
  "requiresConfiguration": true
}

Example response for custom objects:

HTTP/1.1 200 application/json; charset=utf-8

{
  "recordDefinition": {
    "Email": "{{CustomObject[1].Field[4]}}"
  },
  "requiresConfiguration": true
}

requiresConfiguration is an optional Boolean parameter which tells Eloqua whether user configuration is required before the app can be used. If set to true, users will be unable to activate a campaign or program containing the unconfigured app service instance. Eloqua will display an error message.


Warning: All field names and values in Eloqua data transfer objects are case sensitive. Be sure to reproduce them exactly. For example: {{Contact.id}} would fail if the correct form is {{Contact.Id}}.

Configure URL

When a user clicks the edit button on the service instance and makes changes through the Configure URL that require an updated recordDefinition DTO, AwesomeApp must call out to Eloqua's cloud API PUT /decisions/instances/{id} endpoint with that updated DTO:

Example request for contacts:

PUT https://secure.p03.eloqua.com/api/cloud/1.0/decisions/instances/9347bfe1-9c72-409c-a5cd-402ff74f0caa

{
    "recordDefinition":
       {
          "ContactID" : "{{Contact.Id}}",
          "EmailAddress" : "{{Contact.Field(C_EmailAddress)}}",
          "field1" : "{{Contact.Field(C_field1)}}",
          "field2" : "{{Contact.Field(C_field2)}}",
          "field3" : "{{Contact.Field(C_field3)}}"
       },
    "requiresConfiguration": false
}

Example request for custom objects:

PUT https://secure.p03.eloqua.com/api/cloud/1.0/decisions/instances/9347bfe1-9c72-409c-a5cd-402ff74f0caa

{
    "recordDefinition": {
          "Email": "{{CustomObject[1].Field[4]}}"
    },
   "requiresConfiguration": false
}

requiresConfiguration is an optional Boolean parameter which tells Eloqua whether user configuration is required before the app can be used. If set to true, users will be unable to activate a campaign or program containing the unconfigured app service instance. Eloqua will display an error message.

Use the Configure URL response to set requiresConfiguration to false when your app's configuration acceptance criteria have been met.

Note: X-Frame-Options must not be set to DENY for any configure page.

Warning: If the campaign or program is not in draft mode, attempting to set requiresConfiguration to true will result in an error.

Notification URL

Eloqua's call to the Notification URL transmits the requested fields in the items parameter:

POST https://example.com/awesomeapp/decide/notify?instance=9347bfe1-9c72-409c-a5cd-402ff74f0caa&asset=456
{
"offset" : 0,
"limit" : 1000,
"totalResults" : 2,
"count" : 2,
"hasMore" : false,
"items" :
[
{
"ContactID" : "1",
"EmailAddress" : "fred@example.com",
"field1" : "stuff",
"field2" : "things",
"field3" : "et cetera"
},
{
"ContactID" : "2",
"EmailAddress" : "john@example.com",
"field1" : "more stuff",
"field2" : "other things",
"field3" : "and so on"
}
]
}

Note: The amount of records in the items parameter is dependent on the Records per Notification option during service registration. If you prefer to retrieve records using a separate export, see Retrieving app records using the bulk API for instructions.

Important: Each batch, delivered through a call to the notification URL, of contacts or custom object records in a step will only remain in the workflow for a maximum of 90 days. Attempts to operate on them (set the status to complete or errored) after 90 days will fail, resulting in the records being stuck in the step, and requiring manual intervention to move them along in the flow. Each batch of records sent through a call to the notification URL has an ExecutionId, available as a template parameter, that identifies a unique batch.

AwesomeApp responds with a 204 response, indicating that the response will be asynchronous, followed by an import to Eloqua's Bulk API, where AwesomeApp specifies a sync action. For Decisions, the sync action is either "yes", "no", or "errored". AwesomeApp will need to create multiple imports for the different statuses, with contacts or custom objects that should follow the "no" path in one import and then contacts and custom objects that should follow the "yes" path in another. Note that the maximum import size per batch is 5,000: if you have more than 5,000 contacts or custom objects, break your data up into multiple imports.

Bulk API contact import

  1. Create the bulk import definition, setting the status to yes to import data.

    If there is no data to import, and you only need to update a record's status, you can update a record's status without performing an import by creating a contact sync action definition.

    When importing, the "destination" field refers to the AppCloud Decision service's instance - in this example, the instance ID is 9347bfe1-9c72-409c-a5cd-402ff74f0caa:

    Warning: When referencing service instances, you must transmit the GUID without dashes. The bulk API will error if you transmit the GUID with the dashes.

    Create a contact import definition where the sync action sets the record's status, where the instance ID is 9347bfe1-9c72-409c-a5cd-402ff74f0caa and execution ID is 12345:

    POST https://secure.p03.eloqua.com/api/bulk/2.0/contacts/imports
    {
    "name" : "AwesomeApp Decision Response Bulk Import",
    "updateRule" : "always",
    "fields" : {
    "emailAddress" : "{{Contact.Field(C_EmailAddress)}}"
    }
    "syncActions" : [
    {
    "destination" : "{{DecisionInstance(9347bfe19c72409ca5cd402ff74f0caa).Execution[12345]}}",
    "action" : "setStatus",
    "status" : "yes"
    }
    ],
    "identifierFieldName" : "emailAddress"
    }

    Eloqua's response will be a 201 created response that includes a uri parameter, which you can use to identify the import:

    {
      "name": "AwesomeApp Decision Response Bulk Import",
      "updateRule": "always",
      "fields": {
        "emailAddress": "{{Contact.Field(C_EmailAddress)}}"
      },
      "identifierFieldName": "emailAddress",
      "syncActions": [
        {
          "destination": "{{DecisionInstance(9347bfe19c72409ca5cd402ff74f0caa).Execution[12345]}}",
          "action": "setStatus",
          "status": "yes"
        }
      ],
      "isSyncTriggeredOnImport": false,
      "isUpdatingMultipleMatchedRecords": false,
      "uri": "/contacts/imports/6",
      "createdBy": "DocsExample",
      "createdAt": "2014-03-06T13:59:00.6600046Z",
      "updatedBy": "DocsExample",
      "updatedAt": "2014-03-06T13:59:00.6600046Z"
    }
  2. Send Eloqua the import data using the uri:

    POST https://secure.p03.eloqua.com/api/bulk/2.0/contacts/imports/6/data
    [
    {
    "emailAddress" : "fred@example.com"
    },
    {
    "emailAddress" : "sylvie@example.com"
    }
    ]
  3. Synchronize the data for import:

    AwesomeApp's request:

    POST https://secure.p03.eloqua.com/api/bulk/2.0/syncs
    {
    "syncedInstanceURI":"/contacts/imports/6"
    }

    Eloqua's response:

    201 Created

    {
    "syncedInstanceURI" : "/contacts/imports/6",
    "status" : "pending",
    "createdAt" : "2014-01-01T13:59:07.1375620Z",
    "createdBy" : "DocsExample",
    "uri" : "/syncs/6"
    }
  4. You can then use the sync's URI (/syncs/6) to check the status of the sync:

    GET https://secure.p03.eloqua.com/api/bulk/2.0/sync/6

    For a full description of the sync status codes, see: bulk API sync status codes

    When the sync is complete, Eloqua's response will resemble:

    200 OK

    {
    "syncedInstanceURI" : "/contacts/imports/6",
    "syncStartedAt" : "2014-01-01T13:59:07.1375620Z",
    "syncEndedAt" : "2014-01-01T13:59:14.1375620Z",
    "status" : "success",
    "createdAt" : "2014-01-01T13:59:07.1375620Z",
    "createdBy" : "DocsExample",
    "uri" : "/syncs/6"
    }

Bulk API custom object import

  1. Create the bulk import definition, setting the status to yes to import data.

    If there is no data to import, and you only need to update a record's status, you can update a record's status without performing an import by creating a custom object sync action definition.

    When importing, the destination field refers to the decision service's instance - in this example, the instance GUID is f82d50cd-86a9-4fca-b37e-4ec9a98b0339:

    Warning: When referencing service instances, you must transmit the GUID without dashes. The bulk API will error if you transmit the GUID with the dashes.

    Create a custom object import definition where the sync action sets the record's status, where the instance ID is f82d50cd-86a9-4fca-b37e4ec9a98b0339 and execution ID is 12345:

    POST https://secure.p03.eloqua.com/api/bulk/2.0/customObjects/9/imports
    {
    "name" : "AwesomeApp Decision Response Bulk Import",
    "updateRule" : "always",
    "fields" : {
    "email" : "{{CustomObject[9].Field[58]}}"
    },
    "syncActions" : [
    {
    "destination" : "{{DecisionInstance(f82d50cd86a94fcab37e4ec9a98b0339).Execution[12345]}}",
    "action" : "setStatus",
    "status" : "yes"
    }
    ],
    "identifierFieldName" : "email"
    }

    Eloqua's response will be a 201 created response that includes a uri parameter, which you can use to identify the import:

    HTTP/1.1 201 Created

    {
    "name" : "AwesomeApp Decision Response Bulk Import",
    "updateRule" : "always",
    "fields" : {
    "email" : "{{CustomObject[9].Field[58]}}"
    },
    "identifierFieldName" : "email",
    "syncActions" : [
    {
    "destination" : "{{DecisionInstance(f82d50cd86a94fcab37e4ec9a98b0339).Execution[12345]}}",
    "action" : "setStatus",
    "status" : "yes"
    }
    ],
    "isSyncTriggeredOnImport" : false,
    "isUpdatingMultipleMatchedRecords" : false,
    "uri" : "/customObjects/imports/9",
    "createdBy" : "DocsExample",
    "createdAt" : "2014-03-06T13:59:00.6600046Z",
    "updatedBy" : "DocsExample",
    "updatedAt" : "2014-03-06T13:59:00.6600046Z"
    }
  2. Send Eloqua the data for import as a using the uri:
    POST https://secure.p03.eloqua.com/api/bulk/2.0/customObjects/imports/9/data
    [
    {
    "email" : "fred@example.com"
    },
    {
    "email" : "sylvie@example.com"
    }
    ]
  3. Synchronize the data for import:

    AwesomeApp's request:

    POST https://secure.p03.eloqua.com/api/bulk/2.0/syncs
    {
    "syncedInstanceURI":"/customObjects/imports/9"
    }

    Eloqua's response:

    201 Created

    {
    "syncedInstanceURI" : "/customObjects/imports/9",
    "status" : "pending",
    "createdAt" : "2014-01-01T13:59:07.1375620Z",
    "createdBy" : "DocsExample",
    "uri" : "/syncs/9"
    }
  4. You can then use the sync's URI (/syncs/9) to check the status of the sync:
    GET https://secure.p03.eloqua/api/bulk/2.0/sync/9

    For a full description of the sync status codes, see: bulk API status codes.

    When the sync is complete, Eloqua’s response will resemble:

    200 OK

    {
    "syncedInstanceURI" : "/customObjects/imports/9",
    "syncStartedAt" : "2014-01-01T13:59:07.1375620Z",
    "syncEndedAt" : "2014-01-01T13:59:14.1375620Z",
    "status" : "success",
    "createdAt" : "2014-01-01T13:59:07.1375620Z",
    "createdBy" : "DocsExample",
    "uri" : "/syncs/9"
    }

If you run into trouble or have questions about the bulk API, check out the bulk API documentation.

Delete URL

The delete URL is a templated URL pointing to an endpoint for deleting an instance of your service.

The delete URL uses an HTTP DELETE request and there is no content sent in the request body. All common URL template parameters are available (the same as with a create URL). On success, this endpoint should return a 200-level response.

An example delete URL would look something like:

https://www.someurl.com/delete/{appId}/{installId}/{instanceId}/{userName}/{siteName}/{siteId}

Note: Delete calls are not sent in real time, but are done in a batch once daily.

Learn more

Service descriptions

Service level URL template parameters

App developer reference