API Programs > Prescription API

Prescription API


The Walgreens Prescription API's allows users of third-party applications to quickly order refills of prescriptions originally filled at Walgreens pharmacies. Your app users can order refills in seconds to their nearest Walgreens to be notified when their prescription order is ready for pick up.
The Walgreens Prescription API's also allow for users of third-party applications to quickly order transfers of prescriptions originally filled at other pharmacies. Your app users can order trasnfers in seconds to their nearest Walgreens to be notified when their prescription order is ready for pick up.
The healthcare focused Prescription API is designed to increase prescription compliance and aid in personal health management through streamlining the refill process. By offering easy prescription refills or transfers through this health management API, Walgreens hopes to further increase health care adherence by reaching a wider audience through third party health care apps.

Version Highlights /v2:

  • Update: Massive update to the endpoints and the UI for the Rx Checkout experience. BREAKING CHANGES

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 Prescription API's to Refill or Transfer:

Refill

  • Obtain:
    POST /api/pharmacy/fetch/v1
  • Open:
    GET {LANDING_URL}
  • Callback:
    GET {CALLBACK_URL}

Transfer

  • Obtain:
    POST /api/pharmacy/fetch/v1
  • Open:
    GET {LANDING_URL}
  • Callback:
    GET {CALLBACK_URL}

Obtain Refill

This service is used to fetch the "landingURL" used for the Rx Refill API.

Endpoint URL

Sandbox:
https://services-qa.walgreens.com/api/pharmacy/fetch/v1
Production:
https://services.walgreens.com/api/pharmacy/fetch/v1

Endpoint Information

Request format JSON
Response format JSON
Authentication? Yes
Rate limited? No

Request Body

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 "refill". "refill"
rxNumber optional The rxNumber is the number either scanned/manually entered by the customer, or from your system. Sample Prescription Numbers
callbackURL required The URL you want us to callback to at the end of any of the user flows. "https://www.example.com/callback"
devInf optional The device manufacturer and version. "iPhone,13.0"
appVer optional The build version of your application. "1.0"

Example Request

curl --request POST \
--url 'https://services-qa.walgreens.com/api/pharmacy/fetch/v1' \
--header 'Content-Type: application/json' \
--data '{
    "apikey":"YOUR_API_KEY",
    "affId":"YOUR_AFFILIATE_ID",
    "transaction":"refill",
    "rxNumber":"#######-#####",
    "callbackURL":"https://locahost:3000/callback",
    "devInf":"DEVICE,##.#",
	"appVer":"#.#"
}'
						

Example Response

{
    "landingUrl": "CHECKOUT LANDING URL",
    "errCode": "ERROR CODE NUMBER",
    "errMsg": "ERROR Message",
}
						

Open Refill

This service is used to open the "landingUrl" used for the Rx Refill API.

Endpoint URL

Sandbox:
{landingUrl}
Production:
{landingUrl}

Endpoint Information

Request format HTML
Response format HTML
Authentication? No
Rate limited? No

Request Params

NOTE: these are already included in the {landingUrl} value

Name Optionality Description Example
affiliateID required Your AffiliateID. "AAAAAAAAAA"
callbackURL required The callbackURL you asked us to callback to at the end of any of the user flows from the obtain refill request. "https://www.example.com/callback"
token required The token is a value that secures the checkout to the landingUrl and callbackURL. The value must be re-obtained for every checkout. "token"
rxNumber optional The rxNumber you asked us to refill from the obtain refill request. Sample Prescription Numbers

Example Request

curl --location --request GET '{{RX_LANDING_URL}}'
						
						

Example Response

{
    "The website for the checkout of the Rx Refill API, that should be made in the browser window or WebView"
}
					

Handling Refill Callbacks:

Once the user has completed their checkout on our website there are some user actions that must be handled by your callbackURL passed in obtaining the Refill API:

Possible Refill Callback Scenarios:

  • When the user taps the "BACK" button on the landing or confirmation page
  • When the user taps the "CANCEL" button to remove the Rx on the confirmation page
  • When the user is "DONE" by hitting the Submit Request button on the confirmation page
  • After an invalid "ERROR" in loading the API or pages


Example of a call from the Successful completion callback: "YOUR_CALLBACK_URL?affiliateID=YOUR_AFFILIATE_ID&action=refill&status=DONE"

//Make sure to implement the WKWebView delegates as needed
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    // Get the URL from the navigation action
    if let url = navigationAction.request.url {
        print(url)
        // Inspect the URL
        inspectURL(url)
        // Allow navigation to proceed
        decisionHandler(.allow)
    } else {
        // If there is no URL, deny the navigation
        decisionHandler(.cancel)
    }
}

private func inspectURL(_ url: URL) {
    // Parse the query parameters from the URL
    let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
    let queryItems = components?.queryItems
    
    //Check for a specific query parameter of action="refill"
    if let action:String = queryItems?.first(where: { $0.name == "action" })?.value, action.lowercased() == "refill" {
        print("Query parameter 'action' has value: \(action)")
        //Check for a specific query parmater of status= one of the various callback status values
        if let status = queryItems?.first(where: { $0.name == "status" })?.value?.lowercased() {
            print("Query parameter 'status' has value: \(status)")
            switch (status)
            {
                case "back":
                    print("Open the Error View Controller, customer backed out of their refill")
                    self.dismiss(animated: true)
                    break
                case "cancel":
                    print("Open the Error View Controller, customer cancelled out of the checkout")
                    self.dismiss(animated: true)
                    break
                case "done":
                    print("Open the Success View Controller, their Rx is on its way")
                    self.dismiss(animated: true)
                    break
                case "error":
                    print("Open the Error View Controller, some error happened in the checkout")
                    self.dismiss(animated: true)
                    break
                default:
                    print("Open the Error View Controller, some unknown callback happened")
                    print(status)
                    self.dismiss(animated: true)
                    break
            }
            return
        }
    }
}
//Make sure to implement the WebView overrides as needed
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
    val url = request.url.toString()
    println(url)
    inspectUrl(request.url.toString())
    return false // Allow WebView to handle the URL
}

private fun inspectUrl(url: String) {
    //Parse the URI string to extract the query string
    val uri = Uri.parse(url)
    val queryParams = uri.queryParameterNames

    //Check for a specific query parameter of action="refill"
    if (queryParams.contains("action")) {
        val action = uri.getQueryParameter("action")
        if (action.equals("refill", ignoreCase = false)) {
            println("Query parameter 'action' has value: $action")
            //Check for a specific query parmater of status= one of the various callback status values
            val status = uri.getQueryParameter("status")?.toLowerCase()
            if (status != null) {
                println("Query parameter 'status' has value: $status")
                when (status) {
                    "back" -> {
                        println("Open the Error View, customer backed out of their refill")
                        finish()
                    }
                    "cancel" -> {
                        println("Open the Error View, customer cancelled out of the checkout")
                        finish()
                    }
                    "done" -> {
                        println("Open the Success View, their Rx is on its way")
                        finish()
                    }
                    "error" -> {
                        println("Open the Error View, some error happened in the checkout")
                        finish()
                    }
                    else -> {
                        println("Open the Error View, some unknown callback happened")
                        println(status)
                        finish()
                    }
                }
            }
        }
    }
}
//Route in your express router or server.js file, for the callbackURL which was passed when obtaining the checkout in your callbackURL value.
app.get('/callback', (req, res) => {
    //Parse the URI string to extract the query string
    const action = req.query.action ? req.query.action.toLowerCase() : '',
        status = req.query.status ? req.query.status.toLowerCase() : '';

    console.log(`Query parameter 'action' has value: ${action}`);
    console.log(`Query parameter 'status' has value: ${status}`);

    //Check for a specific query parameter of action="refill"
    if(action !== "refill")
    {
        console.log(`Unknown Callback Action: ${action}`)
        return res.render('pages/callback', { type: "Error", message: 'Some unknown action happened' });
    }
    //Check for a specific query parmater of status= one of the various callback status values
    switch (status) {
        case 'back':
            res.render('pages/callback', { type: 'Warning', message: 'Backed out of refill' });
            break;
        case 'cancel':
            return res.render('pages/callback', { type: 'Warning', message: 'Cancelled refill' });
            break;
        case 'done':
            return res.render('pages/callback', { type: 'Success', message: 'Success, refill is on its way!' });
            break;
        case 'error':
            return res.render('pages/callback', { type: "Error", message: 'Some error happened when refilling' });
            break;
        default:
            console.log(`Unknown Callback Status: ${status}`)
            return res.render('pages/callback', { type: "Error", message: 'Some unknown callback happened' });
            break;
    }
});

//We use then use EJS to render content for the appropriate callback message value in the callback.ejs page (you can use any view rendering engine)
<%= type %>, <%= message %>

Obtain Transfer

This service is used to fetch the "landingURL" used for the Rx Transfer API.

Endpoint URL

Sandbox:
https://services-qa.walgreens.com/api/pharmacy/fetch/v1
Production:
https://services.walgreens.com/api/pharmacy/fetch/v1

Endpoint Information

Request format JSON
Response format JSON
Authentication? Yes
Rate limited? No

Request Body

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 transfer service. The value must be "transfer". "transfer"
callbackURL required The URL you want us to callback to at the end of any of the user flows. "https://www.example.com/callback"
devInf optional The device manufacturer and version. "iPhone,13.0"
appVer optional The build version of your application. "1.0"

Example Request

curl --request POST \
--url 'https://services-qa.walgreens.com/api/pharmacy/fetch/v1' \
--header 'Content-Type: application/json' \
--data '{
    "apikey":"YOUR_API_KEY",
    "affId":"YOUR_AFFILIATE_ID",
    "transaction":"transfer",
    "rxNumber":"#######-#####",
    "callbackURL":"https://locahost:3000/callback",
    "devInf":"DEVICE,##.#",
	"appVer":"#.#"
}'
						

Example Response

{
    "landingUrl": "CHECKOUT LANDING URL",
    "errCode": "ERROR CODE NUMBER",
    "errMsg": "ERROR Message",
}
						

Open Transfer

This service is used to open the "landingUrl" used for the Rx Transfer API.

Endpoint URL

Sandbox:
{landingUrl}
Production:
{landingUrl}

Endpoint Information

Request format HTML
Response format HTML
Authentication? No
Rate limited? No

Request Params

NOTE: these are already included in the {landingUrl} value

Name Optionality Description Example
affiliateID required Your AffiliateID. "AAAAAAAAAA"
callbackURL required The callbackURL you asked us to callback to at the end of any of the user flows from the obtain refill request. "https://www.example.com/callback"
token required The token is a value that secures the checkout to the landingUrl and callbackURL. The value must be re-obtained for every checkout. "token"

Example Request

curl --location --request GET '{{RX_LANDING_URL}}'
						
						

Example Response

{
    "The website for the checkout of the Rx Transfer API, that should be made in the browser window or WebView"
}
					

Handling Transfer Callbacks:

Once the user has completed their checkout on our website there are some user actions that must be handled by your callbackURL passed in obtaining the Transfer API:

Possible Transfer Callback Scenarios:

  • When the user taps the "BACK" button on the confirmation page
  • When the user taps the "CANCEL" button on the confirmation page
  • When the user is "DONE" by hitting the Submit Request button on the confirmation page
  • After an invalid "ERROR" in loading the API or pages


Example of a call from the Successful completion callback: "YOUR_CALLBACK_URL?affiliateID=YOUR_AFFILIATE_ID&action=transfer&status=DONE"

//Make sure to implement the WKWebView delegates as needed
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    // Get the URL from the navigation action
    if let url = navigationAction.request.url {
        print(url)
        // Inspect the URL
        inspectURL(url)
        // Allow navigation to proceed
        decisionHandler(.allow)
    } else {
        // If there is no URL, deny the navigation
        decisionHandler(.cancel)
    }
}

private func inspectURL(_ url: URL) {
    // Parse the query parameters from the URL
    let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
    let queryItems = components?.queryItems
    
    //Check for a specific query parameter of action="transfer"
    if let action:String = queryItems?.first(where: { $0.name == "action" })?.value, action.lowercased() == "transfer" {
        print("Query parameter 'action' has value: \(action)")
        //Check for a specific query parmater of status= one of the various callback status values
        if let status = queryItems?.first(where: { $0.name == "status" })?.value?.lowercased() {
            print("Query parameter 'status' has value: \(status)")
            switch (status)
            {
                case "back":
                    print("Open the Error View Controller, customer backed out of their transfer")
                    self.dismiss(animated: true)
                    break
                case "cancel":
                    print("Open the Error View Controller, customer cancelled out of the checkout")
                    self.dismiss(animated: true)
                    break
                case "done":
                    print("Open the Success View Controller, their Rx is on its way")
                    self.dismiss(animated: true)
                    break
                case "error":
                    print("Open the Error View Controller, some error happened in the checkout")
                    self.dismiss(animated: true)
                    break
                default:
                    print("Open the Error View Controller, some unknown callback happened")
                    print(status)
                    self.dismiss(animated: true)
                    break
            }
            return
        }
    }
}
//Make sure to implement the WebView overrides as needed
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
    val url = request.url.toString()
    println(url)
    inspectUrl(request.url.toString())
    return false // Allow WebView to handle the URL
}

private fun inspectUrl(url: String) {
    //Parse the URI string to extract the query string
    val uri = Uri.parse(url)
    val queryParams = uri.queryParameterNames

    //Check for a specific query parameter of action="transfer"
    if (queryParams.contains("action")) {
        val action = uri.getQueryParameter("action")
        if (action.equals("transfer", ignoreCase = false)) {
            println("Query parameter 'action' has value: $action")
            //Check for a specific query parmater of status= one of the various callback status values
            val status = uri.getQueryParameter("status")?.toLowerCase()
            if (status != null) {
                println("Query parameter 'status' has value: $status")
                when (status) {
                    "back" -> {
                        println("Open the Error View, customer backed out of their transfer")
                        finish()
                    }
                    "cancel" -> {
                        println("Open the Error View, customer cancelled out of the checkout")
                        finish()
                    }
                    "done" -> {
                        println("Open the Success View, their Rx is on its way")
                        finish()
                    }
                    "error" -> {
                        println("Open the Error View, some error happened in the checkout")
                        finish()
                    }
                    else -> {
                        println("Open the Error View, some unknown callback happened")
                        println(status)
                        finish()
                    }
                }
            }
        }
    }
}
//Route in your express router or server.js file, for the callbackURL which was passed when obtaining the checkout in your callbackURL value.
app.get('/callback', (req, res) => {
    //Parse the URI string to extract the query string
    const action = req.query.action ? req.query.action.toLowerCase() : '',
        status = req.query.status ? req.query.status.toLowerCase() : '';

    console.log(`Query parameter 'action' has value: ${action}`);
    console.log(`Query parameter 'status' has value: ${status}`);

    //Check for a specific query parameter of action="refill"
    if(action !== "transfer")
    {
        console.log(`Unknown Callback Action: ${action}`)
        return res.render('pages/callback', { type: "Error", message: 'Some unknown action happened' });
    }
    //Check for a specific query parmater of status= one of the various callback status values
    switch (status) {
        case 'back':
            res.render('pages/callback', { type: 'Warning', message: 'Backed out of transfer' });
            break;
        case 'cancel':
            return res.render('pages/callback', { type: 'Warning', message: 'Cancelled transfer' });
            break;
        case 'done':
            return res.render('pages/callback', { type: 'Success', message: 'Success, transfer is on its way!' });
            break;
        case 'error':
            return res.render('pages/callback', { type: "Error", message: 'Some error happened when transfering' });
            break;
        default:
            console.log(`Unknown Callback Status: ${status}`)
            return res.render('pages/callback', { type: "Error", message: 'Some unknown callback happened' });
            break;
    }
});

//We use then use EJS to render content for the appropriate callback message value in the callback.ejs page (you can use any view rendering engine)
<%= type %>, <%= message %>

Error Codes

Error Codes for Rx Refill API

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
403 ERROR Invalid JSON or Invalid APIKey.
500 ERROR Gateway or Server Error, please contact API team.

Error Codes for Rx Transfer API

Code Type Message
403 ERROR Invalid JSON or Invalid APIKey.
500 ERROR Gateway or Server Error, please contact API team.