2026-06-29 07:27:03 +07:00

Doom CC Loan on App API

Base path: /api/v1/cc-loan-on-app/

All endpoints accept POST and return JSON. Standard response wrapper (defined by bitbucket.bri.co.id/mod/brimocomp/basic/dto/response/v2):

{
  "code": "00",
  "refnum": "<request_refnum>",
  "id": "<process_id / request_id>",
  "desc": "success",
  "data": { ... endpoint-specific payload ... }
}

When an error occurs, data is wrapped as {"error": "<error message>"} (see internal/utils/utils.go:22).

Request Origin: Frontend vs Erangel

Doom is not called directly by the frontend. The call flow is:

Frontend ──POST──▶ Erangel (API Gateway, CodeIgniter PHP)
                       └─ Doom library
                            └─POST──▶ Doom microservice
                                 ├─ Vikendi    (user/account/safety-mode)
                                 ├─ Eredar     (credit card / CC list)
                                 ├─ Brigate    (LOA simulation, submit, status)
                                 ├─ Database   (static params, LOA persistence)
                                 └─ Cipher-OTP (OTP send / validate)   ◀── only send-otp & submit-otp
  • Frontend → Erangel: hits routes like POST /v3-cc-loan-on-app-onboarding (mapped in erangel/application/config/routes.php). The frontend sends only the user-action fields (see per-endpoint tables).
  • Erangel → Doom: the Doom library (erangel/application/libraries/microservices/Doom.php) injects the cross-cutting fields. It also adds HTTP headers: User-Agent, IP-Address, Device-Type, Device-Id, Device-Name, Device-Version.
  • Doom → Cipher-OTP: triggered only by the send-otp and submit-otp endpoints (see the "Downstream: Cipher-OTP" subsections).

Field source legend used below:

  • [FE] = set by the frontend in the body sent to erangel
  • [EG] = erangel-generated/injected when forwarding to doom (not in the frontend body)
  • [EG→DM] = arrives at doom via erangel-injected field (originated from session/config/timestamp)
  • [FE→EG→DM] = flows frontend → erangel → doom unchanged
  • [DM] = doom server-side (overwritten inside the handler, or hardcoded)

Common Request Fields (all endpoints)

Field Type Required Source Validation Notes
client string yes [EG] oneof=BRIMON From erangel config doom_client
request_refnum string yes [EG] len=12 Generated by erangel (get_reference_number()); echoed in refnum
username string yes [EG] len=10 From erangel auth session (get_session_username())
timestamp string yes [EG] len=13 Generated by erangel via round(microtime(TRUE) * 1000)
channel_id string yes [EG] oneof=NBMB From erangel config doom_channel_id
request_id string no [DM] Not sent by erangel; overwritten in handler with the process ID

Common Response Codes

Code Constant Description
00 RCSuccess Success
01 RC01 No credit card / empty list
VE RCValidationError Invalid request body
EH RCErrorHandling Error handling
NF RCNotFound Not found
NA RCNotAuthorized Not authorized
CNF RCCreditCardNotFound Credit card not found
SM RCUserSafetyMode Safety mode active
FM RCFM Malformed JSON
TV RCTimeoutVikendi Vikendi timeout
TB RCTimeoutDB Database timeout
TBR RCTimeoutBrigate Brigate timeout
TC RCTimeoutMicroOTP Cipher/OTP timeout
TE RCTimeoutEredar Eredar timeout
SK RCSkipOtp (cipher) OTP skipped (disabled in config) — passed through from send-otp
NV RCOtpNotValid (cipher) Invalid OTP — passed through from submit-otp
TMT RCOtpTooManyTries (cipher) Too many wrong-OTP attempts
EX RCOtpNotExist (cipher) OTP not exist or expired
TR RCTimeoutRedis (cipher) Redis timeout (OTP store)
TK RCTimeoutKafka (cipher) Kafka timeout (OTP SMS/WA delivery)
THV RCTimeoutHaven (cipher) Haven timeout

Messages are localized in id or en (selected via the language header / middleware).


1. POST /api/v1/cc-loan-on-app/onboarding

Erangel route: POST /v3-cc-loan-on-app-onboardingerangel/application/controllers/api/v3/loan_on_app/Onboarding.php Doom library call: Doom::onboarding($refnum, $username, $device)Doom.php:68 Handler: loaHandler.Onboardingloauc.Onboarding (internal/usecase/loa/onboarding.go)

Loads the onboarding screen: scheme/slider text configuration and the user's existing loan applications grouped by status.

Request Body

Field Source Required
no body fields

The frontend sends no body fields to erangel for this endpoint. All common fields below are injected by erangel.

Request Body JSON
{
  "client": "BRIMON",                              // [EG]
  "request_refnum": "123456789154",                // [EG]
  "username": "acctest009",                        // [EG]
  "timestamp": "1652034352767",                    // [EG]
  "channel_id": "NBMB",                            // [EG]
  "request_id": "f6eb58d24d6842f59ddb40f40d2a7992" // [DM] (overwritten)
}

Struct: usecase.OnboardingRequest (internal/interfaces/usecase/loa.go:51)

Response Body (200)

Response Body JSON
{
  "code": "00",
  "refnum": "123456789154",
  "id": "<process_id>",
  "desc": "success",
  "data": {
    "eligible": true,
    "eligible_note": "Pinjaman baru belum bisa diajukan karena masih ada proses yang berlangsung.",
    "admin_fee_note": { 
      "title": "Ketentuan Biaya Admin", 
      "description": "1% dari total pinjaman (min. Rp200.000)"
    },
    "scheme": [
      { 
        "tenor": "3 Bulan", 
        "bunga": "0%" 
      },
      { 
        "tenor": "6 Bulan", 
        "bunga": "0,5%" 
      },
      { 
        "tenor": "12 Bulan", 
        "bunga": "0,5%" 
      },
      { 
        "tenor": "15 Bulan", 
        "bunga": "0,99%" 
      },
      { 
        "tenor": "18 Bulan", 
        "bunga": "0,99%" 
      },
      { 
        "tenor": "24 Bulan", 
        "bunga": "0,99%" 
      },
      { 
        "tenor": "36 Bulan", 
        "bunga": "0,99%" 
      }
    ],
    "slider_texts": [
      { 
        "title": "Pinjaman Fleksibel", 
        "description": "Pinjaman dana minimal 1 juta hingga 75 juta atau 50% dari sisa limit kartu kredit.",
        "image_path": "http://asset-host/example.png"
      },
      { 
        "title": "Pinjaman Fleksibel", 
        "description": "Pinjaman dana minimal 1 juta hingga 75 juta atau 50% dari sisa limit kartu kredit.",
        "image_path": "http://asset-host/example.png"
      },
      { 
        "title": "Pinjaman Fleksibel", 
        "description": "Pinjaman dana minimal 1 juta hingga 75 juta atau 50% dari sisa limit kartu kredit.",
        "image_path": "http://asset-host/example.png"
      }
    ],
    "list": [
      {
        "ticket_no": "TKT001",
        "card_no": "2003 **** **** 4302",
        "card_name": "Agung Harsono",
        "card_product_type": "Easy Card",
        "card_image_name": "bri_easy_card",
        "card_image_path": "http://asset-host/card/bri_easy_card.png",
        "account_no": "029012345678901",
        "account_string": "0290 **** **** 112",
        "account_name": "BRItama Bisnis",
        "account_image_name": "britama_bisnis",
        "account_image_path": "http://asset-host/account/britama_bisnis.png",
        "status": "PROCESSING",
        "status_string": "Pengajuan Diproses",
        "request_time": "09 February 2026, 09:41:02 WIB",
        "amount": "Rp3.200.000",
        "monthly_payment": "Rp1.015.000",
        "admin_fee": "Rp200.000",
        "interest_rate": "0%",
        "term": "3 Bulan",
        "seq_no": 1,
        "progress": [
          {
            "status_title": "Pengajuan dalam Analisis",
            "status_time": "09 Feb 2026, 09:41 WIB",
            "order": 1,
            "current": true
          },
          {
            "status_title": "Pengajuan Disetujui",
            "status_time": "",
            "order": 2,
            "current": false
          }
        ]
      },
      {
        "ticket_no": "TKT002",
        "card_no": "2003 **** **** 4302",
        "card_name": "Agung Harsono",
        "card_product_type": "Easy Card",
        "card_image_name": "bri_easy_card",
        "card_image_path": "http://asset-host/card/bri_easy_card.png",
        "account_no": "029012345678901",
        "account_string": "0290 **** **** 112",
        "account_name": "BRItama Bisnis",
        "account_image_name": "britama_bisnis",
        "account_image_path": "http://asset-host/account/britama_bisnis.png",
        "status": "REJECTED",
        "status_string": "Pengajuan Ditolak",
        "request_time": "09 February 2026, 09:41:02 WIB",
        "amount": "Rp3.200.000",
        "monthly_payment": "Rp1.015.000",
        "admin_fee": "Rp200.000",
        "interest_rate": "0%",
        "term": "3 Bulan",
        "seq_no": 2,
        "progress": [
          {
            "status_title": "Pengajuan dalam Analisis",
            "status_time": "09 Feb 2026, 09:41 WIB",
            "order": 1,
            "current": false
          },
          {
            "status_title": "Pengajuan Ditolak",
            "status_time": "10 Feb 2026, 06:30 WIB",
            "order": 2,
            "current": true
          }
        ]
      },
      {
        "ticket_no": "TKT003",
        "card_no": "2003 **** **** 4302",
        "card_name": "Agung Harsono",
        "card_product_type": "Easy Card",
        "card_image_name": "bri_easy_card",
        "card_image_path": "http://asset-host/card/bri_easy_card.png",
        "account_no": "029012345678901",
        "account_string": "0290 **** **** 112",
        "account_name": "BRItama Bisnis",
        "account_image_name": "britama_bisnis",
        "account_image_path": "http://asset-host/account/britama_bisnis.png",
        "status": "APPROVED",
        "status_string": "Pengajuan Disetujui",
        "request_time": "09 February 2026, 09:41:02 WIB",
        "amount": "Rp3.200.000",
        "monthly_payment": "Rp1.015.000",
        "admin_fee": "Rp200.000",
        "interest_rate": "0%",
        "term": "3 Bulan",
        "seq_no": 3,
        "progress": [
          {
            "status_title": "Pengajuan dalam Analisis",
            "status_time": "09 Feb 2026, 09:41 WIB",
            "order": 1,
            "current": false
          },
          {
            "status_title": "Pengajuan Disetujui",
            "status_time": "10 Feb 2026, 06:30 WIB",
            "order": 2,
            "current": true
          }
        ]
      }
    ]
  }
}

data is usecase.OnboardingResponse.

admin_fee_note carries the admin fee info banner shown in the scheme bottom sheet (title: "Ketentuan Biaya Admin", content: "1% dari total pinjaman (min. Rp200.000)").

Each scheme item now only contains tenor and bunga (removed nominal_transaksi and subtitle_transaksi).

Each item in list is usecase.Application:

Application item schema
{
  "ticket_no": "...",
  "card_no": "2003 **** **** 4302",
  "card_name": "Agung Harsono",
  "card_product_type": "Easy Card",
  "card_image_name": "bri_easy_card",
  "card_image_path": "http://asset-host/card/bri_easy_card.png",
  "account_no": "029012345678901",
  "account_string": "0290 **** **** 112",
  "account_name": "BRItama Bisnis",
  "account_image_name": "britama_bisnis",
  "account_image_path": "http://asset-host/account/britama_bisnis.png",
  "status": "PROCESSING|APPROVED|REJECTED",
  "status_string": "Pengajuan Diproses|Pengajuan Disetujui|Pengajuan Ditolak",
  "request_time": "09 February 2026, 09:41:02 WIB",
  "amount": "Rp3.200.000",
  "monthly_payment": "Rp1.015.000",
  "admin_fee": "Rp200.000",
  "interest_rate": "0%",
  "term": "3 Bulan",
  "seq_no": 1,
  "progress": [
    {
      "status_title": "Pengajuan dalam Analisis",
      "status_time": "09 Feb 2026, 09:41 WIB",
      "order": 1,
      "current": true
    },
    {
      "status_title": "Pengajuan Disetujui|Pengajuan Ditolak",
      "status_time": "",
      "order": 2,
      "current": false
    }
  ]
}

status / status_string mapping:

status status_string Description
PROCESSING Pengajuan Diproses Loan submitted, under review
APPROVED Pengajuan Disetujui Loan approved
REJECTED Pengajuan Ditolak Loan rejected

Error Codes

Code When
00 success also returned when user has no CC (CC list empty from Eredar).
TV Vikendi timeout (Eredar call)
NA Not authorized (Eredar call)
TB Static param DB read failure
TBR Brigate timeout on GetLoaStatusFromBrigate

2. POST /api/v1/cc-loan-on-app/form

Erangel route: POST /v3-cc-loan-on-app-formerangel/application/controllers/api/v3/loan_on_app/Form.php Doom library call: Doom::loanform($refnum, $username, $device, $card_token)Doom.php:81 Handler: loaHandler.Formloauc.Form (internal/usecase/loa/form.go)

Loads the loan form: source accounts, T&C text, product type, min/max loan range.

Request Body

Field Type Source Required Notes
card_token string [FE] yes len=64, validated by doom
client string [EG] yes BRIMON
request_refnum string [EG] yes len=12
username string [EG] yes len=10, from session
timestamp string [EG] yes len=13, server-generated
channel_id string [EG] yes NBMB
request_id string [DM] no overwritten by doom with process ID
Frontend → Erangel
{
  "card_token": "f104d035a92652987b8c82dd91cb13aa1f403d686dcbc3844d261cc8416de9b0"
}
Erangel → Doom (constructed in Doom.php:81)
{
  "client": "BRIMON",
  "request_refnum": "123456789154",
  "username": "acctest009",
  "timestamp": "1652034352767",
  "channel_id": "NBMB",
  "card_token": "f104d035a92652987b8c82dd91cb13aa1f403d686dcbc3844d261cc8416de9b0",
  "request_id": "<overwritten by doom>"
}

Struct: usecase.LoaFormRequest (internal/interfaces/usecase/loa.go:20)

Response Body (200)

Response Body JSON
{
  "code": "00",
  "refnum": "123456789154",
  "id": "<process_id>",
  "desc": "success",
  "data": {
    "account_list": [
      {
        "account": "123451234512345",
        "account_string": "1234 5123 4512 345",
        "name": "supedi",
        "currency": "IDR",
        "alias": "Alias-supedi",
        "product_type": "karti",
        "image_name": "karti.png",
        "image_path": "http://.../karti.png",
        "default": 1
      }
    ],
    "balance_string": "Rp20.000.000,00",
    "loan_note":"Pinjaman mulai Rp1 juta s.d Rp75 juta, maksimal 50% dari sisa limit.",
    "tnc_text": "tnc-id",
    "product_type": "Jcb Platinum",
    "cc_image_slim": "http://.../card/jcb_platinum_slim.png",
    "minimum_loan": 1000000,
    "maximum_loan": 20000000,
    "loan_multiplier": 100000
  }
}

data is usecase.LoaFormResponse (internal/interfaces/usecase/loa.go:30).

Frontend validation: the user-entered amount must be a multiple of loan_multiplier (e.g. if 100000, only values like 100000, 200000, 1500000, … are accepted).

Error Codes

Code When
00 Success
SM User is in safety mode (form.go:37)
CNF Credit card not found (form.go:100)
TV Vikendi timeout (Eredar, parameter, account list)
TB Database timeout (static param)
TBR Brigate timeout (GetProgramTermFromBrigate)
EH Error handling (account alias/validation fan-in errors)

3. POST /api/v1/cc-loan-on-app/term

Erangel route: POST /v3-cc-loan-on-app-termerangel/application/controllers/api/v3/loan_on_app/Term.php Doom library call: Doom::loanterm($refnum, $username, $device, $card_token, $amount)Doom.php:95 Handler: loaHandler.Termloauc.Term (internal/usecase/loa/term.go)

Returns a list of loan simulations (tenor / monthly payment / admin fee) for a given amount.

Request Body

Field Type Source Required Notes
card_token string [FE] yes
amount int [FE] yes doom validates gt=0
client string [EG] yes BRIMON
request_refnum string [EG] yes len=12
username string [EG] yes len=10, from session
timestamp string [EG] yes len=13, server-generated
channel_id string [EG] yes NBMB
request_id string [DM] no overwritten by doom with process ID
Frontend → Erangel
{
  "card_token": "f104d035a92652987b8c82dd91cb13aa1f403d686dcbc3844d261cc8416de9b0",
  "amount": 5000
}
Erangel → Doom (constructed in Doom.php:95)
{
  "client": "BRIMON",
  "request_refnum": "123456789154",
  "username": "acctest009",
  "timestamp": "1652034352767",
  "channel_id": "NBMB",
  "card_token": "f104d035a92652987b8c82dd91cb13aa1f403d686dcbc3844d261cc8416de9b0",
  "amount": 5000,
  "request_id": "<overwritten by doom>"
}

Struct: usecase.LoaTermRequest (internal/interfaces/usecase/loa.go:104)

Response Body (200)

Response Body JSON
{
  "code": "00",
  "refnum": "123456789154",
  "id": "<process_id>",
  "desc": "success",
  "data": {
    "simulation": [
      {
        "simulation_code": "...",
        "term_code": "123",
        "monthly_payment": 1015000,
        "monthly_payment_string": "Rp1.015.000",
        "admin_fee": 5000,
        "admin_fee_string": "Rp5.000",
        "term": 3,
        "term_string": "3 Bulan",
        "interest_rate": 0.5
      }
    ]
  }
}

data is usecase.LoaTermResponse (internal/interfaces/usecase/loa.go:115).

Error Codes

Code When
00 Success
TBR Brigate timeout (GetLoaSimulationtFromBrigate)

4. POST /api/v1/cc-loan-on-app/send-otp

Erangel route: POST /v3-cc-loan-on-app-send-otperangel/application/controllers/api/v3/loan_on_app/Send_otp.php Doom library call: Doom::loansendotp($refnum, $username, $device, $otp_type)Doom.php:134 Handler: loaHandler.SendOtploauc.SendOtp (internal/usecase/loa/send_otp.go)

Sends a one-time password to the user's registered phone number for the loan-on-app flow.

Request Body

Field Type Source Required Notes
otp_type string [FE] yes WA or SMS — OTP delivery channel
client string [EG] yes BRIMON
request_refnum string [EG] yes len=12
username string [EG] yes len=10, from session
timestamp string [EG] yes len=13, server-generated
channel_id string [EG] yes NBMB
request_id string [DM] no overwritten by doom with process ID
Frontend → Erangel
{
  "otp_type": "WA"
}
Erangel → Doom
{
  "client": "BRIMON",
  "request_refnum": "123456789154",
  "username": "acctest009",
  "timestamp": "1652034352767",
  "channel_id": "NBMB",
  "otp_type": "WA",
  "request_id": "<overwritten by doom>"
}

Struct: usecase.LoaSendOtpRequest (internal/interfaces/usecase/loa.go:177)

Response Body (200)

Response Body JSON
{
  "code": "00",
  "refnum": "123456789154",
  "id": "<process_id>",
  "desc": "success",
  "data": {
    "server_id": "abc123",
    "cellphone_number": "0812****1234",
    "duration_sec": 300
  }
}

If otp_type=loanInApp is disabled in cipher config, doom returns code: "00" with data: { "skip": true } — frontend skips OTP entry and proceeds to /submit-otp without an OTP code.

Error Codes

Code When
00 Success
TV Vikendi timeout (fetching user phone number)
TC Cipher/OTP timeout
TR Redis timeout (cipher)
TK Kafka timeout — OTP SMS/WA delivery failed

Downstream: Cipher-OTP POST /api/v1/otp/send

Doom fetches the user's phone number from Vikendi (via username), then proxies the send request to cipher-otp.

Request forwarded to cipher-otp:

Field Type Source Notes
client string [EG→DM] BRIMON
request_refnum string [EG→DM] len=12
username string [EG→DM] len=10
timestamp string [EG→DM] len=13
channel_id string [EG→DM] NBMB
otp_type string [DM] hardcoded loanInApp (constant.OtpTypeLoanInApp)
phone_no string [DM] from user profile returned by Vikendi
method string [FE→EG→DM] from otp_type field (WA or SMS)

request_id is not forwarded — cipher-otp generates its own.

  • If an OTP is already active in Redis, cipher returns desc: "Already Exist" with the same server_id/duration_sec (send.go:84-95).

5. POST /api/v1/cc-loan-on-app/submit-otp

Erangel route: POST /v3-cc-loan-on-app-submit-otperangel/application/controllers/api/v3/loan_on_app/Submit_otp.php Doom library call: Doom::loansubmitotp($refnum, $username, $device, $server_id, $otp, $otp_type)Doom.php:TBD Handler: loaHandler.SubmitOtploauc.SubmitOtp (internal/usecase/loa/submit_otp.go)

Validates the OTP the user received via /send-otp. On success the frontend proceeds to /submit. Modelled after haven-credit-card /api/v1/apply-cc/submit-otp (see erangel/application/libraries/microservices/Haven.php:submit_otp and erangel/application/controllers/api/v3/credit_card_application/Submit_otp.php).

Request Body

Field Type Source Required Notes
server_id string [FE] yes from /send-otp response
otp string [FE] yes code entered by user
otp_type string [FE] yes WA or SMS — must match channel used in /send-otp
client string [EG] yes BRIMON
request_refnum string [EG] yes len=12
username string [EG] yes len=10, from session
timestamp string [EG] yes len=13, server-generated
channel_id string [EG] yes NBMB
request_id string [DM] no overwritten by doom with process ID
Frontend → Erangel
{
  "server_id": "abc123",
  "otp": "123456",
  "otp_type": "WA"
}
Erangel → Doom
{
  "client": "BRIMON",
  "request_refnum": "123456789154",
  "username": "acctest009",
  "timestamp": "1652034352767",
  "channel_id": "NBMB",
  "server_id": "abc123",
  "otp": "123456",
  "otp_type": "WA",
  "request_id": "<overwritten by doom>"
}

Struct: usecase.LoaSubmitOtpRequest (internal/interfaces/usecase/loa.go:TBD)

Response Body (200)

Response Body JSON
{
  "code": "00",
  "refnum": "123456789154",
  "id": "<process_id>",
  "desc": "success",
  "data": null
}

No data payload on success — frontend simply checks code == "00" before proceeding to /submit.

Error Codes

Code When
00 OTP valid
NV Invalid OTP
TMT Too many wrong-OTP attempts
EX OTP not exist or expired
TC Cipher/OTP validation timeout
TR Redis timeout (cipher)

Downstream: Cipher-OTP POST /api/v1/otp/validate

Doom forwards the validate call to cipher-otp:

Field Type Source Notes
client string [EG→DM] BRIMON
request_refnum string [EG→DM] len=12
username string [EG→DM] len=10
timestamp string [EG→DM] len=13
channel_id string [EG→DM] NBMB
otp_type string [DM] hardcoded loanInApp (constant.OtpTypeLoanInApp) — doom maps FE's WA/SMS to this internally
server_id string [FE→EG→DM] from request
otp string [FE→EG→DM] from request

Cipher validate logic:

  1. Rate-limit check in Redis → TMT if exceeded.
  2. If otp_type=loanInApp disabled in cipher config → returns 00 (skip).
  3. Reads OTP from Redis by (otp_type, username)EX if missing.
  4. Compares server_id + otpNV on mismatch (increments rate-limit counter).
  5. On match: deletes OTP from Redis, writes otp_history, returns 00.

A failed validate returns immediately — cipher's code/desc forwarded 1:1 to the frontend.


6. POST /api/v1/cc-loan-on-app/submit

Erangel route: POST /v3-cc-loan-on-app-submiterangel/application/controllers/api/v3/loan_on_app/Submit.php Doom library call: Doom::loansubmit($refnum, $username, $device, $card_token, $amount, $simulation_code, $account_no, $account_name, $term, $interest_rate, $monthly_payment, $admin_fee, $pin)Doom.php:110 Handler: loaHandler.Submitloauc.Submit (internal/usecase/loa/submit.go)

Final step: submits the loan to Brigate, persists to DB, and returns the new application's progress. OTP validation has moved to /submit-otp; this endpoint now requires PIN instead.

Erangel PIN validation (Submit.php): the frontend must send pin. Erangel validates it via check_pin() before calling doom. The pin value is not forwarded to doom.

Request Body

Field Type Source Required Notes
card_token string [FE] yes
amount number [FE] yes doom: gt=0; erangel casts to int before forwarding
simulation_code string [FE] yes
account_no string [FE] yes
account_name string [FE] yes
term int [FE] yes erangel casts to int before forwarding
interest_rate number [FE] yes erangel casts to float
monthly_payment number [FE] yes doom: gt=0; erangel casts to float
admin_fee number [FE] yes doom: gte=0; erangel casts to float
pin string [FE] yes consumed by erangel only, not sent to doom
client string [EG] yes BRIMON
request_refnum string [EG] yes len=12
username string [EG] yes len=10, from session
timestamp string [EG] yes len=13, server-generated
channel_id string [EG] yes NBMB
request_id string [DM] no overwritten by doom with process ID
Frontend → Erangel
{
  "card_token": "f104d035a92652987b8c82dd91cb13aa1f403d686dcbc3844d261cc8416de9b0",
  "amount": 5000000,
  "simulation_code": "...",
  "account_no": "123451234512345",
  "account_name": "BRItama Bisnis",
  "term": 3,
  "interest_rate": 0.5,
  "monthly_payment": 1700000,
  "admin_fee": 50000,
  "pin": "123456"
}
Erangel → Doom (pin consumed by erangel, not forwarded)
{
  "client": "BRIMON",
  "request_refnum": "123456789154",
  "username": "acctest009",
  "timestamp": "1652034352767",
  "channel_id": "NBMB",
  "card_token": "f104d035a92652987b8c82dd91cb13aa1f403d686dcbc3844d261cc8416de9b0",
  "amount": 5000000,
  "simulation_code": "...",
  "account_no": "123451234512345",
  "account_name": "BRItama Bisnis",
  "term": 3,
  "interest_rate": 0.5,
  "monthly_payment": 1700000.0,
  "admin_fee": 50000.0,
  "request_id": "<overwritten by doom>"
}

Struct: usecase.LoaSubmitRequest (internal/interfaces/usecase/loa.go:131)

Response Body (200)

Response Body JSON
{
  "code": "00",
  "refnum": "123456789154",
  "id": "<process_id>",
  "desc": "success",
  "data": {
    "ticket_no": "TKT001",
    "card_no": "2003 **** **** 4302",
    "card_name": "Agung Harsono",
    "card_product_type": "Easy Card",
    "card_image_name": "bri_easy_card",
    "card_image_path": "http://asset-host/card/bri_easy_card.png",
    "account_no": "029012345678901",
    "account_string": "0290 **** **** 112",
    "account_name": "BRItama Bisnis",
    "account_image_name": "britama_bisnis",
    "account_image_path": "http://asset-host/account/britama_bisnis.png",
    "request_time": "09 February 2026, 09:41:02 WIB",
    "amount": "Rp3.200.000",
    "monthly_payment": "Rp1.015.000",
    "admin_fee": "Rp200.000",
    "interest_rate": "0%",
    "term": "3 Bulan",
    "sla_note": "Proses pengajuan 1x24 jam kerja. Kamu akan diberi notifikasi saat pencairan disetujui.",
    "status": "PROCESSING|APPROVED|REJECTED",
    "status_string": "Pengajuan Diproses|Pengajuan Disetujui|Pengajuan Ditolak",
    "progress": [
      {
        "status_title": "Pengajuan dalam Analisis",
        "status_time": "09 Feb 2026, 09:41 WIB",
        "order": 1,
        "current": true
      },
      {
        "status_title": "Pengajuan Disetujui|Pengajuan Ditolak",
        "status_time": "",
        "order": 2,
        "current": false
      }
    ]
  }
}

data is usecase.LoaSubmitResponse (internal/interfaces/usecase/loa.go:151).

Error Codes

Code When
00 Success
NA account_no not in user's financial accounts (submit.go:44)
TBR Brigate LoaSubmitToBrigate failed
TB DB insert failed (InsertLoanOnAppToDB) or GetLoaStatusFromBrigate DB error

7. GET /healthz

Health check. Defined in internal/delivery/http/http.go:47. Returns literal "ok".

Response body
"ok"

Source Code References

Doom (this microservice)

  • Routes: internal/delivery/http/http.go:39-50
  • Handlers: internal/delivery/http/loa.go
  • Request/Response structs: internal/interfaces/usecase/loa.go
  • Usecase logic:
    • internal/usecase/loa/onboarding.go
    • internal/usecase/loa/list.go
    • internal/usecase/loa/form.go
    • internal/usecase/loa/term.go
    • internal/usecase/loa/send_otp.go
    • internal/usecase/loa/submit_otp.go
    • internal/usecase/loa/submit.go
  • Response codes & messages: constant/response_code.go
  • Constants & route prefixes: constant/app.go

Erangel (API Gateway, sibling repo)

  • Routes mapping (frontend-facing URLs): erangel/application/config/routes.php
  • Doom client library: erangel/application/libraries/microservices/Doom.php
  • Frontend-facing controllers (each validates FE body, then calls Doom::*):
    • erangel/application/controllers/api/v3/loan_on_app/Onboarding.php
    • erangel/application/controllers/api/v3/loan_on_app/List_loa.php
    • erangel/application/controllers/api/v3/loan_on_app/Form.php
    • erangel/application/controllers/api/v3/loan_on_app/Term.php
    • erangel/application/controllers/api/v3/loan_on_app/Send_otp.php
    • erangel/application/controllers/api/v3/loan_on_app/Submit_otp.php
    • erangel/application/controllers/api/v3/loan_on_app/Submit.php
  • Base controller (auth/session, PIN checks, device, refnum generation): erangel/application/libraries/api/Transaction_Controller.php

Cipher-OTP (downstream microservice called by send-otp and submit-otp)

Base path: /api/v1/otp/ (v1) and /api/v5/otp/ (v5). Doom uses the v1 endpoints.

  • Routes: cipher-otp/internal/delivery/http/http.go:40-44
  • Handlers: cipher-otp/internal/delivery/http/otp.go
  • Request/Response structs: cipher-otp/internal/interfaces/usecase/otp.go
  • Usecase logic:
    • cipher-otp/internal/usecase/otp/send.go (handles skip-OTP, already-active-OTP, Kafka notification)
    • cipher-otp/internal/usecase/otp/validate.go (handles rate limit, server_id+otp match, history insert)
  • Response wrapper: cipher-otp/internal/pkg/dto/basic.go (uses response_code/response_refnum/response_id/response_desc/response_data)
  • Response codes & messages: cipher-otp/constant/response_code.go (notable additions: SK, NV, TMT, EX, TR, TK, THV)
  • Doom's cipher client: doom-cc-loan-on-app/internal/library/cipher/cipher.go
S
Description
No description provided
Readme 107 KiB