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
idpara 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
:namepara 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:namedebe 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/ddosifyLuego 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 deployPara levantar la base de datos.npm run seedPara 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": "contacto@rodrigoalvarez.co.uk", "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
estatusen la respuesta de/consulta-estatus-tx - Cuales son los valores posibles, y que significan, del campo
estatus_transaccionen 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