API REST Reference
Endpoints públicos del backend Accesly. La mayoría de integradores no toca esto directamente porque el SDK envuelve todo. Consulta esta referencia si necesitás llamar al backend desde un lenguaje distinto a JavaScript o desde tu propio servidor.
Base URL
| Environment | URL |
|---|---|
| Development | https://api.accesly.xyz |
| Staging | https://api-staging.accesly.xyz |
| Producción | https://api.accesly.xyz |
Autenticación
La API usa dos mecanismos de auth según el endpoint:
JWT Cognito (usuario end)
La mayoría de endpoints requieren un JWT válido de Cognito en el header Authorization: Bearer <jwt>. El JWT se obtiene del flow de signin.
curl https://api.accesly.xyz/wallets \
-H "Authorization: Bearer eyJhbGciOi..." API keys (integrador)
Endpoints de /v1/* son server to server. Se autentican con API key del integrador en el header x-accesly-api-key: sk_live_.... Estas keys se crean en el dashboard.
curl https://api.accesly.xyz/v1/wallets/CBUS... \
-H "x-accesly-api-key: sk_live_abc123..." Errores comunes
Todas las responses de error tienen esta shape:
{
"error": "WalletNotEnrolled",
"code": "WALLET_NOT_ENROLLED",
"message": "The wallet is not enrolled for asset USDC.",
"details": { "asset": "USDC" }
} Catálogo completo de errores en Errores.
Wallet
GET /wallets
Devuelve la wallet del usuario Cognito autenticado, o null si no tiene.
// Response 200
{
"walletAddress": "CBUSYQ6AW...",
"appId": "app_d_prueba1_j42h0",
"createdAt": "2026-06-29T22:36:20.381Z",
"onChain": true,
"deployedTxTargetsCount": 3,
"gAddress": "GD6EVND7...",
"bootstrapGComplete": true
} POST /wallets
Crea una wallet nueva. Body:
{
"appId": "app_d_...",
"pubkeyEd25519": "<hex 64>",
"secp256r1Pubkey": "<hex 130>",
"emailCommitment": "<hex 64>",
"fragmentF2": { "ciphertext", "nonce", "algo" },
"fragmentF3": { "ciphertext", "nonce", "algo" },
"emailHash": "<hex 64>",
"recoverySalt": "<base64>"
} POST /wallets/fragment-2
Descarga F2 envuelto en session key ECDH efímera. Body: { "clientEphemeralPubkey": "<base64 X25519>" }. Response tiene { nonce, ciphertext, authTag, serverEphemeralPubkey }.
GET /wallets/{address}/balance
Balance XLM + USDC + otros trustlines de la wallet. Endpoint público (no requiere auth), útil para explorers públicos.
GET /wallets/{address}/history
Historia de transacciones paginada. Query params: limit, cursor.
Transacciones
POST /wallets/tx/simulate
Backend arma una tx unsigned. Body:
{
"kind": "transfer",
"asset": "USDC",
"destination": "CBXY...",
"amount": "10.5"
} Response incluye unsignedXdr, signaturePayloadHashBase64, contextRuleIds, placeholderAuthEntryXdr. El SDK usa esto para armar la firma client side.
POST /wallets/tx/submit
Body: { "unsignedXdr", "signedAuthEntryXdr" }. Backend agrega fee bump con KMS relayer, submitea a Soroban RPC, devuelve { "txHash", "status" }.
Swap
POST /swap/simulate
Cotiza swap XLM ↔ USDC vía Soroswap. Body:
{
"fromAsset": "XLM",
"toAsset": "USDC",
"amountIn": "1000000",
"slippageBps": 50
} Response: { quote: { amountOut, priceImpactPct, platform }, unsignedXdr, signaturePayloadHashBase64, ... }.
POST /swap/submit
Submit con firma. Body: { "unsignedXdr", "signedAuthEntryXdr" }.
POST /swap-sdex/simulate + /submit + /finalize
Flow de tres pasos para swap classic SDEX. Requiere G address bootstrappeada. El SDK auto dispara bootstrapG y addTrustlineG si están missing.
Recovery
POST /recovery/otp/request
Body: { "email": "..." }. Rate limited: 1 por 60s, 3 por hora. Response 200 OK aunque el email no exista (anti enumeración).
POST /recovery/otp/verify
Body: { "email", "code", "idToken?" }. Response: { "recoveryJwt": "...", "expiresAt": <epoch ms> }. El idToken es opcional y sirve para atar el JWT al Cognito sub actual.
GET /fragments/3
Header X-Recovery-Jwt: <jwt>. Devuelve { fragmentF3Encrypted, fragmentF2Recovery, recoverySalt }. Requiere JWT válido con scope recovery-finalize.
POST /recovery/simulate-rotate-signer
Header X-Recovery-Jwt: <jwt>. Body:
{
"newOwnerEd25519Pubkey": "<hex 64>",
"newSecp256r1Pubkey": "<hex 130>",
"newEmailCommitment": "<hex 64>"
} Backend arma la tx rotate_signer y devuelve { unsignedXdr, signaturePayloadHashBase64, placeholderAuthEntryXdr, contextRuleIds }.
POST /recovery/finalize
Header X-Recovery-Jwt: <jwt>. Body incluye el signedAuthEntryXdr + los nuevos fragments. Backend ejecuta el rotate on chain y persiste los fragments nuevos.
En wallets con 4 o más context rules el submit rebota con HTTP 422 code: ROTATE_SIGNER_WRITE_CAP_EXCEEDED. El body del error incluye rotatableRuleIds con los IDs elegibles para partition. El SDK reacciona automáticamente y ejecuta el flow multi tx descrito abajo.
POST /recovery/simulate-rotate-partial
Header X-Recovery-Jwt: <jwt>. Body:
{
"partialRuleIds": [0, 1],
"newOwnerEd25519Pubkey": "<hex 64>",
"newSecp256r1Pubkey": "<hex 130>"
} Backend arma la tx rotate_signer_partial(rule_ids, new_owner, new_secp) del Smart Account v3.2.0 para rotar solo el subset de rules pasado. Response idéntico al simulate legacy: { unsignedXdr, signaturePayloadHashBase64, placeholderAuthEntryXdr, contextRuleIds }.
POST /recovery/rotate-partial
Header X-Recovery-Jwt: <jwt>. Body { unsignedXdr, signedAuthEntryXdr, partialRuleIds }. Backend re simula con la auth firmada, submitea el batch y devuelve { walletAddress, txHash, status, rotatedRuleIds }. No persiste ningún fragment. El SDK llama este endpoint una vez por batch.
POST /recovery/simulate-finalize-rotation
Header X-Recovery-Jwt: <jwt>. Body:
{
"newOwnerEd25519Pubkey": "<hex 64>",
"newSecp256r1Pubkey": "<hex 130>",
"newEmailCommitment": "<hex 64>"
} Backend arma la tx finalize_rotation(new_owner, new_secp, new_email_commitment). Se llama una sola vez cuando todos los batches de rotate-partial ya fueron aplicados.
POST /recovery/finalize-rotation
Header X-Recovery-Jwt: <jwt>. Body incluye signedAuthEntryXdr + los mismos fragments que /recovery/finalize (F1', F2', F2 recovery', F3', salt, email commitment). Backend ejecuta el finalize_rotation on chain y persiste TODOS los nuevos fragments en la misma llamada. Response idéntico a /recovery/finalize: { walletAddress, txHash, status }.
KYC y fiat
POST /kyc/register-bank-account
Registra CLABE + datos personales para KYC en Dynerox. Body:
{
"clabe": "012180011201000123",
"firstName": "Luis",
"paternalLastName": "Perez",
"maternalLastName": "Sanchez",
"holderCurp": "PESL800101HDFRRS01",
"birthDate": "1980-01-01",
"phone": "+525512345678"
} GET /kyc/status
Devuelve el status KYC del usuario actual. Response: { "status": "active", "authorizationUrl": "https://auth.dynerox.com/..." }.
POST /onramp
Crea route Dynerox de MXN a USDC Stellar. Body:
{
"amount": "500",
"currency": "MXN"
} Response: { "routeId", "status", "authorizationUrl" }. El user visita el authorizationUrl para completar el pago SPEI.
POST /offramp
Body: { "amount", "asset": "USDC", "bankAccountId" }. Retira USDC de la wallet a la CLABE registrada.
App config
GET /app-config/{appId}
Público. Devuelve el appConfig del app. Usado por el SDK al mount del Provider.
{
"appId": "app_d_...",
"appName": "Mi App",
"network": "testnet",
"branding": { ... },
"auth": { "providers": ["email", "google"] },
"trustlines": [...],
"cognito": { "userPoolId", "clientId" }
} PATCH /apps/{appId}
Editar el appConfig. Requiere JWT del developer pool y ownership del app. Usado por el dashboard.
Handles y contactos
POST /handles
Reserva un handle global tipo @luis.accesly. Body: { "handle": "luis" }. FCFS: primer usuario que lo reserve gana.
GET /handles/{handle}
Resuelve un handle a la wallet address. Público.
GET /contacts
Address book del usuario actual. Response array de { contactId, name, walletAddress, handle? }.
POST /contacts
Agrega contacto. Body: { "name", "walletAddress" o "handle" }.
Metadata y observabilidad
GET /status: health check público, incluye status de dependencias externas.GET /apps/{appId}/users: lista de usuarios del app. Requiere JWT developer pool.GET /apps/{appId}/audit-logs: audit trail paginado.GET /apps/{appId}/metrics: métricas agregadas.GET /apps/{appId}/webhooks: lista de webhooks configurados.POST /apps/{appId}/webhooks: registra webhook.GET /contracts?network=mainnet: registry de contratos deployados por network.
Idempotencia
Operaciones que mueven state aceptan header Idempotency-Key: <uuid>. Si repetís el mismo key en 24h, devolvemos la response cached en vez de re ejecutar. Recomendado para createWallet, recovery/finalize y tx/submit.
Rate limits
| Endpoint group | Límite |
|---|---|
| Recovery OTP request | 1 por 60s, 3 por hora por email |
| Recovery OTP verify | 5 intentos por OTP |
| Auth signIn | 10 por minuto por IP |
| Tx submit | 60 por minuto por user |
| Balance / history reads | 300 por minuto por user |
Response 429 cuando se supera el límite. Header Retry-After indica segundos hasta reintentar.
Siguientes pasos
- Catálogo de errores.
- SDK Reference: métodos JavaScript que envuelven todos estos endpoints.