Microsoft accepts one usage event per subscription, dimension and hour (the hour of effectiveStartTime). WeTransact applies the same rule before calling Microsoft, but only against reports Microsoft has accepted โ a failed attempt never blocks its own retry.
That makes retries safe: after a timeout, a 429 or a 502, resend the same effectiveStartTime and you get one of two answers, never a double charge:
| HTTP | Meaning | Retry? |
|---|---|---|
200 | Microsoft accepted the usage event. Microsoft.UsageEventId is Microsoft's id. | No |
400 | Invalid input (quantity, dimensionId, effectiveStartTime unparsable / future / older than 24h). | Fix first |
404 | Subscription or dimension unknown. | Fix first |
409 | Already reported for this hour โ by an earlier accepted call, or Microsoft answered Duplicate. Body carries the original UsageReportEventId and Microsoft.UsageEventId. | No |
422 | Microsoft rejected the event (ResourceNotActive, InvalidDimension, Expired, BadArgument, ...). See Microsoft.Status. | Fix first |
429 | Too many concurrent charges. | Yes, same effectiveStartTime |
502 | Microsoft unreachable, timed out or 5xx. Outcome unknown; resending the same hour cannot double charge. retryable is true. | Yes, same effectiveStartTime |
Every response from the endpoint includes retryable, effectiveStartTime and Microsoft's own verdict under Microsoft, so your reconciliation can tie each report to what Microsoft actually recorded. The 429 from the concurrency limiter carries no body.
Still, it's your responsibility to make sure your integration is idempotent and stable.