Withdrawal
Withdrawal is one platform-wide endpoint shared by every product: POST /v1/withdrawals with reference_type + reference_id + amount. Internally, the endpoint routes to per-product handlers that debit the matching holding and credit the main balance. An optional follow-on disbursement sends the funds to an external bank account via the payment gateway.
Lifecycle
Section titled “Lifecycle”A withdrawal is two movements stitched together. The first is internal: the per-product holding (saving goal, investment, saving circle) is debited and the owner’s main balance is credited — this is usually synchronous and can auto-approve. The second is optional and external: a disbursement debits the main balance and sends the funds to a bank account through the payment gateway, with an async signed callback that mirrors top-up in reverse.
flowchart LR
U([Account owner])
REQ[/"POST /v1/withdrawals<br/>reference_type · reference_id<br/>amount"/]
subgraph SOURCES[" Source holdings "]
direction TB
SG_H[("Saving Goal<br/>holding")]
INV_H[("Investment<br/>holding")]
SC_H[("Saving Circle<br/>holding")]
end
MAIN[("Main balance")]
GW[("Payment gateway<br/>disbursement")]
BANK[/"Bank account<br/>end of the line"/]
U -->|initiate| REQ
REQ -->|debit| SG_H
REQ -->|debit| INV_H
REQ -->|debit| SC_H
SG_H -->|credit| MAIN
INV_H -->|credit| MAIN
SC_H -->|credit| MAIN
MAIN -->|optional disbursement| GW
GW -->|transfer| BANK
classDef money fill:#FDF8E8,stroke:#3C2C96,stroke-width:2px,color:#1E1B4B;
classDef edge fill:#FFF3D0,stroke:#F4BE27,stroke-width:1.5px,color:#8B5A00;
classDef user fill:#E8E1FF,stroke:#3C2C96,stroke-width:1.5px,color:#1E1B4B;
class MAIN,SG_H,INV_H,SC_H,GW money;
class REQ,BANK edge;
class U user;
Sequence
Section titled “Sequence”Two-step model. Step 1 moves funds from the product-specific holding back to the main balance — this part is usually synchronous and can auto-approve. Step 2, when requested, is the disbursement from the main balance to an external bank via the payment gateway — an async flow with a signed callback that mirrors top-up in reverse.
---
config:
sequence:
actorMargin: 320
width: 220
messageMargin: 38
boxMargin: 14
noteMargin: 12
---
sequenceDiagram
autonumber
actor U as Account owner
participant API as Moria API
actor AD as Admin reviewer
participant GW as Payment Gateway
Note over U,GW: Two-step model<br/>• step 1: holding → main balance (internal)<br/>• step 2: main balance → bank (disbursement via gateway)
U->>API: POST /v1/withdrawals<br/>{ reference_type, reference_id,<br/>amount, destination? }
API->>API: validate ownership · check holding balance<br/>set status: "pending"<br/>route to handler by reference_type
API-->>U: 201 Created<br/>{ id, status: "pending" }
Note over AD,API: Admin review · applies to disbursements that need approval<br/>internal-only moves can auto-approve
AD->>API: approve the withdrawal request
API->>API: debit source holding<br/>credit main balance · status → "approved"
opt disbursement to external bank
API->>GW: create disbursement transaction<br/>(account_number, amount)
GW-->>API: { trx_id, status: processing }
GW->>API: callback · status: success
API->>API: debit main balance · mark disbursed
end
U->>API: GET /v1/withdrawals/:id
API-->>U: 200 OK<br/>{ status: "approved", history[] }