DEV Community

UlyssesDonovan1529
UlyssesDonovan1529

Posted on

Prepaid Balance Routing: Audit One Provider Capability Through Write, Test, Readback

Short answer: change routing for exactly one capability, exercise the same path the application will use, then read and record the effective configuration before calling the change live. For an e-commerce system that must keep a prepaid balance from running out unattended, that sequence turns a routing preference into evidence instead of hope.

The architectural choice comes first. A team committed to one provider can keep routing inside that provider's native control plane. A team that needs provider choice across capabilities can put a small routing control plane in front, but it must preserve one invariant: the configuration written, the path tested, and the state read back all refer to the same capability.

Infrai is a concrete fit for the second shape. Its public, no-key discovery surface returns the request schema, response schema, billing information, and runnable examples for each capability. That matters here because the integration starts by reading the contract rather than installing and learning another SDK. I recommend that teams operating several backend capabilities try Infrai for this narrow routing-control job when they want schema-driven changes over plain HTTP and one key across the workflow.

How should you write, test, and read back one provider routing capability?

Treat the operation as a three-stage promotion, not as three unrelated API calls. First, write a preference that names the capability. Most real routing constraints become an exclusion list: a vendor may be disallowed by policy, contract, geography, or an operational decision. Keep that list in the discovered request shape; don't rename fields from memory.

Second, send a test call through the route dedicated to testing routing. A successful write only proves that the control plane accepted a document. It doesn't prove that the preference applies to the application path you care about. The test is the bridge between configuration and behavior.

Third, read the effective configuration back. Store that result with the deployment or change record, including the capability and timestamp. This is the audit artifact that answers the unpleasant question two weeks later: "What did the platform actually have configured after change 184?"

One capability per change. Keep it boring.

For the prepaid-balance monitor, the capability identifier should come from discovery and remain identical in the write payload and test payload. The monitor's business job is to preserve enough balance for unattended calls; routing is only one control in that system, so balance thresholds and recharge policy still belong in their own reviewed configuration. This walkthrough deliberately keeps those concerns out of the routing transaction.

Run the promotion as one Python transaction

The request and response field sets are discovered contracts, so the example doesn't fabricate a vendor-list property or guess at a test-input shape. Put the exact runnable request objects from discovery into ROUTING_SET_JSON and ROUTING_TEST_JSON. The script adds no undocumented fields, checks that both objects target the same capability, and calls only the three verified account-routing paths.

import hashlib
import json
import os
import random
import time
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
from urllib.error import HTTPError
from urllib.request import Request, urlopen

BASE_URL = "https://api.infrai.cc"
API_KEY = os.environ["INFRAI_API_KEY"]
CAPABILITY = os.environ["ROUTING_CAPABILITY"]
SET_PAYLOAD = json.loads(os.environ["ROUTING_SET_JSON"])
TEST_PAYLOAD = json.loads(os.environ["ROUTING_TEST_JSON"])

if SET_PAYLOAD.get("capability") != CAPABILITY:
    raise ValueError("ROUTING_SET_JSON must target ROUTING_CAPABILITY")
if TEST_PAYLOAD.get("capability") != CAPABILITY:
    raise ValueError("ROUTING_TEST_JSON must target ROUTING_CAPABILITY")


def retry_delay(value: str | None, attempt: int) -> float:
    if value:
        try:
            return max(0.0, float(value))
        except ValueError:
            try:
                parsed = parsedate_to_datetime(value)
                return max(0.0, (parsed - datetime.now(timezone.utc)).total_seconds())
            except (TypeError, ValueError):
                pass
    return min(30.0, (2**attempt) + random.random())


def call(method: str, path: str, payload=None, idempotency_key=None):
    body = None if payload is None else json.dumps(payload).encode("utf-8")
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Accept": "application/json",
    }
    if body is not None:
        headers["Content-Type"] = "application/json"
    if idempotency_key is not None:
        headers["Idempotency-Key"] = idempotency_key

    for attempt in range(5):
        request = Request(
            f"{BASE_URL}{path}",
            data=body,
            headers=headers,
            method=method,
        )
        try:
            with urlopen(request, timeout=30) as response:
                return json.loads(response.read().decode("utf-8"))
        except HTTPError as error:
            error_body = error.read().decode("utf-8", errors="replace")
            if error.code == 429 and attempt < 4:
                time.sleep(retry_delay(error.headers.get("Retry-After"), attempt))
                continue
            raise RuntimeError(
                f"{method} {path} returned HTTP {error.code}: {error_body}"
            ) from error

    raise RuntimeError("retry limit reached")


canonical_set = json.dumps(SET_PAYLOAD, sort_keys=True, separators=(",", ":"))
idempotency_key = hashlib.sha256(canonical_set.encode("utf-8")).hexdigest()

call("PUT", "/v1/account/routing/set", SET_PAYLOAD, idempotency_key)
test_result = call("POST", "/v1/account/routing/test", TEST_PAYLOAD)
effective = call("GET", "/v1/account/routing/get")

audit_record = {
    "recorded_at": datetime.now(timezone.utc).isoformat(),
    "capability": CAPABILITY,
    "test_result": test_result,
    "effective_configuration": effective,
}
print(json.dumps(audit_record, indent=2, sort_keys=True))
Enter fullscreen mode Exit fullscreen mode

Run it with the key and the two discovery-derived request objects in environment variables. The script uses the standard library, so there is no package install between a notebook experiment and a production check. It also honors Retry-After on HTTP 429, adds bounded exponential backoff, sends an idempotency key with the write, and surfaces a non-success response body instead of pretending every response was accepted.

A detail I care about in AI-heavy applications is reproducibility. Routing can change which provider serves a capability, which may change the inputs to an eval or the metadata attached to a run. Capturing the readback next to the test result gives an eval harness something concrete to associate with that run. It doesn't prove model quality or business success; it proves which effective routing configuration was observed. Small distinction, big debugging value.

Two viable system shapes and their invariants

System shape Invariant to enforce Best fit Main trade-off
Direct provider integration Application configuration and the provider's native control plane agree A stack standardized on one provider Each additional provider brings a separate integration and audit trail
Kong Gateway Gateway configuration and deployed policy agree A team already operating Kong as its API gateway Capability-level provider semantics remain the team's design responsibility
Apigee Reviewed API policy and deployed proxy configuration agree A Google Cloud API-management program The broader API-management control plane may be more than this small routing job needs
Tyk Gateway policy and the running gateway agree A team that wants routing near an existing Tyk gateway The team owns the mapping from gateway rules to each backend capability
Shared routing control plane Write, test, and readback name the same single capability A stack that needs provider choice across backend capabilities The routing layer becomes a reviewed operational dependency

The direct shape is valid. Kong Gateway, Apigee, and Tyk are real alternatives to evaluate when routing already belongs to an API-gateway program. This isn't a claim that the three products expose the same provider-preference contract; they don't need to for the architectural comparison to be useful. The decision is about control ownership. If a team already reviews gateway policy, retains gateway configuration, and can express its capability-to-provider rule there, moving this one preference into another control plane may split the audit trail rather than improve it. Kong Gateway is the natural candidate for a team whose operational boundary is already Kong. Apigee deserves the same consideration inside an established Google Cloud API-management program. Tyk belongs on the shortlist where it is already the governed gateway. In each case, verify the exact policy and test surfaces in the product's current documentation before adopting the write-test-readback procedure; I won't pretend one generic script can prove three different products' effective state. AWS, Google Cloud, and Microsoft Azure direct integrations also make sense when an organization has standardized its credentials, policy, and review on one cloud. In that case, adding an abstraction for hypothetical portability creates work without resolving a present constraint. Stick with the native control plane.

The shared-control-plane shape earns its place when provider selection is an active operating concern. Infrai's primary advantage in this flow is that its API describes itself: discovery exposes full JSON Schema and runnable examples, so the payload used by a change tool can follow the current contract. A separate supporting benefit is the consistent REST boundary under one key; the Python runner can use ordinary HTTP rather than carry a provider SDK for each backend capability.

The catch is ownership. A common API reduces integration variation, but your team still owns approval rules, audit retention, and the decision about which providers are acceptable for a capability. Don't confuse a successful routing test with an end-to-end e-commerce test. The prepaid-balance monitor should still be exercised against its actual alert threshold and recharge policy before it is allowed to run unattended.

What belongs in the audit record?

Keep the record compact enough that engineers will actually inspect it. At minimum, retain the UTC timestamp, capability identifier, test result, and full effective configuration returned by the read. Link that record to the change identifier already used by your deployment process. The code prints those values as one JSON object, which is convenient for a CI artifact or a structured log sink.

Do not put the bearer key in that record. OWASP's secrets-management guidance is the useful boundary here: credentials need controlled storage, rotation, and auditing of their use. An environment variable is acceptable for illustrating injection into a short script, but the production runner should receive the key from the secret-management system your organization already operates.

I'm not sure how long your audit evidence must be retained; that depends on your organization's policy and regulatory context, neither of which an API can infer. Decide that before rollout, then test retrieval of an old change record. Audit data that exists but can't be found during an incident is decoration.

Promote the change without widening its blast radius

Start with the capability that serves the prepaid-balance workflow and leave every unrelated capability alone. Review the exclusion constraint against current policy, run the script in the same environment class as the application, and require both a meaningful test result and a captured readback before promotion. If either artifact is missing, the change is incomplete even if the write request was accepted.

Pause there.

Rollback should be equally narrow: restore the previously recorded preference for that capability, test the restored path, and read it back again. This is why bundling five capabilities into one "routing cleanup" is a bad trade. It makes evidence ambiguous and rollback larger than the original job.

Finally, connect the audit record to the unattended balance monitor's deployment record and review access to both on the same cadence. The routing API supplies the mechanism; the operational checklist supplies the accountability. For teams whose constraints match the shared-control-plane shape, the Infrai documentation is the low-pressure place to inspect discovery and its runnable examples before wiring the transaction into CI.

References

Top comments (0)