The Native Photo Prints API enables third party integrations to upload photos, fetch product details, validate coupons, search for stores, and finally submit orders for same-day printing of photo orders at any one of our thousands of Walgreens Stores. Once an order has been submitted its order status can be fetched.
Below are the technical steps you will need to go through in order to get your integration configured and branded correctly:
The following API endpoints can be used to programmatically integrate all functions of the Native Photo Prints API experience:
This endpoint can be used to fetch the credentials needed to upload images to the Walgreens Storage server. Take note, when uploading to our storage, the files will not be accessible once uploaded and you should save image data if planning to use later in your checkout flow for previewing the images.
Sandbox: https://services-qa.walgreens.com/api/photo/creds/v3
Production: https://services.walgreens.com/api/photo/creds/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Name | Optionality | Description | Example |
---|---|---|---|
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
platform | required | The software platform. | "ios" || "android" |
transaction | required | A static value describing the reason for fetching the credentials. | "photocheckoutv2" |
appVer | optional | The build version of your application. | "1.0" |
devInf | optional | The device manufacturer and version. | "iPhone,13.0" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/creds/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"platform":"ios", \
"transaction":"photocheckoutv2", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#" \
}' \
{
"uploadLimit": 200,
"template": "default",
"landingUrl": "https://m5.walgreens.com/photoprints/",
"cloud": [{
"sasKeyToken": "https://pstrgqp01.blob.core.windows.net/qpcontainerin?sig=BLAHBLAHBLAH&se=YYYY-MM-DDT22%3A53%3A57Z&sv=YYYY-MM-DD&sp=w&sr=c"
}]
}
Before an image can be uploaded, the value for the sasKeyToken (looks like a url) must be converted correctly into the Upload_URL. This is completed by doing the following:
SWIFT:
let blobContainer:String = sasToken.components(separatedBy: "?").first!
let signature:String = sasToken.components(separatedBy: "?").last!
let imageName:String = "Image-\(affId)-\(UUID().uuidString).jpg"
let Upload_URL:String = "\(blobContainer)/\(imageName)?\(signature)"
KOTLIN:
var blobContainer:String = sasToken.split("?").toTypedArray().first()
var signature:String = sasToken.split("?").toTypedArray().last()
var imageName:String = "Image-".plus(affId).plus("-").plus(UUID.randomUUID().toString()).plus(".jpg")
var Upload_URL:String = blobContainer.plus("/").plus(imageName).plus("?").plus(signature)
JAVASCRIPT:
function generateUUID()
{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)
{
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
var blobContainer = sasToken.split("?").shift();
var signature = sasToken.split("?").pop();
var imageName = "Image-"+affId+"-"+generateUUID()+".jpg";
var Upload_URL = blobContainer+"/"+imageName+"?"+signature;
https://pstrgqp01.blob.core.windows.net/qpcontainerin/Image-YOUR_AFFILIATE_ID-a12b3cd-e4f5-6789-ghi0-1234567j89kl.jpg?sig=BLAHBLAHBLAH&se=YYYY-MM-DDT22%3A53%3A57Z&sv=YYYY-MM-DD&sp=w&sr=c
To upload an image, make a PUT request to the generated UPLOAD_URL with the custom HTTP headers. Place the image data to be uploaded in the HTTP body. If multiple images are to be printed, repeat the process above for every single image.
The image url is generated using the process above.
Request format | Binary Data |
Response format | XML |
Authentication? | Yes |
Rate limited? | No |
Name | Optionality | Description | Example |
---|---|---|---|
Content-Type | required | The type of image format for the file. We convert the file to JPEG on our side, however we prefer you do this on your side. | image/jpeg |
Content-Length | required | The count of the bytes of data in the image file. | 1073741824 |
x-ms-client-request-id | required | A Universally Unique Identifier (UUID) for each request. | a12b3cd-e4f5-6789-ghi0-1234567 |
x-ms-blob-type | required | A static value describing the request upload type. | BlockBlob |
curl -X PUT \
'https://pstrgqp01.blob.core.windows.net/qpcontainerin/Image-YOUR_AFFILIATE_ID-a12b3cd-e4f5-6789-ghi0-1234567j89kl.jpg?sig=BLAHBLAHBLAH&se=YYYY-MM-DDT22%3A53%3A57Z&sv=YYYY-MM-DD&sp=w&sr=c' \
-H 'Content-Length: 1073741824' \
-H 'Content-Type: image/jpeg' \
-H 'x-ms-blob-type: BlockBlob' \
-H 'x-ms-client-request-id: a12b3cd-e4f5-6789-ghi0-1234567' --upload-file image.jpeg
HTTP STATUS CODE: 201
You are absolutely able to use your own url for images uploaded to another server then the Walgreens server. Please ensure the url is accessible for at least 36 hours (due to delays at store level) with a simple HTTP Get Request and that as that is how our image downloader will get the file to the store.
Used to get the list of photo products & price details that have been configured for your application. You should call this every single time you are showing products or prices in your UI to the customer. Prices and Products are subject to change at anytime.
Sandbox: https://services-qa.walgreens.com/api/photo/products/v3
Production: https://services.walgreens.com/api/photo/products/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Name | Optionality | Description | Example |
---|---|---|---|
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
productGroupId | optional | Used to differentiate product groups for filtering the product list results. | "STDPR" || "SQR01" |
act | required | A static value that tells our service what action the request is making. | "getphotoprods" |
appVer | optional | The build version of your application. | "1.0" |
devInf | optional | The device manufacturer and version. | "iPhone,13.0" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/products/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"productGroupId":"STDPR", \
"act":"getphotoprods", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#" \
}' \
{
"errDesc": "",
"err": "",
"products": [{
"productId": "The Product Id",
"boxQty": "The number of times the image is printed for this product",
"productSize": "4x6",
"productGroupId": "STDPR",
"offsetWidth": "Offset width from edge of image for product",
"woodFrameColor": "Wood Frame Color (Floating Frames only)",
"templateUrl": "A template url (Creative Products only)",
"productDesc": "4x6 Internet Print",
"portraitTemplateUrl": "A portrait template url (Creative Products only)",
"resWidth": "Resolution width (Creative products only)",
"offsetHeight": "Offset height from edge of image for product",
"vendorQtyLimit": "Limit of Product per Order (Creative Products only)",
"backerBoardColor": "Board Back Color (Floating Frames only)",
"dpi": "Dots Per Inch (Creative products only)",
"multiImageIndicator": "Y || N (Creative products only)",
"resHeight": "Resolution height (Creative products only)",
"productPrice": "The price of the product, ex 0.01"
},
...shortened for brevity
]
}
Used to validate a coupon code & retrieve offer details and the updated price. The couponCode
should only be added to the submit order request body if it has been successfully validated with this endpoint.
Sandbox: https://services-qa.walgreens.com/api/photo/order/coupon/v3
Production: https://services.walgreens.com/api/photo/order/coupon/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 100 |
orderDiscountPrice
must be subtracted off the order total price. With an orderTotalPrice
of $40 with a coupon code for 20% off, you would get an orderDiscountPrice
of $8.orderTotalPrice
- orderDiscountPrice
= New Subtotal.
Example: $40 - $8 = $32
Coupons from other partners or walgreens.com or the Walgreens app will not work in your application integration. Only offer codes we have specifically setup for your application integration will work with your credentials. Please feel free to ask about any sort of promotions we are always happy to work on new business promotions.
Name | Optionality | Description | Example |
---|---|---|---|
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
couponCode | required | The actual coupon code being applied to the order. | "TESTFORALL" |
act | required | A static value that tells our service what action the request is making. | "getdiscount" |
appVer | required | The build version of your application. | "1.0" |
devInf | required | The device manufacturer and version. | "iPhone,13.0" |
productDetails | required | An array of JSON Product objects. JSON Product objects will contain the two below parameters. | [{"productId":"0000001",
"qty":"10"},
{"productId":"0000002",
"qty":"1"}]
|
productId | required | The Product Id obtained from the service above which the user has selected to add to the cart. | "0000001" |
qty | required | This is the quantity of the product that the customer has selected to add to the cart. | "10" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/order/coupon/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"couponCode":"TESTFORALL", \
"act":"getdiscount", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#", \
"productDetails":[{ \
"productId":"0000001", \
"qty":"10" \
}], \
}' \
{
"errDesc": "",
"err": "",
"orderTotalPrice": 40.00,
"orderDiscountPrice": 8.00,
"status": "success"
}
Used to retrieve list of available & applicable photo printing stores near customer. This endpoint takes into account the stores that are currently available to print an order based on the cart that that the user has built.
Sandbox: https://services-qa.walgreens.com/api/photo/store/v3
Production: https://services.walgreens.com/api/photo/store/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
No Promise Time:
Walgreens refers to select stores as being in a state called "No Promise Time" when the "promiseTime" for a store is returned as "01-01-3000 00:00 AM"
. This means that the store is temporarily unavailable (e.g. maintenance window/upgrades), but is expected to be operational within 48 hours. In such cases, the pickup time should be displayed as "Within 48 hours" in the customer facing user interface. When placing the order for such stores, the same time stamp string must be passed when placing an order aka the API call below. As long as stores in this state are back operational within 48 hours, the orders will be submitted and fulfilled. If not, the orders in question will be systematically cancelled and the end customer will receive an order cancellation email.
Name | Optionality | Description | Example |
---|---|---|---|
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
latitude | required | The actual latitude of the customer. | "41.880977" |
longitude | required | The actual longitude of the customer. | "-87.626481" |
act | required | A static value that tells our service what action the request is making. | "photoStores" |
appVer | required | The build version of your application. | "1.0" |
devInf | required | The device manufacturer and version. | "iPhone,13.0" |
productDetails | required | An array of JSON Product objects. JSON Product objects will contain the two below parameters. | [{"productId":"0000001",
"qty":"10"},
{"productId":"0000002",
"qty":"1"}]
|
productId | required | The Product Id obtained from the service above which the user has selected to add to the cart. | "0000001" |
qty | required | This is the quantity of the product that the customer has selected to add to the cart. | "10" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/store/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"latitude":"41.880977", \
"longitude":"-87.626481", \
"act":"photoStores", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#", \
"productDetails":[{ \
"productId":"0000001", \
"qty":"10" \
}], \
}' \
{
"status": "success",
"errCode": "",
"errDesc": "",
"photoStores": [{
"photoStoreDetails": {
"storeNum": "STORE NUMBER",
"promiseTime": "STORE PROMISE TIME",
"type": "STORE TYPE WAG/DR",
"zip": "STORE ZIP CODE",
"city": "STORE CITY",
"state": "STORE STATE",
"street": "STORE STREET",
"county": "STORE COUNTY",
"latitude": "STORE LATITUDE",
"longitude": "STORE LONGITUDE",
"phone": "STORE PHONE NUMBER",
"distance": "USER DISTANCE FROM STORE",
"distanceUnit": "DISTANCE UNIT OF MEASUREMENT",
"openTime": "STORE OPEN TIME",
"closeTime": "STORE CLOSE TIME",
"extendedHours": "STORE HAS EXTENDED HOURS",
"storeName": "STORE NAME",
"holidayEventName": "HOLIDAY EVENT NAME",
"timeZone": "STORE TIME ZONE",
"tax": "STORE TAX PERCENTAGE"
}
},
...shortened for brevity
]
}
This endpoint can be used to submit the order containing the selected products, applicable coupon code, and selected store.
Sandbox: https://services-qa.walgreens.com/api/photo/order/submit/v3
Production: https://services.walgreens.com/api/photo/order/submit/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Order Limits:
Please ensure that the order has a post-coupon price that is less then $998, and the order has a maximum of 200 distinct images, with a maximum print quantity of 20 image urls for standard prints.
Terms and Conditions:
Your application must contain a UI element that the customer must take an action on every single order with the following copy (Example: Checkbox, Toggle Switch):
Name | Optionality | Example | |
---|---|---|---|
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
publisherId | optional | Your Publisher Id, Learn more here: https://developer.walgreens.com/support/revenue-share. | "12345678" |
firstName | required | The First Name of the customer. A required input from the user. | "John" |
lastName | required | The Last Name of the customer. A required input from the user. | "Smith" |
phone | required | The Phone Number of the customer. A required input from the user. | "8009254733" |
required | The Email of the customer. A required input from the user. | "apibizdev@walgreens.com" |
|
couponCode | optional | If the couponCode has been validated for the cart, pass the couponCode here. | "TESTFORALL" |
storeNum | required | The store number selected by the customer returned from the Store Search endpoint. | "211" |
promiseTime | required | The promise time of the store selected by the customer returned from the Store Search endpoint, must be fetched uniquely for every order. | "MM-DD-YYYY H:MM AM/PM" |
affNotes | optional | The notes to the printer, if needed. Can also be used to pass a unique tracking ID from your side that we can reference later for reporting. | "12345678" || "Don't put a backing on the frame" |
act | required | A static value that tells our service what action the request is making. | "submitphotoorder" |
appVer | required | The build version of your application. | "1.0" |
devInf | required | The device manufacturer and version. | "iPhone,13.0" |
productDetails | required | An array of JSON ProductDetails objects. JSON ProductDetails objects will contain the two below parameters. | [{
"productId":"0000001",
"imageDetails":SEE BELOW
},
{
"productId":"0000002",
"imageDetails":SEE BELOW
},
...Repeated for every unique productId
]
|
productId | required | The Product Id obtained from the service above which the user has selected to add to the cart. | "0000001" |
imageDetails | required | An array of JSON imageDetails objects. JSON imageDetails objects will contain the two below parameters. | [{
"qty":"1",
"url":"UPLOAD_URL"
},
...Repeated for each image for a productId
] |
url | required | This is the url where the image is uploaded. | "UPLOAD_URL" |
qty | required | This is the quantity of the product that the customer has selected to add to the cart. | "10" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/order/submit/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"publisherId": "YOUR PUBLISHER ID", \
"firstName": "CUSTOMER FIRST NAME", \
"lastName": "CUSTOMER LAST NAME", \
"phone": "CUSTOMER PHONE NUMBER", \
"email": "CUSTOMER EMAIL ADDRESS", \
"storeNum": "STORE NUMBER SELECTED", \
"promiseTime": "PROMISE TIME FOR SELECTED STORE", \
"affNotes": "TRACKING ID FOR YOUR LOGS", \
"act": "submitphotoorder", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#" \
"productDetails": [{ \
"productId": "PRODUCT ID", \
"imageDetails":[{ \
"qty": "IMAGE URL QUANTITY", \
"url": "IMAGE URL" \
},{
"qty": "IMAGE URL QUANTITY", \
"url": "IMAGE URL" \
}] \
},{ \
"productId": "PRODUCT ID", \
"imageDetails":[{ \
"qty": "IMAGE URL QUANTITY", \
"url": "IMAGE URL" \
}] \
}] \
}' \
{
"vendorOrderId": "0000000001",
"err": "",
"errDesc": "",
"status": "success"
}
Used to submit multiple products with multiple quantities. It will collect all the necessary information required for the request to submit multiple products.
Sandbox: https://services-qa.walgreens.com/api/photo/order/submit/v3
Production: https://services.walgreens.com/api/photo/order/submit/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Name | Optionality | Description | Example |
---|---|---|---|
firstName | required | First lame of the customer | "firstName" |
lastName | required | Last name of the customer | "lastName" |
phone | required | Phone number | "##########" |
required | The email value is the email address of the customer. | "email@domain.tld" |
|
storeNum | required | The store number selected by the customer returned from the Store Search endpoint. | "211" |
promiseTime | required | The promise time of the store selected by the customer returned from the Store Search endpoint, must be fetched uniquely for every order. | "MM-DD-YYYY H:MM AM/PM" |
currencyType | required | The type of currency that is used | "1" |
productDetails | required | An array of JSON ProductDetails objects. JSON ProductDetails objects will contain the two below parameters. | [{
"productId":"0000001",
"imageDetails":SEE BELOW
},
{
"productId":"0000002",
"imageDetails":SEE BELOW
},
...Repeated for every unique productId
]
|
sdkVer | required | The version of the sdk | "1.0.0" |
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
act | required | A static value telling our service what to do, always set to the value "storenumber". | "storenumber" |
appVer | optional | The build version of your application. | "1.0" |
devInf | optional | The device manufacturer and version. | "iPhone,13.0" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/order/submit/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"firstName":"OneFoldedCard",
"lastName":"foldedcard",
"phone":"5555555555",
"email":"email@email.com",
"storeNum":"59181",
"promiseTime":"03-02-2020 5:15 PM",
"currencyType":"1",
"productDetails": [{
"multiImageQuantity": "10", // Order quantity is counted based on this value
"productId": "8420005",
"imageDetails": [{
"url": "https://www.walgreens.com/livestyleguide/walgreens.com/v3.0/
themes/images/global/logo-corner-red.png",
"qty": "1"
}, {
"url": "http://clipart-library.com/images/rTjraz5yc.jpg",
"qty": "1"
}]
}],
"sdkVer":"3.4.5",
"devinf":"DEVICE,##.#",
"appver":"1.0",
"act":"submitphotoorder",
"affId":"YOUR_API_KEY",
"apikey":"YOUR_API_KEY"
}
// multiImageQuantity parameter is optional value for non creative print products
This endpoint can be used to report on the status of orders based on an array of vendorOrderId
. At least one valid vendorOrderId
is needed to get back a valid status.
Sandbox: https://services-qa.walgreens.com/api/photo/order/status/v3
Production: https://services.walgreens.com/api/photo/order/status/v3
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Name | Optionality | Description | Example |
---|---|---|---|
apiKey | required | Your API Key. | "AbCdEfGhIjKlMnOpQrStUvWxYz" |
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
orders | required | An array of vendor order Id's. | ["0000000001"] |
act | required | A static value that tells our service what action the request is making. | "orderstatus" |
appVer | optional | The build version of your application. | "1.0" |
devInf | optional | The device manufacturer and version. | "iPhone,13.0" |
curl --request POST \
--url https://services-qa.walgreens.com/api/photo/order/status/v3 \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"orders": ["0000000001","0000000002","0000000003"], \
"act": "orderstatus", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#" \
}' \
{
"errDesc": "",
"err": "",
"statuses": [{
"valid": "true",
"code": "0",
"orderId": "0000000001",
"orderStatus": "Submitting"
},
{
"valid": "true",
"code": "1",
"orderId": "0000000002",
"orderStatus": "Downloading"
},
{
"valid": "false",
"code": "",
"orderId": "0000000003",
"orderStatus": ""
}]
}
Possible codes: