Response headers
Response headers that might provide additional information
In addition to standard response headers, several custom headers are also returned. Not all of them have high relevance; some are present as telemetry data. The informative headers are described below.
Important response headers
X-U4-RemainingLimit
Contains the maximum number of calls that can be made in the current minute (sliding window) time-frame with the current subscription claim given by the X-U4-SubscriptionClaim header.
X-U4-QuotaType
As described in the limits section, APIs have separate inbound and outbound quotas (per 5 minutes and per 24 hours). This header provides information about which quota was affected by this call: INBOUND or OUTBOUND.
Retry-After
This is a standard response header, but due to its importance, we mention it here as well. When a response with status code 429 is returned, this header provides information regarding the number of seconds one should wait before the next attempt to make a call. The same information is also available in the response body, but this header can be used for applying automatic retry mechanisms in the caller code. Example: Retry-After: 32.
The following C# example demonstrates how to set up automatic retry behaviour based on the Retry-After header:
// filepath: Example retry policy implementation
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.Extensions.Http;
using System.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient("RetryClient")
.AddPolicyHandler(GetRetryPolicy());
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests ||
msg.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable)
.WaitAndRetryAsync(3, (retryAttempt, response, context) =>
{
var randomBuffer = TimeSpan.FromMilliseconds(500 + (Random.Shared.NextDouble() * 500)); // 500ms to 1000ms
if (response.Result?.Headers?.RetryAfter != null)
{
var retryAfter = response.Result.Headers.RetryAfter;
if (retryAfter.Delta.HasValue)
{
return retryAfter.Delta.Value + randomBuffer;
}
else if (retryAfter.Date.HasValue)
{
var delay = retryAfter.Date.Value - DateTimeOffset.UtcNow + randomBuffer;
return delay > TimeSpan.Zero ? delay : randomBuffer;
}
}
return TimeSpan.FromSeconds(2); // fallback
});
}