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?