Timba Api is a Typescript
+ Express
+ Node
starter kit to develop REST API
server apps.
Nothing new under the sun, just a straight forward combo to make server development a little bit faster. And of course, this make my freelancing days more enjoyable 😎
Comes with:
-
Everything typed with Typescript
-
ES6 features/modules
-
Run with Nodemon for automatic reload & watch
-
ESLint for code linting
-
Code formatting using Prettier
-
Configuration management using dotenv
-
Improved commits with Husky
-
Manage production app proccess with PM2
- Listar Jugadores
- Ver Jugador
- Crear Jugador
- Editar Jugador
- Login de Jugador
- Consultar Balance
- Consultar Bono
- Cargar Fichas (instanciar depósito)
- Ver Depósitos Pendientes
- Ver Depósito
- Listar Depósitos
- Editar Depósito
- Ver Cuenta Bancaria de Alquimia
- Retirar Premios (instanciar pago)
- Listar Pagos
- Login de Agente
- Marcar Pago Como Completado
- Liberar Pago
- Ver QR
- Ver Cuenta Bancaria
- Actualizar Cuenta Bancaria
- Ver Balance Casino
- Ver Balance Alquimia
- Ver Transferencias de Fichas Pendientes
- Liberar Fichas Pendientes
- Indicar Que El Agente Esta De Guardia
- Ver Estado De Guardia
- Ver Números de Soporte
- Actualizar Números de Soporte
- Cambiar Contraseña de Jugador
Endpoint: | /players |
---|---|
Método | GET |
Query string | ResourceListQueryString |
Devuelve | PlayerListResponse |
Requiere rol | agent |
Endpoint: | /players/:id |
---|---|
Método | GET |
Devuelve | Player & { bank_accounts: BankAccount[] } |
Requiere rol | player |
Endpoint: | /players |
---|---|
Método | POST |
Body (json) | PlayerRequest |
Devuelve | LoginResponse |
Endpoint: | /players/:id |
---|---|
Método | POST |
Body (json) | PlayerUpdateRequest |
Devuelve | Player |
Requiere rol | agent |
Endpoint | /players/login |
---|---|
Método | POST |
Body (json) | Credenciales |
Devuelve | LoginResponse |
Endpoint | /players/:id/balance |
---|---|
Método | GET |
Devuelve | [Number ] |
Endpoint | /players/:id/bonus |
---|---|
Método | GET |
Devuelve | Bonus[] |
❗Nota: devuelve un array.
Endpoint | /bank-account/:id? |
---|---|
Método | GET |
Devuelve | BankAccount[] |
Requiere rol | player |
Nota: Siempre devuleve un array
Nota: Omitir el parámetro
id
para ver todas las cuentas bancarias del usuario
Endpoint | /bank-account |
---|---|
Método | POST |
Body (json) | BankAccountRequest |
Devuelve | BankAccount |
Requiere rol | player |
Endpoint | /bank-account |
---|---|
Método | POST |
Body (json) | BankAccountRequest |
Devuelve | BankAccount |
Requiere rol | player |
Nota: Los campos son opcionales. Incluir los que se quiera modificar
Endpoint | /bank-account/:id/delete |
---|---|
Método | POST |
Devuelve | 200 OK |
Requiere rol | player |
Incluir el id en la URL y omitir el body para confirmar un depósito pendiente Omitir el id en la URL e incluir los datos en el body para crear un depósito nuevo
Endpoint | /transactions/deposit/:id? |
---|---|
Método | POST |
Body (json) | DepositRequest |
Devuelve | DepositResult |
Requiere rol | player |
Rate-limited | 1 every 10 seconds |
Endpoint | /transactions/cashout |
---|---|
Método | POST |
Body (json) | CashoutRequest |
Devuelve | CoinTransferResult |
Requiere rol | player |
Endpoint | /transactions/payment |
---|---|
Método | GET |
Query string | ResourceListQueryString |
Devuelve | Payment[] |
Requiere rol | agent |
Endpoint | /transactions/deposit/pending |
---|---|
Método | GET |
Devuelve | Deposit[] |
Requiere rol | player |
Nota: siempre devuelve un array
Endpoint | /transactions/deposit/:id/confirm |
---|---|
Método | POST |
Devuelve | DepositResult |
Requiere rol | player |
Endpoint | /transactions/bank-details |
---|---|
Método | GET |
Devuelve | RootBankAccount |
Requiere rol | player |
Endpoint | /auth/refresh |
---|---|
Método | POST |
Body (json) | RefreshRequest |
Devuelve | Tokens |
Endpoint | /auth/logout |
---|---|
Método | POST |
Body (json) | RefreshRequest |
Devuelve | 200 OK si el token es invalidado |
Error | 403 si el token no le pertenece al usuario, 404 si el token no se encuentra |
Requiere rol | player | agent |
Nota el token puede ser un access o refresh token. Al recibir uno, los dos serán invalidados.
Envia un email al usuario con un enlace para reestablecer su contraseña. El token tiene una validez de 10' y sólo puede ser usado una vez.
Endpoint | /auth/forgot-password |
---|---|
Método | POST |
Body (json) | ForgotPasswordRequest |
Devuelve | OK 200 | 429 too_many_requests |
Rate limited | 1 request cada 10' por username. |
Nota: siempre devuelve 200 OK para evitar user enumeration attack. Cuando devuelve 429, el tiempo que se debe esperar hasta el próximo request está en el encabezado
Retry-After
(en segundos).
Reestablecer contraseña usando el token generado en /auth/forgot-password
.
Endpoint | /auth/restore-password |
---|---|
Método | POST |
Body (json) | RestorePasswordRequest |
Devuelve | OK 200 |
Endpoint | /auth/reset-password |
---|---|
Método | POST |
Body (json) | ResetPasswordRequest |
Devuelve | OK 200 |
Requiere rol | player |
Endpoint | /agent/login |
---|---|
Método | POST |
Body (json) | Credenciales |
Devuelve | Tokens |
Endpoint | /agent/payments/:id/paid |
---|---|
Método | POST |
Devuelve | Payment |
Requiere rol | agent |
Transferir desde alquimia a la cuenta del jugador
Endpoint | /agent/payments/:id/release |
---|---|
Método | POST |
Devuelve | Payment |
Requiere rol | agent |
Endpoint | /transactions/deposit/:id |
---|---|
Método | GET |
Devuelve | Deposit[] |
Requiere rol | agent |
Endpoint | /transactions/deposit/ |
---|---|
Método | GET |
Query string | ResourceListQueryString |
Devuelve | Deposit[] |
Requiere rol | agent |
Endpoint para que el agente modifique el tracking_number
de un depósito y dispare el flujo de verificación.
Endpoint | /transactions/deposit/:id |
---|---|
Método | POST |
Body (json) | EditDepositRequest |
Devuelve | DepositResult |
Requiere rol | agent |
Para que el agente marque un depósito como pagado
Endpoint | /transactions/deposit/:id/update |
---|---|
Método | POST |
Body (json) | EditDepositStatusRequest |
Devuelve | Deposit |
Requiere rol | agent |
Endpoint | /agent/bank-account |
---|---|
Método | GET |
Devuelve | RootBankAccount |
Requiere rol | agent |
Endpoint | /agent/bank-account |
---|---|
Método | POST |
Body (json) | RootBankAccount |
Devuelve | RootBankAccount |
Requiere rol | agent |
Nota Todos los parámetros son opcionales, incluir solo los que se quiera actualizar.
Endpoint | /agent/balance/casino |
---|---|
Método | GET |
Devuelve | Balance |
Requiere rol | agent |
Endpoint | /agent/balance/alquimia |
---|---|
Método | GET |
Devuelve | Balance |
Requiere rol | agent |
Devuelve el total de fichas que debe cargar el agente para liberar transferencias pendientes
Endpoint | /agent/pending/pending-coin-transfers |
---|---|
Método | GET |
Devuelve | number |
Requiere rol | agent |
Liberar transferencias que hayan quedado pendientes en el caso que un jugador quiera comprar mas fichas de las que tiene dispoibles el agente
Endpoint | /agent/pending/deposits |
---|---|
Método | GET |
Devuelve | Deposit[] - los depositos afectados |
Requiere rol | agent |
Indicar que alguien está al teléfono para que el bot muestre el menú "contactanos".
Endpoint | /agent/on-call |
---|---|
Método | POST |
Body (json) | OnCallRequest |
Devuelve | 200 OK |
Requiere rol | agent |
Indicar que alguien está al teléfono para que el bot muestre el menú "contactanos".
Endpoint | /agent/on-call |
---|---|
Método | GET |
Devuelve | boolean |
Requiere rol | agent |
Endpoint | /agent/support |
---|---|
Método | GET |
Devuelve | SupportResponse |
Requiere rol | agent |
Endpoint | /agent/support |
---|---|
Método | POST |
Body (json) | SupportRequest |
Devuelve | 200 OK |
Requiere rol | agent |
Endpoint | /agent/reset-player-password |
---|---|
Método | POST |
Body (json) | PlayerPasswordResetRequest |
Devuelve | 200 OK |
Requiere rol | agent |
Endpoint | /bot/:name? |
---|---|
Método | GET |
Devuelve | `Blob |
Requiere rol | agent |
Omitir el parametro
:name
para que devuelva un array con los nombres de los bots. Cualquier caracter que no esté en el rango [a-b] es eliminado del parametro:name
. Ademas:name
debe tener entre 1 y 10 caracteres.
Endpoint | /analytics/ |
---|---|
Método | GET |
Query string | ResourceListQueryString |
Devuelve | Analytics[] |
Endpoint | /analytics/:id |
---|---|
Método | GET |
Devuelve | Analytics[] |
Endpoint | /analytics/ |
---|---|
Método | POST |
Body (json) | AnalyticsRequest |
Devuelve | Analytics |
Endpoint | /analytics/summary |
---|---|
Método | GET |
Devuelve | AnalyticsSummary[] |
Endpoint | /bonus |
---|---|
Método | GET |
Query string | ResourceListQueryString |
Devuelve | Bonus[] |
Requiere rol | agent |
Sólo muestra el bono si pertenece al usuario logueado o si el usuario logueado es agente
Endpoint | /bonus/:id |
---|---|
Método | GET |
Devuelve | Bonus[] |
Endpoint | /bonus/:id |
---|---|
Método | POST |
Body (json) | { player_id: string } |
Devuelve | Bonus |
Requiere rol | player |
Endpoint | /bonus/:id/redeem |
---|---|
Método | GET |
Devuelve | BonusRedemptionResult |
Requiere rol | player |
{
id: string
panel_id: number
username: string
email: string?
first_name: string?
last_name: string?
date_of_birth: string?
movile_number: string?
country: string?
balance_currency: string
status: string
created_at: string // 2024-01-29T18:14:41.534Z
}
page=1
items_per_page=20
search=<string>
sort_column=<string>
sort_direction='asc' | 'desc'
{
result: Player[]
total: number
}
{
access: string
refresh: string
player: Player
}
{
username: string
password: string
email: string
first_name: string?
last_name: string?
date_of_birth: DateTime?
movile_number: string?
country: string?
}
{
email?: string
movile_number?: string
first_name?: string
last_name?: string
}
{
owner: string // Nombre del beneficiario
bankId: string // Nombre del banco
bankNumber: string // CBU
bankAlias: string?
}
{
id: string
owner: string // Nombre del beneficiario
player_id: string // ID de Player
bankId: string // Nombre del banco
bankNumber: string // CBU
bankAlias: string?
created_at: datetime // 2024-01-29T18:14:41.534Z
updated_at: datetime // 2024-01-29T18:14:41.534Z
}
{
username: string
password: string
}
{
tracking_number: string;
amount: number;
date: datetime; // 2024-01-29T18:14:41.534Z
sending_bank: string; // valid bank ID
}
{
amount: number
bank_account: number // ID de cuenta bancaria
}
Estado de transferencia de fichas
{
ok: boolean
player_balance: number
error: string? // En caso de error, el motivo
}
{
player_balance: number? // undefined en caso de fichas no transferidas
error: string? // En caso de error, el motivo
deposit: Deposit
}
{
id: string
player_id: string
currency: string
dirty: boolean
// Esperando verificacion | verificado en alquimia | verificado y fichas enviadas | todo OK | eliminado por agente
status: "pending"|"verified"|"confirmed"|"completed"|"deleted"
tracking_number: string
amount: number
created_at: datetime // 2024-02-23T12:35:51.017Z
updated_at: datetime // 2024-02-23T12:35:51.017Z
}
{
tracking_number: string
}
{
status: "pending"|"verified"|"confirmed"|"completed"|"deleted"
}
{
id: string
player_id: string
amount: number
paid: datetime | null // 2024-02-23T12:35:51.017Z
bank_account: string
currency: string
created_at: datetime // 2024-02-23T12:35:51.017Z
updated_at: datetime // 2024-02-23T12:35:51.017Z
}
{
name: string
dni: string
bankId: string
accountNumber: string
clabe: string
alias: string
}
{
token: string
}
{
access: string
refresh: string
}
{
balance: number
}
{
active: boolean
}
{
bot_phone: string | null;
human_phone: string | null;
}
{
bot_phone?: string;
human_phone?: string;
}
{
username: string
}
{
token: string
new_password: string
repeat_password: string
}
{
new_password: string
repeat_password: string
}
{
new_password: string
user_id: string
}
{
id: string
source: string
event: string
data?: object
created_at: datetime // 2024-01-29T18:14:41.534Z
updated_at: datetime // 2024-01-29T18:14:41.534Z
}
{
source: string
event: string
data?: object
}
{
_count: { event: number };
source: string;
event: string;
}
{
id: string
player_id: string
Player: Player
status: string
percentage: number
amount: number
created_at: DateTime
updated_at: DateTime
}
{
player_balance: number? // undefined en caso de fichas no transferidas
error: string? // En caso de error, el motivo
bonus: Bonus
}
Correr contenedor de ddosify con
$ docker run -it --rm --add-host host.docker.internal:host-gateway ddosify/ddosify
Luego obtener un token de acceso y correr el siguiente comando en el contenedor
$ ddosify -t 'http://host.docker.internal:8080/app/v1/endpoint \
-m POST \
-b '{"json": "data"}' \
-h 'Content-Type: application/json' \
-h "Authorization: Bearer $ACCESS_TOKEN" \
-h 'User-Agent: curl/7.81.0' \
-n <request_count>
-d <test_duration>
npx prisma migrate deploy
Para levantar la base de datos.npm run seed
Para registrar al agente en nuestra base de datos. El comando pide el usuario y contraseña del casino y de nuestro panel propio. Las credenciales que se ingresen serán las que se usen para loguear al agente en el casino y en nuestro panel.
-
Usar endpoint /auth/logout en frontend
-
Refactor calls to *DAO.authorize* to use same format as
PaymentsDAO.authorizeRelease()
-
Ambientes staging y prod en, bot-timba y alquimia
-
Cambiar start-staging por start:production en timba-api scripts
-
Generar allowed origin dinamicamente en producción para incluir localhost
-
Caracter invisible en metricas bot
- Revisar respuesta y avisarle al agente si quedaron transferencias sin liberar
- Invalidar tokens en conjunto con una sola petición SQL
- Usar instancia global de prisma.
- ID Cuenta ahorro: 120902
- Carolina Maruzza
- 646180146003556692
- Albo
- Luis Gonzalo Sosa
- 646180402301855904
- Banco Stori
Listar cuentas de ahorro
curl -X GET \
-H "Authorization: Bearer $API_TOKEN" \
-H "AuthorizationAlquimia: Bearer $ALQ_TOKEN" \
${ALQ_TEST_BASE_URL}/cuenta-ahorro-cliente \
-H 'Content-Type: x-www-form-urlencoded' \
-d 'id_cliente=2733226'
Crear TX
curl -X POST \
-H "Authorization: Bearer $API_TOKEN" \
-H "AuthorizationAlquimia: Bearer $ALQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cuenta_origen": 120902, "id_cliente": 2733226, "medio_pago": 4, "importe": 1, "cuenta_destino": 646180146003556692,"nombre_beneficiario": "Carolina Maruzza", "rfc_beneficiario": "NA", "email_beneficiario": "[email protected]", "concepto": "test", "no_referencia": 123456, "api_key": "694cefc59cdd7a30202dcd4ea7fdb790"}' \
"${ALQ_TEST_BASE_URL}/guardar-transacciones"
Response
{
"error": false,
"id_transaccion": 7281723,
"folio_orden": "334251325903025153",
"message": "Operación registrada con éxito. Estado: Aplicada.",
"pendiente": true,
"obj_res": []
}
Confirmar TX
curl -X POST \
-H "Authorization: Bearer $API_TOKEN" \
-H "AuthorizationAlquimia: Bearer $ALQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id_transaccion": 7279624, "accion": 1, "id_cuenta": 120902, "api_key": "694cefc59cdd7a30202dcd4ea7fdb790"}' \
"${ALQ_TEST_BASE_URL}/ordenes-importador"
Listar TX pendientes
curl -X GET \
-H "Authorization: Bearer $API_TOKEN" \
-H "AuthorizationAlquimia: Bearer $ALQ_TOKEN" \
"${ALQ_TEST_BASE_URL}/ordenes-importador?id_cuenta=120902"
7388577, 7388722 Consultar status TX
curl -X GET \
-H "Authorization: Bearer $API_TOKEN" \
-H "AuthorizationAlquimia: Bearer $ALQ_TOKEN" \
"${ALQ_TEST_BASE_URL}/consulta-estatus-tx?id_transaccion=7281723"
Respuesta
{
id_transaccion: "7281723",
estatus: "LIQUIDADA",
detalle_proveedor: {
"error":true,
"message":"Respuesta proveedor desconocida"
}
}
Consultar transferencia por clave de rastreo
curl -X GET \
-H "Authorization: Bearer $API_TOKEN" \
-H "AuthorizationAlquimia: Bearer $ALQ_TOKEN" \
"${ALQ_TEST_BASE_URL}/cuenta-ahorro-cliente/120902/transaccion" \
-d 'clave_rastreo=$TRACKING_NUMBER'
Datos que necesitamos saber:
- Cuales son los distintos valores posibles, y que significan, del campo
estatus
en la respuesta de/consulta-estatus-tx
- Cuales son los valores posibles, y que significan, del campo
estatus_transaccion
en la respuesta de/cuenta-ahorro-cliente/$ACCOUNT_ID/transaccion
Enviar el siguiente pedido y guardar la cookie JSESSIONID de la respuesta
curl -X POST \
-i \
https://www.banxico.org.mx/cep/valida.do \
-d 'tipoCriterio=T&fecha=11-03-2024&criterio=53771ALBO11032024195558814&emisor=90646&receptor=90659&cuenta=659437001005389354&receptorParticipante=0&monto=10&captcha=c&tipoConsulta=1'
Despues
curl https://www.banxico.org.mx/cep/descarga.do?formato=XML \
-H "Cookie: JSESSIONID=$JSESSIONID"
Respesta
<SPEI_Tercero
FechaOperacion="2024-03-11"
Hora="13:56:07"
ClaveSPEI="90659"
sello="DbcZSGP5NnDGhmfHt+2wBv1+tdOorVXVdM4rktrhjycj1okIAcgQSM7B3glPe6DEB9nsNZ6iM4ckjjwcdn1q0ub9aOi8qHwg1vuBDr+nmv00+VwKNGX/vDcIosPk2NzHW5pAYYeHQy+WINzFtSgJx4o30dK7rtlGFjWNfaLRKQC0Cau4E1KLWZ+AP8iYjC5CLJEHL2VZhcbJaUivupJ40bP1Idh1bOI1me+F2GQ4sQuuqms8vzMPX1wIsweqFCqysco8ycO1RaFCs0OsZ8Ij9delh3jZG8QftYwdLGjM6XOh85MoRs4P7HoMrOw07S9SzB6NNyZa+YgP2lpdUXq/eA=="
numeroCertificado="00001000000505544848"
cadenaCDA="||1|11032024|11032024|135607|90659|STP|CAROLINA MARUZZA|40|646180146003556692|MAXC720729MNERXR07|ASP INTEGRA OPC|TECHNOLOGY AND INTEROPERABILITY SA DE CV|40|659437001005389354|TIN160223BC2|sin concepto|0.00|10.00|NA|NA|0|0|NA|0|0.00|00001000000505544848||DbcZSGP5NnDGhmfHt+2wBv1+tdOorVXVdM4rktrhjycj1okIAcgQSM7B3glPe6DEB9nsNZ6iM4ckjjwcdn1q0ub9aOi8qHwg1vuBDr+nmv00+VwKNGX/vDcIosPk2NzHW5pAYYeHQy+WINzFtSgJx4o30dK7rtlGFjWNfaLRKQC0Cau4E1KLWZ+AP8iYjC5CLJEHL2VZhcbJaUivupJ40bP1Idh1bOI1me+F2GQ4sQuuqms8vzMPX1wIsweqFCqysco8ycO1RaFCs0OsZ8Ij9delh3jZG8QftYwdLGjM6XOh85MoRs4P7HoMrOw07S9SzB6NNyZa+YgP2lpdUXq/eA=="
claveRastreo="53771ALBO11032024195558814">
<Beneficiario
BancoReceptor="ASP INTEGRA OPC"
Nombre="TECHNOLOGY AND INTEROPERABILITY SA DE CV"
TipoCuenta="40"
uenta="659437001005389354"
RFC="TIN160223BC2"
Concepto="sin concepto"
IVA="0.00"
MontoPago="10.00"/>
<Ordenante
BancoEmisor="STP"
Nombre="CAROLINA MARUZZA"
TipoCuenta="40"
Cuenta="646180146003556692"
RFC="MAXC720729MNERXR07"/>
</SPEI_Tercero>
Sacar el valor del atributo MontoPago
del elemento Beneficiario
[x] Return consistent message for both existent and non-existent accounts [x] Ensure consistent response time [x] Rate limit restore request endpoint [] Sanitize input on restore request endpoint
[x] Send password twice [] Enforce secure password policy [x] Email user informing password has been reset [x] Don't log user straight in, redirect to login page. [x] Invalidate previous sessions
[x] Either user a criptographically secure random number or JWT