C#

Without Router - Current Approach
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace AAEcosystem
{
    public class AccountDiscoveryClient
    {
        private const string API_URL = "https://fip-1.dev.sahamati.org.in/v2/Accounts/discover";
        private const string JWS_SIGNATURE = "eyJhbGciOiJSUzI1NiIsImtpZCI6IlRlZ1FhMms3MUlFWlotaEhxcm1ueWFFc3ZvSWloNWdrVUx2SjFfTEhibGsiLCJjcml0IjpbImI2NCJdLCJiNjQiOmZhbHNlfQ..Dux_bx7X-q1YSvyNmZiyPM60ZgaK3MshWBhWeY-bLBeSmxkU5VpH-lQjBjGFW_2opX3ZK5XfF7oPc3wkp-Qj7-qVfgTg53YvGyS3oLbKvkMRHtKa33x5I-0b8BmlMzojtnA_zFfubOJoqZVPpz7BQ4qrazizaF2Z6m3FygNGuAkdbdqtnCgPCjBZ6ibkpyiKR_n_g5FcTOq7fa7JgE6IoMD0R575ssdFbHzcT-IZs0DDqc_DJ0pR7m56z9IlmRZ6kUg99kaYVl6GUHSYPwY9OCbmHa7EbgE5vUdIJjhF3vJDZhYMWCojpbh9KLGSpbHkWG4OY19S-YNJv85FtXZe0Q";
        private const string BEARER_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJsRlByWU4wR3dBQ3YyUzJFVFZyRkVvZVVlc2VzelppQ2xIaVY1M3hrU3JNIn0.eyJleHAiOjE3NDQ5NjgwNDAsImlhdCI6MTc0NDg4MTY0MCwianRpIjoiYzZiZTcyNDAtOWU5Ny00MzYwLTk3OGUtZWI5MTY0MWZiMmMwIiwiaXNzIjoiaHR0cHM6Ly9hcGkuZGV2LnNhaGFtYXRpLm9yZy5pbi9hdXRoL3JlYWxtcy9zYWhhbWF0aSIsInN1YiI6ImIyMzE1MTU3LWRmNzYtNGQzZS04ZjM2LWQ4NzZmY2ViOWFlZiIsInR5cCI6IkJlYXJlciIsImF6cCI6IkFBLVNJTVVMQVRPUiIsImFjciI6IjEiLCJzY29wZSI6ImVtYWlsIG1pY3JvcHJvZmlsZS1qd3QgcHJvZmlsZSBhZGRyZXNzIHBob25lIiwidXBuIjoic2VydmljZS1hY2NvdW50LWFhLXNpbXVsYXRvciIsImNsaWVudElkIjoiQUEtU0lNVUxBVE9SIiwiYWRkcmVzcyI6e30sImNsaWVudEhvc3QiOiIxMC4yMjQuMC4xODIiLCJyb2xlcyI6IkFBIiwic2VjcmV0LWV4cGlyeS10cyI6IjIwMjUtMTItMDRUMTU6MzM6MzQuMDU5MTgzIiwiY2xpZW50QWRkcmVzcyI6IjEwLjIyNC4wLjE4MiJ9.G-ErvIeZUtKkqN4CbaH09Nwzy9fUjKSD18xpNh6y74AQdB8YFfNuhC8m6nxMpDCLY2fUj8sIcQ--Jp-EYDxChSR8kQTbKDmYJzPGRGunO-hkLxPK83R3Q7Byc6KZot1lZlj-Dsv-l5JD0Ay0KpPr4bKqIas5FEZTx2qoA3p6J1CyNbiQ81t4_KxVoO44hmVKPe0FIVNLw9MK04bkHOwO-WMB9DoUX5Y8bBREYgRv_W3QEEC8gcI5vZLnHuBXSZSXQ3MDPSLOq7lGnMsxh5A0YF1Wvfqg3LJjXizMfIfRNMyq2M0eMwHQEWfjLNTEqS6Bd6qkjPREVdhRTTnHaggq9A";
        private const string FIP_ID = "FIP-SIMULATOR";

        private static readonly string REQUEST_BODY = @"{
            ""ver"": ""2.0.0"",
            ""timestamp"": ""2023-06-26T06:41:54.904+0000"",
            ""txnid"": ""f35761ac-4a18-11e8-96ff-0277a9fbfedc2"",
            ""Customer"": {
                ""id"": ""customer_identifier@AA_identifier"",
                ""Identifiers"": [
                    {
                        ""category"": ""STRONG"",
                        ""type"": ""AADHAAR"",
                        ""value"": ""XXXXXXXXXXXXXXXX""
                    }
                ]
            },
            ""FITypes"": [
                ""DEPOSIT""
            ]
        }";

        public static async Task Main(string[] args)
        {
            try
            {
                using var httpClient = new HttpClient();
                httpClient.Timeout = TimeSpan.FromSeconds(10);

                var request = new HttpRequestMessage(HttpMethod.Post, API_URL);
                request.Headers.Add("x-jws-signature", JWS_SIGNATURE);
                request.Headers.Add("x-simulate-res", "Ok");

                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", BEARER_TOKEN);
                request.Content = new StringContent(REQUEST_BODY, Encoding.UTF8, "application/json");

                var response = await httpClient.SendAsync(request);
                var responseBody = await response.Content.ReadAsStringAsync();

                Console.WriteLine($"Response Status Code: {(int)response.StatusCode} {response.StatusCode}");
                Console.WriteLine($"Response Body: {responseBody}");
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error occurred: {ex.Message}");
                Console.Error.WriteLine(ex.StackTrace);
            }
        }
    }
}

With Router Integration - Request
import requests
import json
from datetime import datetime
from typing import Dict, Any

# ==============================
#  Config Metadata
# ==============================
ENTITY_METADATA_FROM_CR = {
    "baseUrl": "http://fip-1.sandbox.sahamati.org.in/fip-simulate",
    "id": "FIP-SIMULATOR"
}
ROUTER_INTEGRATION_HELPER_URL = "https://api.sandbox.sahamati.org.in/router-helper/v1/request/header"


# ==============================
#  Core Functions
# ==============================
def build_discovery_request_body() -> Dict[str, Any]:
    """Creates the ReBIT-defined account discovery request body."""
    return {
        "ver": "2.0.0",
        "timestamp": datetime.utcnow().isoformat(),
        "txnid": "f35761ac-4a18-11e8-96ff-0277a9fbfedc2",
        "Customer": {
            "id": "9766334467@aa_simulator",
            "Identifiers": [
                {
                    "category": "STRONG",
                    "type": "AADHAAR",
                    "value": "XXXXXXXXXXXXXXXX"
                }
            ]
        },
        "FITypes": ["DEPOSIT"]
    }


def get_http_config(base_url: str, route: str, headers: Dict[str, str], data: Dict[str, Any], method_type: str) -> Dict[str, Any]:
    """Builds base HTTP config."""
    return {
        "url": f"{base_url}{route}",
        "headers": headers,
        "json": data,
        "method": method_type
    }


def router_integration_helper(route: str, rebit_request_body: Dict[str, Any]) -> Dict[str, Any]:
    """Calls Router Integration Helper service to get host and x-request-meta."""
    payload = {
        "rebitAPIEndpoint": route,
        "recipientId": ENTITY_METADATA_FROM_CR["id"],
        "customerId": "9766334467@aa_simulator",
        "requestBody": rebit_request_body
    }

    response = requests.post(
        ROUTER_INTEGRATION_HELPER_URL,
        json=payload,
        headers={"Content-Type": "application/json"},
        timeout=30
    )
    response.raise_for_status()
    return response.json()


def add_sahamati_configuration(config: Dict[str, Any], route: str, rebit_request_body: Dict[str, Any]) -> Dict[str, Any]:
    """Updates config with router URL and adds x-request-meta header by calling Router Helper API."""
    header_response = router_integration_helper(route, rebit_request_body)

    target_host = header_response.get("targetHost")
    if not target_host:
        raise RuntimeError("Router Helper response missing required field 'targetHost'")

    # Update URL
    config["url"] = f"{target_host}{route}"
    config.setdefault("headers", {})

    # Add x-request-meta header only if it exists
    x_request_meta = header_response.get("x-request-meta")
    if x_request_meta:
        config["headers"]["x-request-meta"] = x_request_meta

    return config


def execute_discovery_request() -> Dict[str, Any]:
    """Executes account discovery request via Sahamati Router (helper API flow)."""
    route = "/Accounts/discover"
    rebit_request_body = build_discovery_request_body()

    # Step 1: Base config
    config = get_http_config(
        base_url=ENTITY_METADATA_FROM_CR["baseUrl"],
        route=route,
        headers={},
        data=rebit_request_body,
        method_type="POST"
    )

    # Step 2: Add Router configuration (call helper API)
    config = add_sahamati_configuration(config, route, rebit_request_body)

    # Step 3: Execute request
    response = requests.request(**config, timeout=30)
    response.raise_for_status()
    return response.json()


def perform_another_operations(account_discover_response: Dict[str, Any]) -> None:
    """Placeholder for next steps."""
    print("Next steps with response:")
    print(json.dumps(account_discover_response, indent=2))


# ==============================
#  Main Runner
# ==============================
if __name__ == "__main__":
    try:
        response = execute_discovery_request()
        perform_another_operations(response)
        print("✅ Account discovery successful.")
    except Exception as e:
        print(f"❌ Account discovery failed. Reason: {e}")
    finally:
        print("ℹ️ Account discovery completed.")

With Router Integration - Response
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

const string ROUTER_RESPONSE_HEADER_URL = "https://api.sandbox.sahamati.org.in/router-helper/v1/response/header";
const string RECIPIENT_ID = "AA-SIMULATOR";

async Task<Dictionary<string, object>> routerIntegrationHelper(Dictionary<string, object> requestBody)
{
    using var client = new HttpClient();
    var json = JsonSerializer.Serialize(requestBody);
    var content = new StringContent(json, Encoding.UTF8, "application/json");
    var resp = await client.PostAsync(ROUTER_RESPONSE_HEADER_URL, content);
    resp.EnsureSuccessStatusCode();
    var respJson = await resp.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<Dictionary<string, object>>(respJson);
}

Dictionary<string, object> FetchAccountFromRequestBody(Dictionary<string, object> requestBody)
{
    if (requestBody == null || !requestBody.TryGetValue("Customer", out var customerObj) || customerObj is not JsonElement customerElem || customerElem.ValueKind != JsonValueKind.Object)
        return null;
    if (!customerElem.TryGetProperty("Identifiers", out var identifiersElem) || identifiersElem.ValueKind != JsonValueKind.Array)
        return null;
    foreach (var idElem in identifiersElem.EnumerateArray())
    {
        if (idElem.ValueKind != JsonValueKind.Object) continue;
        var category = idElem.GetProperty("category").GetString();
        var type = idElem.GetProperty("type").GetString();
        var value = idElem.GetProperty("value").GetString();
        if (category == "STRONG" && type == "AADHAAR" && !string.IsNullOrEmpty(value))
        {
            return new Dictionary<string, object>
            {
                ["FIType"] = "DEPOSIT",
                ["accType"] = "SAVINGS",
                ["accRefNumber"] = "BANK11111111",
                ["maskedAccNumber"] = "XXXXXXX3468"
            };
        }
    }
    return null;
}

app.MapPost("/accounts/discover", async (HttpRequest req, HttpResponse res) =>
{
    var incomingRequestBody = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(req.Body);
    var discoveredAccount = FetchAccountFromRequestBody(incomingRequestBody);
    if (discoveredAccount == null)
    {
        res.StatusCode = 404;
        await res.WriteAsJsonAsync(new { error = "Account not found" });
        return;
    }
    var responseBody = new Dictionary<string, object>
    {
        ["ver"] = "2.0.0",
        ["timestamp"] = "2023-06-26T06:45:54.904+0000",
        ["txnid"] = "f35761ac-4a18-11e8-96ff-0277a9fbfedcs",
        ["DiscoveredAccounts"] = new[] { discoveredAccount }
    };
    var responseHeaderRequestBody = new Dictionary<string, object>
    {
        ["rebitAPIEndpoint"] = "/accounts/discover",
        ["customerId"] = "9977336577@aa_simulator",
        ["recipientId"] = RECIPIENT_ID,
        ["additionalAttributes"] = new Dictionary<string, object>(),
        ["responseBody"] = responseBody
    };
    var responseHeaderResp = await routerIntegrationHelper(responseHeaderRequestBody);
    if (responseHeaderResp.TryGetValue("x-response-meta", out var xResponseMetaObj) && xResponseMetaObj is JsonElement xMetaElem && xMetaElem.ValueKind == JsonValueKind.String && !string.IsNullOrEmpty(xMetaElem.GetString()))
    {
        res.Headers["x-response-meta"] = xMetaElem.GetString();
    }
    res.ContentType = "application/json";
    await res.WriteAsJsonAsync(responseBody);
});

app.Run();

Last updated

Was this helpful?