The Walgreens Pharmacy Prescription API allows users of third-party applications to quickly order refills of prescriptions originally filled at one of the 8,200+ Walgreens pharmacies. Your app users can order refills in seconds, as well transfer non-Walgreens prescriptions to their nearest Walgreens to be notified when their prescription order is ready for pick up. The health care focused Pharmacy Prescription API is designed to increase prescription compliance and aid in personal health management through automated refill alerts and a streamlining of the refill process. By offering easy prescription refills through this health management API, Walgreens hopes to further increase health care adherence by reaching a wider audience through third party health care apps.
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 RX Refill or Transfer API:
This service is used to fetch the "landingURL" used for the Rx Refill API.
Sandbox: https://services-qa.walgreens.com/api/util/mweb5url
Production: https://services.walgreens.com/api/util/mweb5url
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" |
transaction | required | The Transaction is a value that invokes the refill service. The value must be "refillByScan". | "refillByScan" |
act | required | The Action is a value that invokes our internal service. | "mweb5Url" |
view | required | The View is a value that invokes our internal service. | "mweb5UrlJSON" |
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/util/mweb5url \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"transaction":"refillByScan", \
"act":"mweb5Url", \
"view":"mweb5UrlJSON", \
"devInf":"DEVICE,##.#" \
"appVer":"#.#", \
}' \
{
"landingUrl": "CHECKOUT LANDING URL",
"template": "TEMPLATE FOR CUSTOM TEMPLATES",
"token": "ACCESS TOKEN FOR CHECKOUT",
"err": "ERROR CODE NUMBER"
}
This service is used to open the "landingURL" used for the Rx Refill API.
Sandbox: [landingURL]
Production: [landingURL]
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Name | Optionality | Description | Example |
---|---|---|---|
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
token | required | The Token is a value that associates the checkout to the landingURL. The value must be re-obtained for every checkout. | "token" |
lat | optional | The Latitude coordinate of the user. | "42.138199" |
lng | optional | The Longitude coordinate of the user. | "-87.945799" |
rxNo | required | The rxNo is the number either scanned/manually entered by the customer. | Sample Prescription Numbers |
trackingId | optional | The trackingId is a value that can be used for tracking orders on your system. | "AAAAA" |
appID | required | The appId is a value that invokes our internal service. | "refillByScan" |
act | required | The Action is a value that invokes our internal service. | "chkExpRx" |
appVer | optional | The build version of your application. | "1.0" |
devInf | optional | The device manufacturer and version. | "iPhone,13.0" |
curl --location --request POST '{{RX_LANDING_URL}}' \
--form '"affId"=rxapi' \
--form '"token"={{RX_TOKEN}}' \
--form '"lat"=35.9218452' \
--form '"lng"=-86.7942764' \
--form '"rxNo"=0459772-59382' \
--form '"appCallBackScheme"=http://localhost:3000/callback' \
--form '"appCallBackAction"=refill' \
--form '"trackingId"=123456789' \
--form '"appId"=refillByScan' \
--form '"act"=chkExpRx' \
--form '"devinf"=Postman,1.0' \
--form '"appver"=1.0'\
{
"The HTML markup for the checkout of the Rx Refill API, that should be loaded into a WebView"
}
Once the user has loaded the checkout page there are some user engagements that must be handled by your callback URL passed in generating the checkout:
Value of appCallBackScheme passed in the request + ? + value of appCallBackAction passed in the request + = + the callback action value
Example of a call from the "Refill Another" button being pressed:
"appCallbackScheme://appCallbackScheme?appCallbackAction=fillAnother"
func application(_ app: UIApplication, open url: URL, options:
[UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool
{
let arrURL:Array = url.absoluteString.components(separatedBy: "?")
let arrQuery:Array = arrURL[1].components(separatedBy: "=")
if(url.scheme == "refiller" && arrQuery[0] == "action")
{
switch (arrQuery[1])
{
case "refillTryAgain":
//Open the Error View Controller, they entered an invalid Rx Number
case "cancel":
//Open the Error View Controller, customer chose to cancel their refill
case "back":
//Open the Error View Controller, customer chose to back out of the refill
case "close":
//Open the Success View Controller, their Rx is on its way
case "fillAnother":
//Open the Refill View Controller, they want to refill another Rx
default:
//Open the Error View Controller, something bad happened during checkout
}
return true
}
else {return false}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
Uri appCallbackURI = Uri.parse(url);
if (appCallbackURI != null && appCallbackURI.getScheme().equalsIgnoreCase("refiller"))
{
String action = appCallbackURI.getQueryParameter("action");
switch(action)
{
case action.equalsIgnoreCase("refillTryAgain"):
//Open the Error Activity, they entered an invalid Rx Number
case action.equalsIgnoreCase("cancel"):
//Open the Error Activity, customer chose to cancel their refill
case action.equalsIgnoreCase("back"):
//Open the Error Activity, customer chose to back out their refill
case action.equalsIgnoreCase("close"):
//Open the Success Activity, their Rx is on its way
case action.equalsIgnoreCase("fillAnother"):
//Open the Refill Activity, they want to refill another Rx
default:
//Open the Error Activity, something bad happened during checkout
}
}
}
@Override
public void onBackPressed()
{
if (webview.getVisibility() == View.VISIBLE)
{
if (webview.canGoBack())
{
//Java script call to dismiss the Native calendar Control
webview.loadUrl("javascript:dismissCalendar();");
//Java script call to handle page navigations
webview.loadUrl("javascript:nativeBackBtnClicked();");
}
else
{
Intent intent = new Intent(CustomWebView.this, MainActivity.class);
CustomWebView.this.startActivity(intent);
finish();
}
}
}
}
//Route in your app.js file, for the callback action we passed of "rx", the query string value
will be the value you passed when creating the checkout for
"appCallbackAction" app.get('/callback',function(req,res)
{
var rx = (req.query.rx) ? req.query.rx : "";
res.render("pages/callback",{title:rx,rx:rx});
});
//We use then use EJS to render content for the appropriate callback action value on callback.ejs
page (you can use any view rendering engine)
switch (rx) {
case 'refillTryAgain' :
Warning! Invalid Rx Number.
Try Again?
break;
case 'cancel' :
Warning! You have cancelled the refill.
Try Again?
break;
case 'back' :
Warning! You have backed out of the refill.
Try Again?
break;
case 'close' :
Success! The pharmacist has begun to process your refill.
Want a status Update?
break;
case 'fillAnother' :
//Send them to refill homepage to refill another
break;
}
}
This service is used to fetch the "landingURL" used for the Rx Transfer API.
Sandbox: https://services-qa.walgreens.com/api/util/mweb5url
Production: https://services.walgreens.com/api/util/mweb5url
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" |
transaction | required | The Transaction is a value that invokes the refill service. | "refillByScan" |
act | required | The Action is a value that invokes our internal service. | "mweb5Url" |
view | required | The View is a value that invokes our internal service. | "mweb5UrlJSON" |
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/util/mweb5url \
--header 'Content-Type: application/json' \
--data '{ \
"apiKey":"YOUR_API_KEY", \
"affId":"YOUR_AFFILIATE_ID", \
"transaction":"refillByScan", \
"act":"mweb5Url", \
"view":"mweb5UrlJSON", \
"devInf":"DEVICE,##.#" \
"appVer":"#.#", \
}' \
This service is used to make a web request to the "landingURL" used for the Rx Transfer API.
Sandbox: [landingURL]
Production: [landingURL]
Request format | JSON |
Response format | JSON |
Authentication? | Yes |
Rate limited? | Yes |
Requests Per Minute | 300 |
Name | Optionality | Description | Example |
---|---|---|---|
affId | required | Your AffiliateID. | "AAAAAAAAAA" |
token | required | The Token is a value that associates the checkout to the landingURL. The value must be re-obtained for every checkout. | "token" |
lat | optional | The Latitude coordinate of the user. | "42.138199" |
lng | optional | The Longitude coordinate of the user. | ""-87.945799" |
rxImg | required | The rxImg is the Base64 encoded image data as a string pulled from a picture of the customers pill bottle. | "rxImg.jpg" |
fname | optional | The customers first name. | "firstName" |
lname | optional | The customers last name. | "lastName" |
dob | optional | The customers date of birth. | "MM-DD-YYYY" |
phoneNbr | optional | The phone number of the customer. | "5555555555" |
pharmacyNbr | optional | The customers previous pharmacy phone number, usually placed on the Rx Label. | "5555555555" |
trackingId | optional | The trackingId is a value that can be used for tracking orders on your system. | "AAAAA" |
appID | required | The appId is a value that invokes our internal service. | "transferByScan" |
act | required | The Action is a value that invokes our internal service. | "transferRxHome" |
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/util/mweb5url \
--header 'Content-Type: application/json' \
--data '{ \
"affId":"YOUR_AFFILIATE_ID", \
"token":"ACCESS_TOKEN", \
"lat":"Latitude", \
"lng":"Longitude", \
"rxImg":"BASE64_ENCODED_IMAGE_DATA_STRING, \
"fname":CUSTOMER_FIRST_NAME", \
"lname":CUSTOMER_LAST_NAME", \
"dob":CUSTOMER_DATE_OF_BIRTH", \
"phoneNbr":CUSTOMER_PHONE_NUMBER", \
"pharmacyNbr":CUSTOMER_OLD_PHARMACY_PHONE_NUMBER", \
"trackingId":"TRACKING_ID", \
"appId":"transferByScan", \
"act":"transferRxHome", \
"appVer":"#.#", \
"devInf":"DEVICE,##.#" \
}' \
{
"The HTML markup for the checkout of the Rx Refill API, that should be loaded into a WebView"
}
Once the user has loaded the checkout page there are some user engagements that must be handled by your callback URL passed in generating the checkout:
Value of appCallBackScheme passed in the request + ? + value of appCallBackAction passed in the request + = + the callback action value
Example of a call from the "Refill Another" button being pressed:
"appCallbackScheme://appCallbackScheme?appCallbackAction=fillAnother"
func application(_ app: UIApplication, open url: URL, options:
[UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool
{
let arrURL:Array = url.absoluteString.components(separatedBy: "?")
let arrQuery:Array = arrURL[1].components(separatedBy: "=")
if(url.scheme == "transfer" && arrQuery[0] == "action")
{
switch (arrQuery[1])
{
case "txCancel":
//Open the Error View Controller,
//customer chose to cancel their transfer
case "txHome":
//Open the Error View Controller,
//customer chose to hit home on the checkout page
case "txDone":
//Open the Success View Controller,
//their transfer is on its way to the store!
case "txAnother":
//Open the Transfer View Controller,
//they want to transfer another Rx
default:
//Open the Error View Controller,
//something bad happened during checkout
}
return true
}
else {return false}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
Uri appCallbackURI = Uri.parse(url);
if (appCallbackURI != null
&& appCallbackURI.getScheme().equalsIgnoreCase("transfer")){
String action = appCallbackURI.getQueryParameter("action");
switch(action)
{
case action.equalsIgnoreCase("txCancel"):
//Open the Error View Controller, customer chose to
//cancel their transfer or back out of it
case action.equalsIgnoreCase("txHome"):
//Open the Error View Controller, customer chose to
//hit home on the checkout page
case action.equalsIgnoreCase("txDone"):
//Open the Success View Controller, their transfer
//is on its way to the store!
case action.equalsIgnoreCase("txAnother"):
//Open the Transfer View Controller,
//they want to transfer another Rx
default:
//Open the Error View Controller,
//something bad happened during checkout
}
}
}
@Override
public void onBackPressed()
{
if (webview.getVisibility() == View.VISIBLE)
{
if (webview.canGoBack())
{
//Java script call to dismiss the Native calendar Control
webview.loadUrl("javascript:dismissCalendar();");
//Java script call to handle page navigations
webview.loadUrl("javascript:nativeBackBtnClicked();");
}
else
{
Intent intent = new Intent(CustomWebView.this, MainActivity.class);
CustomWebView.this.startActivity(intent);
finish();
}
}
}
//Route in your app.js file, for the callback action we passed of "rx", the query
string value will be the value you passed when creating the checkout for
"appCallbackAction" app.get('/callback',function(req,res)
{
var rx = (req.query.rx) ? req.query.rx : "";
res.render("pages/callback",{title:rx,rx:rx});
});
//We use EJS to then render content for the appropriate callback action value
switch (rx) {
case 'txCancel' :
Warning! You have cancelled the transfer.
Try Again?
case 'txHome' :
Warning! You have backed out of the transfer.
Try Again?
break;
case 'txDone' :
Success! The pharmacist has begun to process your transfer.
Want a status Update?
case 'txAnother' :
//Send them to refill homepage to refill another
break;
Obviously we don't want any errors to happen, but sometimes they do and as a result we respond the following error codes. The table below helps explain why each of the error codes could occur:
Code | Type | Message |
---|---|---|
111,112,113,114,115,116 | ERROR | Configuration issues found in JSON body. |
117 | ERROR | We are unable to complete your request. Please try again later. |
118 | ERROR | A required attribute is missing in the request. |
120 | ERROR | The Rx Number is invalid. |
121 | ERROR | The Rx number entered is a Medicare Part B prescription. It can be refilled by calling 888-727-8265. |
122 | ERROR | The Rx number entered is a Mail Service prescription. It can be refilled by calling 866-525-1590. |
123,124,125,126,127 | ERROR | The Rx number entered cannot be filled at that store. Please select a different store. |
128 | ERROR | Network error, please try again. |
1001 | ERROR | We are unable to enroll you in Rx Text alerts at this time. Please try again later. |
1003 | ERROR | We are unable to complete your request. Please try again later. |
202 | ERROR | We are unable to complete your request. Please try again later. |
205 | ERROR | No request parameters found. |
209 | ERROR | We are unable to locate any stores based on your current location. |
ERR_DEFAULT | ERROR | We are unable to complete your request. |
ERR_PRES_CANT_PICKED | ERROR | Unable to refill that prescription now. Please contact the Pharmacist. |
VALIDATE_RX_WRN_MSG | ERROR | There are no refills left for that prescription. |
ERR_TEXT_SUBSCR | ERROR | Unable to enroll you in Rx Text alerts. Please try again later. |
ERR_NET_FAIL | ERROR | We are unable to complete your request. Please try again later. |
ERR_APP_ID_INCORRECT | ERROR | We are unable to locate any stores based on your current location. |
ALERT_ERR_INVALID_TIME | ERROR | Please select a valid store pickup time. |
ALERT_NO_STORES_FOUND | ERROR | We are unable to locate any stores based on your current location. |
ALERT_ERR_VALID_PHNO | ERROR | Customer entered a valid phone number. |
Code | Type | Message |
---|---|---|
603 | ERROR | We are unable to complete your request. Please try again later. |
630 | ERROR | Please enter a valid phone number. |
632 | ERROR | Please enter all required information. |
633 | ERROR | Please enter a valid pharmacy phone number. |
635 | ERROR | Sorry, failed to subscribe for text messages. |
636 | ERROR | A required attribute is missing in the request. |
638 | ERROR | Invalid SMS OPT Service. |
658 | ERROR | Missing device info. |
111,112,113,114,115,116 | ERROR | Configuration issues found in JSON body. |
118 | ERROR | A required attribute is missing in the request. |
202 | ERROR | We are unable to complete your request. Please try again later. |
205 | ERROR | No request parameters found. |
209 | ERROR | We are unable to locate any stores based on your current location. |
1003 | ERROR | We are unable to complete your request. Please try again later. |
ERR_GEN_PDF | ERROR | We are unable to complete your request. Please try again later. |
ERR_MISSING_MANDATORY_FLDS | ERROR | Please enter all required information. |
ERR_INVALID_PH_NO | ERROR | Please enter a valid phone number. |
ERR_INVALID_PHARMACY_PH_NO | ERROR | Please enter a valid pharmacy phone number. |
ERR_NO_RESPONSE | ERROR | We are unable to complete your request. Please try again later. |
ERR_DEFAULT | ERROR | We are unable to complete your request. Please try again later. |
ALERT_NO_STORES_FOUND | ERROR | We are unable to locate any stores based on your current location. |
ERR_APP_ID_INCORRECT | ERROR | Requested application not found in the configuration file. |