rinha2-back-end-dotnet

API Reference

Base URL

Local and CI smoke tests reach the API through NGINX:

http://localhost:9999

The production compose file exposes the same public entrypoint on port 9999.

Client IDs and limits

The implementation has five predefined clients. The API keeps this small map in memory for fast invalid-client rejection, and PostgreSQL seeds the same limits in docker-entrypoint-initdb.d/rinha.dump.sql.

Client ID Limit, in cents
1 100000
2 80000
3 1000000
4 10000000
5 500000

POST /clientes/{id}/transacoes

Submits a credit or debit transaction.

Request body

{
  "valor": 1000,
  "tipo": "c",
  "descricao": "deposito"
}
Field Type Rule
valor integer Required positive integer amount in cents (> 0)
tipo string Required; "c" for credit or "d" for debit
descricao string Required, non-empty, maximum 10 characters

Successful response

The response uses snake_case JSON output generated by System.Text.Json source generation.

{
  "id": 1,
  "limite": 100000,
  "saldo": 1000
}

Status codes

Status When
200 Transaction accepted and a balance is returned
404 Client ID is not one of 1 through 5
422 Payload validation fails (valor <= 0, invalid tipo, missing/empty/long descricao)

Current implementation note

The intended Rinha contract treats a debit that would exceed the client’s limit as an unprocessable transaction. The current PostgreSQL function keeps the balance unchanged and returns the current balance when the limit update fails, so the API can return 200 with an unchanged balance for this case. If strict challenge behavior is required, adjust InsertTransacao/the route handler before documenting over-limit debits as guaranteed 422 responses.

GET /clientes/{id}/extrato

Returns the current account statement.

Successful response

{
  "saldo": {
    "total": 1000,
    "limite": 100000,
    "data_extrato": "2026-04-01T19:20:20.000000"
  },
  "ultimas_transacoes": [
    {
      "valor": 1000,
      "tipo": "c",
      "descricao": "deposito"
    }
  ]
}

The statement returns the latest 10 transactions ordered from newest to oldest.

Status codes

Status When
200 Client exists and statement data was returned
404 Client ID is not one of 1 through 5

GET /healthz

Health check used by local smoke tests and GitHub Actions.

Status When
200 ASP.NET Core health checks pass

Responsibility split

Layer Responsibility
API (Program.cs) Route mapping, JSON serialization, payload validation, fast invalid-client checks, database calls
PostgreSQL (rinha.dump.sql) Seed clients, keep balances, apply atomic balance updates, insert transaction rows, return recent statement data
NGINX (nginx.conf) Public port 9999 and load balancing across the two API instances