What Programmatically Triggers Magento 2's Shipping Rates to Update

in vendor/magento/module-checkout/view/frontend/web/js/model/shipping-rate-service.js:21 there is a subscribe to the shipping address observerable quote.shippingAddress.

    quote.shippingAddress.subscribe(function () {
        var type = quote.shippingAddress().getType();

        if (processors[type]) {
            processors[type].getRates(quote.shippingAddress());
        } else {
            processors.default.getRates(quote.shippingAddress());
        }
    });

In the callback funtion this calls to the getRates function in vendor/magento/module-checkout/view/frontend/web/js/model/shipping-rate-processor/new-address.js

getRates does an ajax call using the url build via the getUrlForEstimationShippingMethodsForNewAddress method you mentioned in your question and uses the result to update the rateRegistry and sets the shipping rates on the shippingRates observerable of the shipping service.

       getRates: function (address) {
            shippingService.isLoading(true);
            var cache = rateRegistry.get(address.getCacheKey()),
                serviceUrl = resourceUrlManager.getUrlForEstimationShippingMethodsForNewAddress(quote),
                payload = JSON.stringify({
                        address: {
                            'street': address.street,
                            'city': address.city,
                            'region_id': address.regionId,
                            'region': address.region,
                            'country_id': address.countryId,
                            'postcode': address.postcode,
                            'email': address.email,
                            'customer_id': address.customerId,
                            'firstname': address.firstname,
                            'lastname': address.lastname,
                            'middlename': address.middlename,
                            'prefix': address.prefix,
                            'suffix': address.suffix,
                            'vat_id': address.vatId,
                            'company': address.company,
                            'telephone': address.telephone,
                            'fax': address.fax,
                            'custom_attributes': address.customAttributes,
                            'save_in_address_book': address.saveInAddressBook
                        }
                    }
                );

            if (cache) {
                shippingService.setShippingRates(cache);
                shippingService.isLoading(false);
            } else {
                storage.post(
                    serviceUrl, payload, false
                ).done(
                    function (result) {
                        rateRegistry.set(address.getCacheKey(), result);
                        shippingService.setShippingRates(result);
                    }
                ).fail(
                    function (response) {
                        shippingService.setShippingRates([]);
                        errorProcessor.process(response);
                    }
                ).always(
                    function () {
                        shippingService.isLoading(false);
                    }
                );
            }
        }

The above show how the shipping methods get updated below will show how the quote.shippingAddres.subscribe is triggered:

The short version Each shipping method has validation rules set against some of the shipping fields, these fields plus the postcode fields are observered via the knockoutjs 'value' binding and once this is triggered it updates the shipping address and this in turn as mentioned previously updates the shipping methods.

The long version I will now explain the long version looking at the free shipping method, as this seems to be the same for all other included shipping methods.

on page load The view component Magento_OfflineShipping/js/view/shipping-rates-validation/freeshipping gets loaded via vendor/magento/module-offline-shipping/view/frontend/layout/checkout_index_index.xml

This makes a call to

defaultShippingRatesValidationRules.registerRules('freeshipping', freeshippingShippingRatesValidationRules); 

which uses the following

/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
/*global define*/
define(
[],
function () {
    "use strict";
    return {
        getRules: function() {
            return {
                'country_id': {
                    'required': true
                }
            };
        }
    };
}

from vendor/magento/module-offline-shipping/view/frontend/web/js/model/shipping-rates-validation-rules/freeshipping.js

to set up the rateRules in vendor/magento/module-checkout/view/frontend/web/js/model/shipping-rates-validation-rules.js

after this the vendor/magento/module-checkout/view/frontend/web/js/view/shipping.js module gets loaded, which on initialize calls:

shippingRatesValidator.initFields(fieldsetName);

from vendor/magento/module-checkout/view/frontend/web/js/model/shipping-rates-validator.js

initFields: function (formPath) {
            var self = this,
                elements = shippingRatesValidationRules.getObservableFields();

            if ($.inArray(postcodeElementName, elements) === -1) {
                // Add postcode field to observables if not exist for zip code validation support
                elements.push(postcodeElementName);
            }

            $.each(elements, function (index, field) {
                uiRegistry.async(formPath + '.' + field)(self.doElementBinding.bind(self));
            });
        },

where

elements = shippingRatesValidationRules.getObservableFields();

uses the previously set up rate rules to get the fields to observe

it then adds the postcode fields if it is not set up yet and calls doElementBinding method on each element which calls this.bindHandler, which has the following:

  element.on('value', function () {
                    clearTimeout(self.validateAddressTimeout);
                    self.validateAddressTimeout = setTimeout(function () {
                        if (self.postcodeValidation()) {
                            self.validateFields();
                        }
                    }, delay);
                });

which calls self.validateFields();

        validateFields: function () {
            var addressFlat = addressConverter.formDataProviderToFlatData(
                    this.collectObservedData(),
                    'shippingAddress'
                ),
                address;

            if (this.validateAddressData(addressFlat)) {
                address = addressConverter.formAddressDataToQuoteAddress(addressFlat);
                selectShippingAddress(address);
            }
        },

which calls selectShippingAddress(address); which in turn sets the shippingAddress observerable.

  /**
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 /*global define*/
 define(
   [
    'Magento_Checkout/js/model/quote'
   ],
    function(quote) {
      'use strict';
         return function(shippingAddress) {
            quote.shippingAddress(shippingAddress);
       };
   }
);

To force reloading of shipping methods try,

define(
    [
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/model/shipping-rate-processor/new-address',
        'Magento_Checkout/js/model/shipping-rate-processor/customer-address',
        'Magento_Checkout/js/model/shipping-rate-registry'

    ],
    function (quote, defaultProcessor, customerAddressProcessor, rateRegistry) {
       'use strict';

       var processors = [];

       rateRegistry.set(quote.shippingAddress().getCacheKey(), null);

       processors.default =  defaultProcessor;
       processors['customer-address'] = customerAddressProcessor;

       var type = quote.shippingAddress().getType();

       if (processors[type]) {
          processors[type].getRates(quote.shippingAddress());
       } else {
          processors.default.getRates(quote.shippingAddress());
       }

    }
);