API throttling guidance for partners calling Partner Center APIs

Microsoft is implementing API throttling to allow more consistent performance within a time span for partners calling the Partner Center APIs. Throttling limits the number of requests to a service in a time span to prevent overuse of resources. While Partner Center is designed to handle a high volume of requests, if an overwhelming number of requests occur by few partners, throttling helps maintain optimal performance and reliability for all partners.

Throttling limits vary based on the scenario. For example, if you're performing a large volume of writes, the possibility for throttling is higher than if you're only performing reads.

What happens when throttling occurs?

When a throttling threshold is exceeded, Partner Center limits any further requests from that client for a period of time. Throttling behavior depends on the type and number of requests.

Common throttling scenarios

The most common causes of throttling of clients include:

  • A large number of requests for an API per Partner Tenant ID: for some Partner Center APIs, throttling is determined by Partner Tenant ID. Too many calls to those APIs on the same Partner Tenant ID results in exceeding the throttling threshold.
  • A large number of requests for an API per Partner Tenant ID per Customer Tenant ID: for other APIs, throttling is determined by Partner Tenant ID/Customer Tenant ID combination; in those cases, making too many calls against the same customer tenant ID results in throttling - while calls against other customers might succeed.

Best practices to avoid throttling

Programming practices, such as continuously polling a resource to check for updates and regularly scanning resource collections to check for new or deleted resources, are more likely to lead to throttling and degrades overall performance. Concurrent API calls might lead to high number of requests per unit time, which causes requests to be throttled. You should instead use change tracking and change notifications. Additionally, you should be able to use activity logs for detecting changes. For more information, see Partner Center activity logs. We highly recommend partners to consider using the activity log API for more efficiency and to avoid throttling. See also the example of using activity logs, below.

Best practices to handle throttling

The following are best practices for handling throttling:

  • Reduce the degree of parallelism.
  • Reduce the frequency of calls.
  • Avoid immediate retries because all requests accrue against your usage limits.

When you implement error handling, use the HTTP error code 429 to detect throttling. The failed response includes the Retry-After response header. Backing off requests using the Retry-after delay is the fastest way to recover from throttling.

To use the Retry-after delay:

  1. Wait the number of seconds specified in the Retry-After header.
  2. Retry the request.
  3. If the request fails again with a 429 error code, you're still being throttled. Retry with Exponential backoff, use the recommended Retry-After delay and retry the request until it succeeds.
  4. If you're using the SDK, you receive an exception with status code 429 when your request is being throttled. Use the RetryAfter property in the exception and retry the request after the time is elapsed.

APIs currently affected by throttling

In the end, every single Partner Center API that calls the endpoint "api.partnercenter.microsoft.com/" is throttled. Currently, the throttling limits are only enforced on the APIs listed below. Partner Center is collecting the telemetry on each of the APIs and dynamically adjusts the throttling limits. The following table lists the APIs where throttling is currently enforced.

Operation Partner Center documentation
{baseURL}/v1/customers/{customer_id}/orders create an order
{baseURL}/v1/customers/{customer-tenant-id}/subscriptions/{id-for-subscription}/upgrades transition a subscription
{baseURL}/v1/customers/{customer-tenant-id}/orders/{order-id} purchase an addon to a subscription
{baseURL}/v1/customers/{customer-id}/carts/{cart-id} create a cart
{baseURL}/v1/customers/{customer-id}/carts/{cart-id}/checkout checkout a cart
{baseURL}/v1/customers/{customer-id}/carts/{cart-id} update a cart
{baseURL}/v1/customers/{customer-id}/subscriptions/{subscription-id}/registrations register a subscription
{baseURL}/v1/productupgrades create product upgrade entity
{baseURL}/v1/customers/{customer-id}/subscriptions/{subscription-id}/conversions  convert a trial subscription to paid
{baseURL}/v1/customers/{customer-tenant-id} get a customer by ID
{baseURL}/v1/productUpgrades/eligibility get eligibility for product upgrade
{baseURL}/v1/customers/{customer-tenant-id}/subscriptions/{id-for-subscription}  manage subscription
{baseURL}/v1/customers/{customer_id}/subscriptions get-all-of-a-customer-s-subscriptions
{baseURL}/v1/customers/{customer_id}/subscriptions/{subscription_id} Get a subscription by ID
{baseURL}/v1/customers/{customer_id}/orders Get all customer orders
{baseURL}/v1/customers/{customer_id}/orders/{order_id} Get an order by ID
{baseURL}/v1/customers/{customer_id}/orders/{order_id}/provisioningstatus Get subscription provisioning status
{baseURL}/v1/customers/{customer_id}/subscriptions/{subscription_id} Manage orders and manage a subscription
{baseURL}/v1/customers/{customer_id}/subscriptions/{subscription_id}/addons Get a list of add-ons for a subscription
{baseURL}/v1/customers/{customer_id}/subscriptions/{subscription_id}/azureEntitlements Get a list of Azure entitlements for a subscription
{baseURL}/v1/customers/{customer_id}/subscriptions/{subscription_id}/registrationstatus Get subscription registration status
{baseURL}/v1/customers/{customer-tenant-id}/transfers Get all of a customer's transfers
{baseURL}/v1/productUpgrades/{upgrade-id}/status Get product upgrade status
{baseURL}/v1/customers/{customer-id}/subscriptions/{subscription-id}/conversions Get a list of trial conversion offers
{baseURL}/v1/customers/{customer-tenant-id}/migrations/newcommerce/validate Validate a subscription for migration
{baseURL}/v1/customers/{customer-tenant-id}/migrations/newcommerce Create a new commerce migration
{baseURL}/v1/customers/{customerId}/promotionEligibilities Verify a promotion eligibility

Error code response:

HTTP/1.1 429 Too Many Requests 

Content-Length: 84 

Content-Type: application/json 

Retry-After: 57 

Date: Tue, 21 Jul 2020 04:10:58 GMT 

{ "statusCode": 429, "message": "Rate limit is exceeded. Try again in 57 seconds." } 

Example of activity log

For best practice in analyzing daily changes, we recommend that you query audit record for a specific day.

In the response, you get a result with changes to specific operation type. You can filter based on the operation you care about. For example, if you're interested in a newly created customer, you can look at operationType = "add_customer".

List of operationtype/resources can be found in these API docs.

Response example

Request:

Http Get call: https://api.partnercenter.microsoft.com/v1/auditrecords?startDate=2020-09-02&endDate=2020-09-02&size=50 

Authorization: Bearer <token> 

Accept: application/json 

MS-RequestId: 127facaa-e389-41f8-8bb7-1d1af99db893 

MS-CorrelationId: de9c2ccc-40dd-4186-9660-65b9b64c3d14 

X-Locale: en-US 

Host: api.partnercenter.microsoft.com 

Connection: Keep-Alive 

Response:

{ 

    "totalCount": 17, 

    "items": [ 

        { 

            "id": "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d_e905b566-4779-4e57-944c-7b1b5312705b_updatecustomeruserlicenses_637346859797753934", 

            "partnerId": "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d", 

            "participants": [ 

                "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d" 

            ], 

            "customerId": "e905b566-4779-4e57-944c-7b1b5312705b", 

            "userPrincipalName": "admin@testsw09.onmicrosoft.com", 

            "applicationId": "FulfillmentService", 

            "resourceType": "license", 

            "operationType": "update_customer_user_licenses", 

            "operationDate": "2020-09-02T23:26:19.7753934Z", 

            "operationStatus": "succeeded", 

            "customizedData": [ 

                { 

                    "key": "CustomerUserId", 

                    "value": "933808c7-b165-496c-a24e-1a4b7846fab4" 

                } 

            ], 

            "attributes": { 

                "objectType": "AuditRecord" 

            } 

        }, 

        { 

            "id": "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d_86bddccf-9a53-40c6-907c-08067a3f8da7_ia80zlkxp6ewoqpp35pbqjlhqv9iigvz1_createorder_637346662909268372", 

            "partnerId": "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d", 

            "participants": [ 

                "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d" 

            ], 

            "customerId": "86bddccf-9a53-40c6-907c-08067a3f8da7", 

            "customerName": "CustomMetersStagingTest", 

            "userPrincipalName": "admin@testsw09.onmicrosoft.com", 

            "applicationId": "4990cffe-04e8-4e8b-808a-1175604b879f", 

            "resourceType": "order", 

            "resourceNewValue": "{\"Id\":\"Ia80ZLkXp6eWOqpp35pBQJLhqv9IiGVZ1\",\"AlternateId\":\"64144d300bde\",\"ReferenceCustomerId\":\"86bddccf-9a53-40c6-907c-08067a3f8da7\",\"BillingCycle\":\"monthly\",\"CurrencyCode\":\"USD\",\"CurrencySymbol\":\"$\",\"LineItems\":[{\"LineItemNumber\":0,\"ProvisioningContext\":null,\"OfferId\":\"DZH318Z0C964:0001:DZH318Z0BZDG\",\"SubscriptionId\":\"f428d44a-d08b-348b-579e-ce92a6362c7b\",\"ParentSubscriptionId\":null,\"TermDuration\":\"P1M\",\"TransactionType\":\"New\",\"FriendlyName\":\"SaaS custom meter offer - Bronze\",\"Quantity\":1,\"Pricing\":null,\"PartnerIdOnRecord\":null,\"RenewsTo\":null,\"Links\":{\"Product\":{\"Uri\":\"/products/DZH318Z0C964?country=US\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]},\"Sku\":{\"Uri\":\"/products/DZH318Z0C964/skus/0001?country=US\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]},\"Availability\":{\"Uri\":\"/products/DZH318Z0C964/skus/0001/availabilities/DZH318Z0BZDG?country=US\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]},\"ActivationLinks\":{\"Uri\":\"/customers/86bddccf-9a53-40c6-907c-08067a3f8da7/orders/Ia80ZLkXp6eWOqpp35pBQJLhqv9IiGVZ1/lineitems/0/activationlinks\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]}}}],\"CreationDate\":\"2020-09-02T17:58:01.7755853Z\",\"Status\":\"pending\",\"TransactionType\":\"UserPurchase\",\"Links\":{\"Self\":{\"Uri\":\"/customers/86bddccf-9a53-40c6-907c-08067a3f8da7/orders/Ia80ZLkXp6eWOqpp35pBQJLhqv9IiGVZ1\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]},\"ProvisioningStatus\":{\"Uri\":\"/customers/86bddccf-9a53-40c6-907c-08067a3f8da7/orders/Ia80ZLkXp6eWOqpp35pBQJLhqv9IiGVZ1/provisioningstatus\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]},\"PatchOperation\":{\"Uri\":\"/customers/86bddccf-9a53-40c6-907c-08067a3f8da7/orders/Ia80ZLkXp6eWOqpp35pBQJLhqv9IiGVZ1\",\"Method\":\"PATCH\",\"Body\":null,\"Headers\":[]}},\"Client\":{\"marketplaceCountry\":\"US\",\"deviceFamily\":\"UniversalStore-PartnerCenter\",\"name\":\"Partner Center Web\"},\"Attributes\":{\"ObjectType\":\"Order\"}}", 

            "operationType": "create_order", 

            "originalCorrelationId": "96514ebe-c1b2-4865-cb46-2c2d20a2e911", 

            "operationDate": "2020-09-02T17:58:10.9268372Z", 

            "operationStatus": "succeeded", 

            "customizedData": [ 

                { 

                    "key": "OrderId", 

                    "value": "Ia80ZLkXp6eWOqpp35pBQJLhqv9IiGVZ1" 

                }, 

                { 

                    "key": "AlternateId", 

                    "value": "64144d300bde" 

                }, 

                { 

                    "key": "BillingCycle", 

                    "value": "Monthly" 

                }, 

                { 

                    "key": "OfferId-0", 

                    "value": "DZH318Z0C964:0001:DZH318Z0BZDG" 

                }, 

                { 

                    "key": "SubscriptionId-0", 

                    "value": "f428d44a-d08b-348b-579e-ce92a6362c7b" 

                }, 

                { 

                    "key": "SubscriptionName-0", 

                    "value": "SaaS custom meter offer - Bronze" 

                }, 

                { 

                   "key": "Quantity-0", 

                    "value": "1" 

                }, 

                { 

                    "key": "PartnerOnRecord-0", 

                    "value": null 

                } 

            ], 

            "attributes": { 

                "objectType": "AuditRecord" 

            } 

        }, 

                           { 

            "id": "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d_86bddccf-9a53-40c6-907c-08067a3f8da7_86bddccf-9a53-40c6-907c-08067a3f8da7_addcustomer_637346648528069005", 

            "partnerId": "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d", 

            "participants": [ 

                "9daaeb1c-4195-4db5-9f1d-509eb70c8c2d" 

            ], 

            "customerId": "86bddccf-9a53-40c6-907c-08067a3f8da7", 

            "customerName": "CustomMetersStagingTest", 

            "userPrincipalName": "admin@testsw09.onmicrosoft.com", 

            "applicationId": "4990cffe-04e8-4e8b-808a-1175604b879f", 

            "resourceType": "customer", 

            "resourceNewValue": "{\"Id\":\"86bddccf-9a53-40c6-907c-08067a3f8da7\",\"CommerceId\":\"9dd78b4f-f98a-44b4-a2fa-2b82ac58d24c\",\"CompanyProfile\":{\"TenantId\":\"86bddccf-9a53-40c6-907c-08067a3f8da7\",\"Domain\":\"CustomMetersStagingTest.onmicrosoft.com\",\"CompanyName\":\"CustomMetersStagingTest\",\"Address\":null,\"Email\":null,\"OrganizationRegistrationNumber\":null,\"Links\":{\"Self\":{\"Uri\":\"/customers/86bddccf-9a53-40c6-907c-08067a3f8da7/profiles/company\",\"Method\":\"GET\",\"Body\":null,\"Headers\":[]}},\"Attributes\":{\"ObjectType\":\"CustomerCompanyProfile\"}},\"BillingProfile\":{\"Id\":\"4beafd7b-cdab-5bdc-52ed-02e16edf2e7a\",\"FirstName\":\"CustomMetersStagingTest\",\"LastName\":\"CustomMetersStagingTest\",\"Email\":\"CustomMetersStagingTest@CustomMetersStagingTest.com\",\"Culture\":\"en-US\",\"Language\":\"en\",\"CompanyName\":\"CustomMetersStagingTest\",\"DefaultAddress\":{\"Id\":null,\"Country\":\"US\",\"Region\":null,\"City\":\"Seattle\",\"State\":\"WA\",\"District\":null,\"AddressLine1\":\"CustomMetersStagingTest\",\"AddressLine2\":null,\"AddressLine3\":null,\"PostalCode\":\"98122\",\"FirstName\":\"CustomMetersStagingTest\",\"LastName\":\"CustomMetersStagingTest\",\"EmailAddress\":null,\"PhoneNumber\":null,\"MiddleName\":null},\"Attributes\":{\"Etag\":\"-2279334701316321663\",\"ObjectType\":\"CustomerBillingProfile\"}},\"RelationshipToPartner\":\"reseller\",\"AllowDelegatedAccess\":true,\"UserCredentials\":{\"userName\":\"admin\",\"password\":\"\"},\"AssociatedPartnerId\":null,\"CustomDomains\":null,\"Attributes\":{\"ObjectType\":\"Customer\"}}", 

            "operationType": "add_customer", 

            "originalCorrelationId": "7550d9ea-e64a-416f-e49b-3670c516cf69", 

            "operationDate": "2020-09-02T17:34:12.8069005Z", 

            "operationStatus": "succeeded", 

            "customizedData": [ 

                { 

                    "key": "PrimaryDomainName", 

                    "value": "CustomMetersStagingTest.onmicrosoft.com" 

                }, 

                { 

                    "key": "Relationship", 

                    "value": "Reseller" 

                } 

            ], 

            "attributes": { 

                "objectType": "AuditRecord" 

            } 

        }, 

                            

        ... 

    ], 

    "links": { 

        "self": { 

            "uri": "/auditrecords?startDate=2020-09-02&endDate=2020-09-02&size=50", 

            "method": "GET", 

            "headers": [] 

        } 

    }, 

    "attributes": { 

        "objectType": "Collection" 

    } 

}