Forecast API - Documentation
In order to use the Forecast API, your Salesforce Org needs to have API usage activated through having an API usage License.
We also recommend you to automate the OAuth access to avoid authorization issues: 1.6 How to authenticate / authorize ADvendio Gateway for the use of our Third Party System integrations? - Authorize ADvendio message / OAuth#Setup:
The Forecast API function is implemented as Apex class and is exposed as REST web service by using Salesforce standard functionality (see Apex Developer Guide for more information). For general information about the Forecast API feature, see 4.4 Availability Forecast.
1. REST web service
1.1. URL
https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/CheckAvailability/
https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/JobUpdates/
1.2. Method
PATCH
1.3. URL Params
-
1.4. Data Params
A JSON object with the attribute campaignItems, containing a JSON serialized list of Campaign Items.
Example: { "campaignItems":[{<Campaign Item>}, ...]}
See /wiki/spaces/AD/pages/852000769 for detailed information about the internal data structure of the Campaign Item.
1.5. Success Response
Code: 200
Content: A JSON serialized list of the Campaign Items from the request body, but now with updated availability and status fields.
Example: [{<Campaign Item>}, ...]
1.6. Error Response
See Salesforce Apex REST Documentation
1.7. Logic
The CheckAvailability web service function returns the availabilities for all Campaign Items not connected to an Ad Server and starts the availability check for the Campaign Items that are connected to an Ad Server. If an availability check job was started the job information will be saved to the field ADvendio__MostRecentGatewayJobInformation__c. The returned Campaign Item can now be used to get the job results by using the JobUpdates function.
The following fields are updated by the CheckAvailability or JobUpdates function.
Campaign Item Field | Data format | Note |
---|---|---|
ADvendio__AvailabilityRunning__c | Number | Campaign Item start time < NOW() AND Already submitted to the Ad Server |
ADvendio__ReservedImpressionsRunning__c | Number | |
ADvendio__MatchedImpressionsRunning__c | Number | |
ADvendio__Availability__c | Number | Campaign Item start time > NOW() OR Not yet submitted to the Ad Server |
ADvendio__ReservedImpressionsPlanned__c | Number | |
ADvendio__MatchedImpressionsPlanned__c | Number | |
ADvendio__Share_of_Voice__c | Percent | 100 * Matched / BookingQuantity |
ADvendio__LastAvailabilityForecast__c | Date/Time | NOW() |
ADvendio__MostRecentGatewayJobInformation__c | JSON String: {"jobId":123456, | If an Ad Server is connected the availability will be asynchonously checked by the Ad Server Gateway. This field is used to store information about the asynchronous job. campaignItemId: If there is no Campaign Item id, we need an identifier to map back the results, so a fake id is automatically generated. progress: A value between 0 and 1 to show the progress of the job. Starts with 0 and is finished when it reatches 1. message: Message about the job status status: Queued = 0, In progress = 1, completed = 2, failed = 3 start: The the time stamp when the job was started. operation: For Check Availability always "Forecast". orgId: The Salesforce org id. |
ADvendio__SelectedContent__r.ADvendio__Availability__c | JSON: { "version":1, | If there is Content linked to the Campaign Item at it is no AdServer connected, the availability will be checked per content per time frame. Time frames are days for CPD, weeks for CPW, months for CPMo, years for CPY and the Campaign Item run time for Fixed Price billing category. version: A version number for the JSON format in case we need to change it. availabilityPerTime: Map of the first date of a time frame to the availability number for that time frame. |
1.8. Examples
1.8.1. Get a Session-ID
curl -v https://login.salesforce.com/services/oauth2/token -d "grant_type=password" -d "client_id=<CLIENT_ID>" -d "client_secret=<CLIENT_SECRET>" -d "username=<USER_NAME>" -d "password=<PASSWORD+TOKEN>" -H 'X-PrettyPrint:1'
Connected App
Get CLIENT_ID and CLIENT_SECRET from any connected app or create a new app in your org: App Manager -> New Connected App
Enable Enable OAuth Settings to see the consumer key (CLIENT_ID) and Consumer Secret (CLIENT_SECRET)
1.8.2. Minimal request
A simple request for a Campaign Item connected to an Ad Server (Google Ad Manager, other Ad Server may need additional information).
curl https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/CheckAvailability/ -H 'Authorization: Bearer <SESSION_ID>' -H "Content-Type: application/json" -H 'X-PrettyPrint:1' -d @requestBody.txt --request PATCH
For CheckAvailability the following fields are required per Campaign Item: ADvendio__from_Date__c, ADvendio__until_Date__c, ADvendio__Ad_Price__c
{ "campaignItems":[ { "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__Ad_Price__c" : "a0HA000000LYVkQMAX" } ] }
[ { "attributes" : { "type" : "ADvendio__Campaign_Item__c", }, "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__MostRecentGatewayJobInformation__c" : "{\"jobId\":440596,\"campaignItemId\":\"a0Y000000000001EAA\"}", "ADvendio__Ad_Price__c" : "a0HA000000LYVkQMAX", "Id" : null } ]
Second call to get the job results some time later:
curl https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/JobUpdates/ -H 'Authorization: Bearer <SESSION_ID>' -H "Content-Type: application/json" -H 'X-PrettyPrint:1' -d @requestBody1.txt --request PATCH
For the JobUpdates request the field ADvendio__MostRecentGatewayJobInformation__c is required. This contains the jobId and dummy campaignItemId to map the results back to each Campaign Item.
{ "campaignItems":[ { "ADvendio__MostRecentGatewayJobInformation__c" : "{\"jobId\":440596,\"campaignItemId\":\"a0Y000000000001EAA\"}" } ] }
[ { "attributes" : { "type" : "ADvendio__Campaign_Item__c" }, "ADvendio__MatchedImpressionsPlanned__c" : 156, "ADvendio__ReservedImpressionsPlanned__c" : 1, "ADvendio__MostRecentGatewayJobInformation__c" : "{\"errors\":[{\"message\":null}],\"jobId\":440596,\"campaignItemId\":\"a0Y000000000001EAA\",\"status\":{\"jobId\":440596,\"orgId\":\"00DA0000000clAiMAI\",\"operation\":\"Forecast\",\"start\":\"2019-10-17T13:38:29.000+0000\",\"end\":\"2019-10-17T13:38:38.000+0000\",\"status\":2,\"message\":\"Finish Job\",\"progress\":1}}", "ADvendio__Share_of_Voice__c" : 15600, "ADvendio__Availability__c" : 112 } ]
1.8.3. Request with some targeting
A request for a Campaign Item connected to an Ad Server including some targeting information. To simplify this, we're using Targeting Sets, which contain all Targeting Criteria. You will need to create those in advance in Salesforce. See 3.5.8 Create and Manage Targeting Sets for more information on that.
curl https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/CheckAvailability/ -H 'Authorization: Bearer <SESSION_ID>' -H "Content-Type: application/json" -H 'X-PrettyPrint:1' -d @requestBody.txt --request PATCH
{ "campaignItems":[ { "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__Ad_Price__c" : "a1CB0000002lK6RMAU", "ADvendio__FrequencyCapping__c":"2 per 1 campaign", "ADvendio__AdServerTargeting__c" : "{\"Geography\":{\"valL\":[{\"valS\":\"a14B0000001bZaoIAE\",\"type\":\"Id\"}],\"type\":\"List\",\"logic\":\"&&\"}}", "ADvendio__Media_Campaign__r" : { "ADvendio__Account__c" : "001A000001R6HDqIAN" }, "ADvendio__SelectedTargetingSets__r":{"records":[ {"ADvendio__TargetingSet__c":"a2f2K000000orLNQAY"} ]} } ] }
[ { "attributes" : { "type" : "ADvendio__Campaign_Item__c", "url" : "/services/data/v46.0/sobjects/ADvendio__Campaign_Item__c/a0l1j000000ayRJAAY" }, "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__MostRecentGatewayJobInformation__c" : "{\"jobId\":434663,\"campaignItemId\":\"a0Y000000000001EAA\"}", "ADvendio__Ad_Price__c" : "a1CB0000002lK6RMAU", "ADvendio__Media_Campaign__r" : { "attributes" : { "type" : "ADvendio__MediaCampaign__c" }, "ADvendio__Account__c" : "001A000001R6HDqIAN" }, "Id" : null, "ADvendio__FrequencyCapping__c" : "2 per 1 campaign", "ADvendio__AdServerTargeting__c" : "{\"Geography\":{\"valL\":[{\"valS\":\"a14B0000001bZaoIAE\",\"type\":\"Id\"}],\"type\":\"List\",\"logic\":\"&&\"}}", "ADvendio__SelectedTargetingSets__r" : { "totalSize" : 0, "done" : false, "records" : [ { "attributes" : { "type" : "ADvendio__SelectedTargetingSet__c" }, "ADvendio__TargetingSet__c" : "a2f2K000000orLhQAI" }] } } ]
Second call to get the job results some time later:
curl https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/JobUpdates/ -H 'Authorization: Bearer <SESSION_ID>' -H "Content-Type: application/json" -H 'X-PrettyPrint:1' -d @requestBody1.txt --request PATCH
{ "campaignItems":[ { "attributes" : { "type" : "ADvendio__Campaign_Item__c", "url" : "/services/data/v46.0/sobjects/ADvendio__Campaign_Item__c/a0l1j000000ayRJAAY" }, "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__MostRecentGatewayJobInformation__c" : "{\"jobId\":434663,\"campaignItemId\":\"a0Y000000000001EAA\"}", "ADvendio__Ad_Price__c" : "a1CB0000002lK6RMAU", "ADvendio__Media_Campaign__r" : { "attributes" : { "type" : "ADvendio__MediaCampaign__c" }, "ADvendio__Account__c" : "001A000001R6HDqIAN" }, "Id" : null, "ADvendio__FrequencyCapping__c" : "2 per 1 campaign", "ADvendio__AdServerTargeting__c" : "{\"Geography\":{\"valL\":[{\"valS\":\"a14B0000001bZaoIAE\",\"type\":\"Id\"}],\"type\":\"List\",\"logic\":\"&&\"}}", "ADvendio__SelectedTargetingSets__r" : { "totalSize" : 0, "done" : false, "records" : [ { "attributes" : { "type" : "ADvendio__SelectedTargetingSet__c" }, "ADvendio__TargetingSet__c" : "a2f2K000000orLNQAY" } ] } } ] }
[ { "attributes" : { "type" : "ADvendio__Campaign_Item__c", "url" : "/services/data/v46.0/sobjects/ADvendio__Campaign_Item__c/a0l1j000000ayRJAAY" }, "ADvendio__MatchedImpressionsPlanned__c" : 24, "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__ReservedImpressionsPlanned__c" : 1, "ADvendio__MostRecentGatewayJobInformation__c" : "{\"errors\":[{\"message\":null}],\"jobId\":434663,\"campaignItemId\":\"a0Y000000000001EAA\",\"status\":{\"jobId\":434663,\"orgId\":\"00DB0000000IE6XMAW\",\"operation\":\"Forecast\",\"start\":\"2019-10-10T14:50:26.000+0000\",\"end\":\"2019-10-10T14:50:32.000+0000\",\"status\":2,\"message\":\"Finish Job\",\"progress\":1}}", "ADvendio__Ad_Price__c" : "a1CB0000002lK6RMAU", "ADvendio__Media_Campaign__r" : { "attributes" : { "type" : "ADvendio__MediaCampaign__c" }, "ADvendio__Account__c" : "001A000001R6HDqIAN" }, "Id" : null, "ADvendio__FrequencyCapping__c" : "2 per 1 campaign", "ADvendio__Share_of_Voice__c" : 2400, "ADvendio__AdServerTargeting__c" : "{\"Geography\":{\"valL\":[{\"valS\":\"a14B0000001bZaoIAE\",\"type\":\"Id\"}],\"type\":\"List\",\"logic\":\"&&\"}}", "ADvendio__SelectedTargetingSets__r" : { "totalSize" : 0, "done" : false, "records" : [ { "attributes" : { "type" : "ADvendio__SelectedTargetingSet__c" }, "ADvendio__TargetingSet__c" : "a2f2K000000orLNQAY" } ] }, "ADvendio__Availability__c" : 16 } ]
1.8.4. Request for non adserver Campaign Items with Content
A request for a Campaign Item not connected to an Ad Server with selected Content. This will start the Exclusivity Check process inside of ADvendio instead of the Check Availability against the AdServer Gateway.
curl https://<my-domain-name>.my.salesforce.com/services/apexrest/ADvendio/ADvendio__Campaign_Item__c/CheckAvailability/ -H 'Authorization: Bearer <SESSION_ID>' -H "Content-Type: application/json" -H 'X-PrettyPrint:1' -d @requestBody.txt --request PATCH
{ "campaignItems":[ { "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__Ad_Price__c" : "a1CB0000002lK6RMAU", "ADvendio__SelectedContent__r": { "records": [ { "attributes": { "type": "ADvendio__SelectedContent__c" }, "ADvendio__Content__r": { "attributes": { "type": "ADvendio__Content__c" }, "Id": "a2f2K000000orLNQAY", "ADvendio__ConstantQuantity__c": "Quantity", "ADvendio__MaximumApplicability__c": 1, "ADvendio__MaximumApplicabilityUnit__c": "Day" } } ], "done": true } } ] }
[ { "attributes" : { "type" : "ADvendio__Campaign_Item__c", "url" : "/services/data/v46.0/sobjects/ADvendio__Campaign_Item__c/a0l1j000000ayRJAAY" }, "ADvendio__from_Date__c" : "2019-12-01", "ADvendio__until_Date__c" : "2019-12-31", "ADvendio__Ad_Price__c" : "a1CB0000002lK6RMAU", "ADvendio__SelectedContent__r" : { "totalSize" : 1, "done" : false, "records" : [ { "attributes" : { "type" : "ADvendio__SelectedContent__c" }, "ADvendio__Content__c" : "a2f2K000000orLNQAY" "ADvendio__Availability__c" : { "version":1, "availabilityPerTime" : { "2019-12-01" : 16 } } } ] }, "ADvendio__Availability__c" : 16 } ]
1.8.5. Request for non adserver Campaign Items with Content (Inventory Forecast)
A request for a Campaign Item not connected to an Ad Server with selected Content. This will start the Exclusivity Check process inside of ADvendio instead of the Check Availability against the AdServer Gateway.
{ "campaignItems": [ { "ADvendio__from_Date__c": "2022-11-09", "ADvendio__until_Date__c": "2022-11-15", "ADvendio__Quantity__c": "2", "ADvendio__Frequency__c": "1", "ADvendio__RequestedContents__c": "1", "ADvendio__Ad_Price__c": "a0H2K00000VuuRDUAZ", "ADvendio__SelectedContent__r": { "records": [ { "attributes": { "type": "ADvendio__SelectedContent__c" }, "ADvendio__Content__c": "a0e2K00000fn85fQAA" } ], "totalSize": 1, "done": true } } ] }
[ { "attributes": { "type": "ADvendio__Campaign_Item__c", "url": "/services/data/v46.0/sobjects/ADvendio__Campaign_Item__c/a0Y000000000001EAA" }, "ADvendio__ContendingCampaignItems__c": "a0Y2K00000GEyltUAD\na0Y2K00000GEymIUAT", "ADvendio__Quantity__c": 2.0, "ADvendio__Ad_Price__r": { "attributes": { "type": "ADvendio__Ad_price__c", "url": "/services/data/v46.0/sobjects/ADvendio__Ad_price__c/a0H2K00000VuuRDUAZ" }, "Id": "a0H2K00000VuuRDUAZ", "ADvendio__Ad_Spec__c": "a0F2K00000QxD3LUAV", "ADvendio__MaximumApplicability__c": 10.0000, "ADvendio__MaximumApplicabilityUnit__c": "Week", "ADvendio__EffectiveMaximumApplicability__c": 10.0000, "ADvendio__EffectiveMaximumApplicabilityUnit__c": "Week", "ADvendio__ConstantQuantity__c": "Runtime Campaign Item", "ADvendio__Exclusive__c": true, "ADvendio__Ad_Spec__r": { "attributes": { "type": "ADvendio__Ad_Specs__c", "url": "/services/data/v46.0/sobjects/ADvendio__Ad_Specs__c/a0F2K00000QxD3LUAV" }, "Id": "a0F2K00000QxD3LUAV", "ADvendio__Ad_Type__c": "a0G2K00001Uu7qTUAR", "RecordTypeId": "012A00000012g4SIAQ", "ADvendio__Placement__c": "a1M2K00000EhD7hUAF", "ADvendio__Ad_Type__r": { "attributes": { "type": "ADvendio__Ad_Type__c", "url": "/services/data/v46.0/sobjects/ADvendio__Ad_Type__c/a0G2K00001Uu7qTUAR" }, "Id": "a0G2K00001Uu7qTUAR" } } }, "ADvendio__SelectedContent__r": { "totalSize": 1, "done": true, "records": [ { "attributes": { "type": "ADvendio__SelectedContent__c" }, "ADvendio__Content__r": { "attributes": { "type": "ADvendio__Content__c", "url": "/services/data/v46.0/sobjects/ADvendio__Content__c/a0e2K00000fn85fQAA" }, "Id": "a0e2K00000fn85fQAA", "Name": "Store 1000", "ADvendio__ConstantQuantity__c": "Runtime Campaign Item", "ADvendio__MaximumApplicability__c": 1.0000, "ADvendio__MaximumApplicabilityUnit__c": "Week" }, "ADvendio__Content__c": "a0e2K00000fn85fQAA", "ADvendio__Availability__c": "{\"available\":true}" } ] }, "ADvendio__LastAvailabilityForecast__c": "2022-10-10T16:11:55.247+0000", "ADvendio__from_Date__c": "2022-11-09", "ADvendio__Exclusive__c": true, "ADvendio__until_Date__c": "2022-11-15", "ADvendio__RequestedContents__c": 1.0, "ADvendio__Ad_Price__c": "a0H2K00000VuuRDUAZ", "ADvendio__Frequency__c": 1.0, "Id": "a0Y000000000001EAA", "ADvendio__Availability__c": 2.0 } ]
1.8.6. Usage in Apex
List<ADvendio__Campaign_Item__c> cis = ... cis = ADvendio.CheckAvailabilityService.checkAvailability(cis); // there is no real option to wait in APEX, so getting the asynchronous results while running synchronous apex is not really usable while (ADvendio.JobStatusService.isAJobRunning(cis)) { wait some time cis = ADvendio.JobStatusService.getStatusAndWriteToCI(cis); }