Ai knowledge and logicHelpers

proxy_request & proxy_session

Make HTTP requests through Octocom's stable egress IP — for third-party APIs that allowlist by IP address. Available in custom actions, condition providers, event handlers, sidebar widgets, and recurring jobs.

Use these when a third-party API your Python code calls restricts access by IP address, or blocks requests coming from generic cloud IP ranges. Both route the request through Octocom's HTTP proxy, so the target always sees the same stable egress IP — an IP the third party can allowlist once.

proxy_request(method: str, url: str, **kwargs) -> requests.Response
proxy_session(headers: dict = None) -> requests.Session

proxy_request makes a single request. proxy_session returns a pre-configured requests.Session for making several calls to the same API — auth headers set once, connection reuse, and every request routed through the proxy.

Scope. Available in custom actions, condition providers, event handlers, sidebar widgets, and recurring jobs. Product-sync parsers have their own equivalent, fetch_via_proxy, which uses the same egress IP.


Why this exists

By default, outbound requests from your Python code leave through a shared cloud IP that isn't guaranteed to stay the same. That's fine for most APIs, but breaks down when:

  • The API requires you to register an allowlisted IP (common for order-management, ERP, and payment systems)
  • The API blocks well-known cloud IP ranges, returning 403, 429, or connection timeouts on requests that work elsewhere

Routing through the proxy solves both: the third party sees one stable Octocom IP. Contact Octocom support to get the current egress IP so you can add it to your provider's allowlist.


proxy_request

proxy_request(method: str, url: str, **kwargs) -> requests.Response
NameTypeDescription
methodstrHTTP method — "GET", "POST", "PUT", "DELETE", etc.
urlstrAbsolute URL to call.
**kwargsAnything requests.request() accepts — headers, params, json, data, timeout, …

Returns a requests.Response. The timeout defaults to 30 seconds; pass timeout=... to change it. Note that, like requests itself, it does not raise on non-2xx responses — check response.ok or call response.raise_for_status().

def execute_action(context):
    order_id = context["args"]["orderId"]

    response = proxy_request(
        "GET",
        f"https://api.example.com/orders/{order_id}",
        headers={"Authorization": "Bearer <token>"},
    )
    if not response.ok:
        return {"error": f"Order lookup failed ({response.status_code})."}

    order = response.json()
    return {"orderId": order["id"], "status": order["status"]}

proxy_session

proxy_session(headers: dict = None) -> requests.Session
NameTypeDescription
headersdict or NoneDefault headers applied to every request the session makes — put your Authorization / API-key headers here.

Returns a requests.Session with the proxy pre-configured. Use it when your code makes multiple calls to the same API:

def execute_action(context):
    email = context["args"]["email"]

    session = proxy_session(headers={
        "X-Api-Key": "<api-key>",
        "Content-Type": "application/json",
    })

    orders = session.get(
        "https://api.example.com/orders",
        params={"email": email},
        timeout=30,
    ).json()

    if not orders:
        return f"No orders found for {email}."

    latest = orders[0]
    session.put(
        f"https://api.example.com/orders/{latest['id']}/notes",
        json={"note": "[Octocom] Customer contacted support"},
        timeout=30,
    )

    return {"orderId": latest["id"], "status": latest["status"]}

Unlike proxy_request, the session does not apply a default timeout — pass timeout= on each call.


Policy

Default to plain requests. The proxy is an extra hop; only route through it when the target API allowlists by IP or you've actually seen it block the default egress (403/429/timeouts on URLs that work in a browser). Once an API is behind an IP allowlist, use proxy_session for all calls to it — a mix of proxied and direct calls will fail intermittently.


See also

On this page