Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 218 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@



<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
Expand Down Expand Up @@ -53,6 +50,17 @@
- [Lightroom APIs](#lightroom-apis)
- [General Workflow](#general-workflow-2)
- [How to use the Lightroom API's](#how-to-use-the-lightroom-apis)
- [Using Webhooks through Adobe I/O Events](#using-webhooks-through-adobe-io-events)
- [Registering your application to our Event Provider](#registering-your-application-to-our-event-provider)
- [Prerequisites needed to use the Event Provider](#prerequisites-needed-to-use-the-event-provider)
- [Registering the Webhook](#registering-the-webhook)
- [Triggering an Event from the API's](#triggering-an-event-from-the-apis)
- [Example 1: /documentManifest (Retrieving a PSD manifest from the Photoshop API)](#example-1-documentmanifest-retrieving-a-psd-manifest-from-the-photoshop-api)
- [Step 1: Initiate a job to retrieve a PSD's JSON manifest](#step-1-initiate-a-job-to-retrieve-a-psds-json-manifest-1)
- [Step 2: Receive the Job's status on the Webhook application when the job is complete](#step-2-receive-the-jobs-status-on-the-webhook-application-when-the-job-is-complete)
- [Example 2: /autoTone (Auto tone an image through the Lightroom API)](#example-2-autotone-auto-tone-an-image-through-the-lightroom-api)
- [Step 1: Initiate a job to auto tone an image](#step-1-initiate-a-job-to-auto-tone-an-image)
- [Step 2: Receive the Job's status on the Webhook application when the job is complete](#step-2-receive-the-jobs-status-on-the-webhook-application-when-the-job-is-complete-1)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -935,3 +943,210 @@ The typical workflow involves making an API POST call to the endpoint https://im
## How to use the Lightroom API's

The API's are documented at [https://github.com/AdobeDocs/lightroom-api-docs](https://github.com/AdobeDocs/lightroom-api-docs/)

# Using Webhooks through Adobe I/O Events
Adobe I/O Events offers the possibility to build an event-driven application, based on events originating from Photoshop and Lightroom API's. To start listening for events, your application needs to register a webhook URL, specifying the Event Types to receive. Whenever a matching event gets triggered, your application is notified through an HTTP POST request to the webhook URL.
The Event Provider for Photoshop and Lightroom API's is `Imaging API Events`.
This event provider has two event types:
1. `Photoshop API events`
2. `Lightroom API events`

As the names indicate, these event types represent events triggered by the individual APIs.
## Registering your application to our Event Provider
### Prerequisites needed to use the Event Provider
1. Only supported for a `Service Integration`: To learn how to create a Service Integration, please refer to [this](https://github.com/AdobeDocs/photoshop-api-docs#service-token-workflow-adobe-etla-users) section of the document.
2. Make sure that the integration is created under your own Organization Role in https://console.adobe.io and this will ensure that you have a unique `Organization ID`. A typical ID would look something like this: `ABCDEF123B6CCB7B0A495E2E@AdobeOrg` and can be found in the overview section of the details of the integration.
3. Create a Webhook application. [This](https://www.adobe.io/apis/experienceplatform/events/docs.html#!adobedocs/adobeio-events/master/intro/webhook_docs_intro.md#your-first-webhook) page gives all the details of what the skeleton of a basic application would look like. You can find a sample NodeJS application [here](https://github.com/AdobeDocs/photoshop-api-docs/tree/master/sample_code/webhook-sample-app)

### Registering the Webhook
Once the above prerequisites are met, you can now proceed to register the webhook to the service integration. The steps to do that can be found [here](https://www.adobe.io/apis/experienceplatform/events/docs.html#!adobedocs/adobeio-events/master/intro/webhook_docs_intro.md#registering-the-webhook).
After the webhook has been successfully registered, you will start to receive the events for any submitted job that either succeeded or failed, from the Event Types selected. This eliminates the need for your application to poll for the status of the job using the jobID.
## Triggering an Event from the API's
In order to start receiving the events in your Webhook Application, the additional thing that needs to be done is to pass in your IMS ORG ID in a header: `x-gw-ims-org-id: <YOUR_IMS_ORG_ID>`, when you make an API call to initiate a job. Please have a look at the examples below that demonstrates the usage of the new header and a sample event received for that job.
### Example 1: /documentManifest (Retrieving a PSD manifest from the Photoshop API)

#### Step 1: Initiate a job to retrieve a PSD's JSON manifest

The `/documentManifest` api can take one or more input PSD's to generate JSON manifest files from. The JSON manifest is the tree representation of all of the layer objects contained in the PSD document. Using Example.psd, with the use case of a document stored in Adobe's Creative Cloud, a typical curl call might look like this:

```shell
curl -X POST \
https://image.adobe.io/pie/psdService/documentManifest \
-H 'Authorization: Bearer <auth_token>' \
-H 'Content-Type: application/json' \
-H 'x-api-key: <YOUR_API_KEY>' \
-H 'x-gw-ims-org-id: <YOUR_IMS_ORG_ID>' \
-d '{
"inputs": [
{
"href":"<SIGNED_GET_URL>",
"storage":"external"
}
]
}'
```

This initiates an asynchronous job and returns a response containing the href to poll for job status and the JSON manifest.
```json
{
"_links": {
"self": {
"href": "https://image.adobe.io/pie/psdService/status/63c6e812-6cb8-43de-8a60-3681a9ec6feb"
}
}
}
```
#### Step 2: Receive the Job's status on the Webhook application when the job is complete
The value in the key `body` inside the event JSON contains the result of the job. Here is a sample event received from the job initiated above:
```json
{
"event_id": "b412a90e-8bc0-4f0d-931e-9e9b8d24993d",
"event": {
"header": {
"msgType": "JOB_COMPLETION_STATUS",
"msgId": "8afa1a46-2733-406c-a646-e1c1acdee333",
"imsOrgId": "<YOUR_IMS_ORG_ID>",
"eventCode": "photoshop-job-status",
"_pipelineMeta": {
"pipelineMessageId": "1586288145511:631472:VA7_A1:142:0"
},
"_smarts": {
"definitionId": "3ee6c9056a9d72fc40e09ddf5fdbb0af752e8e49",
"runningSmartId": "psmart-yw6wosjksniuuathenny"
},
"_adobeio": {
"imsOrgId": "<YOUR_IMS_ORG_ID>",
"providerMetadata": "di_event_code",
"eventCode": "photoshop-job-status"
}
},
"body": {
"jobId": "63c6e812-6cb8-43de-8a60-3681a9ec6feb",
"outputs": [
{
"status": "succeeded",
"layers": [
{
"id": 2,
"index": 0,
"type": "layer",
"name": "Layer",
"locked": false,
"visible": true,
"bounds": {
"top": 0,
"left": 0,
"width": 100,
"height": 100
},
"blendOptions": {
"opacity": 100,
"mode": "normal"
}
}
],
"document": {
"name": "test.psd",
"width": 1000,
"height": 1000,
"bitDepth": 8,
"imageMode": "rgb",
"photoshopBuild": "Adobe Creative Imaging Service"
}
}
],
"_links":{
"self":{
"href":"https://image.adobe.io/pie/psdService/status/8ec6e4f5-b580-41ac-b693-a72f150fec59"
}
}
}
}
}
```
### Example 2: /autoTone (Auto tone an image through the Lightroom API)

#### Step 1: Initiate a job to auto tone an image
```shell
curl -X POST \
https://image.adobe.io/lrService/autoTone \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-H "x-api-key: <YOUR_API_KEY>" \
-H 'x-gw-ims-org-id: <YOUR_IMS_ORG_ID>' \
-d '{
"inputs": {
"href": "<SIGNED_GET_URL>",
"storage": "external"
},
"outputs": [
{
"href": "<SIGNED_PUT_URL>",
"type": "<type>",
"storage": "external",
"overwrite": <boolean>
}
]
}'
```

This initiates an asynchronous job and returns a request body containing the href to poll for job status.

```json
{
"_links": {
"self": {
"href": "https://image.adobe.io/lrService/status/eb4a9211-eb8a-4e88-b853-b9c08ba47427"
}
}
}
```
#### Step 2: Receive the Job's status on the Webhook application when the job is complete
The value in the key `body` inside the event JSON contains the result of the job. Here is a sample event received from the job initiated above:
```json
{
"event_id": "7b59cc70-88d7-4895-b204-87f5350a0cce",
"event": {
"header": {
"msgType": "JOB_COMPLETION_STATUS",
"msgId": "eb4a9211-eb8a-4e88-b853-b9c08ba47427",
"imsOrgId": "<YOUR_IMS_ORG_ID>",
"eventCode": "lightroom-job-status",
"_pipelineMeta": {
"pipelineMessageId": "1586290300876:944289:VA7_A1:149:0"
},
"_smarts": {
"definitionId": "3ee6c9056a9d72fc40e09ddf5fdbb0af752e8e49",
"runningSmartId": "psmart-yw6wosjksniuuathenny"
},
"_adobeio": {
"imsOrgId": "<YOUR_IMS_ORG_ID>",
"providerMetadata": "di_event_code",
"eventCode": "lightroom-job-status"
}
},
"body": {
"jobId": "eb4a9211-eb8a-4e88-b853-b9c08ba47427",
"outputs": [
{
"input": "<SIGNED_GET_URL>",
"status": "succeeded",
"_links": {
"self": [
{
"href": "<SIGNED_PUT_URL>",
"storage": "external"
}
]
}
}
],
"_links": {
"self": {
"href": "https://image.adobe.io/lrService/status/eb4a9211-eb8a-4e88-b853-b9c08ba47427"
}
}
}
}
}
```
10 changes: 10 additions & 0 deletions sample_code/webhook-sample-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Install Node.js packages
```bash
npm install http express body-parser
```
# Usage
Now, run the app:

```bash
node app.js
```
22 changes: 22 additions & 0 deletions sample_code/webhook-sample-app/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const HTTP = require('http');
const express = require('express');
const bodyParser = require('body-parser');

let app = express();
app.use(bodyParser.json({ limit: '10mb' }));

app.get('/', function(req, res) {
res.end(req.query.challenge);
});

app.post('/', function(req, res) {
console.log(JSON.stringify(req.body, null, 2));
res.end();
});

let startServer = function() {
HTTP.createServer(app).listen(8888);
console.log( { "events-server": "started" });
}

startServer();