- Parte 1, el concepto. Léela primero. v3 es un rediseño, no un cambio de nombre: si mapeas endpoints antiguos uno a uno, lucharás contra la API. Diez minutos aquí te ahorrarán días después.
- Parte 2, la API. Mapeo endpoint por endpoint, ejemplos de peticiones, máquinas de estado y una lista de verificación de migración.
api.deprecation para recibir avisos de retirada.
Contenidos. Parte 1: 1.1 por qué existe v3, 1.2 modelo de objetos, 1.3 preparación por capability, 1.4 bucle de tareas, 1.5 movimiento de dinero, 1.6 máquinas de estado, 1.7 convenciones, 1.8 ruta dorada. Parte 2: 2.1 customers, 2.2 capabilities, 2.3 tasks y submissions, 2.4 accounts, 2.5 recipients y destinations, 2.6 quotes y transfers, 2.7 webhooks, 2.8 sandbox, 2.9 endpoints heredados, 2.10 orden de migración, 2.11 lista de escollos.
Parte 1, el concepto
1.1 Por qué existe v3
v1 y v2 desarrollaron cuatro formas superpuestas de dejar a un customer listo para pagos:/rails, /banks, /accounts/applications y la superficie empresarial rail-applications, cada una con su propio vocabulario de estados. La recopilación de documentos (/documents, importaciones de KYC, tokens SDK de verificación) estaba desconectada de aquello que en realidad desbloqueaba. v3 lo condensa todo en seis recursos: el customer más cinco cosas que posee:
1.2 El modelo de objetos
Dos reglas estructurales que debes interiorizar:- Las capabilities regulan todo. Las accounts se aprovisionan bajo una capability
ready; las quotes se cotizan contra una capability. La incorporación equivale a obtener las capabilities que necesitas en estadoready. - Las tasks se adjuntan en cualquier lugar. Una capability, una account o una transfer en curso pueden llevar
openTaskIds. Donde las veas, el bucle es el mismo: leer la task, enviar respuestas, esperar la revisión, releer el recurso padre.
1.3 La preparación es por capability, no por customer
v1 enredaba la preparación de/rails con una barrera de KYC a nivel de customer. En v3 no hay estado de customer: un customer puede ser totalmente usable en stablecoin_transfers mientras su capability sepa sigue teniendo tasks abiertas. Las capabilities de cuenta agrupada suelen pasar a ready más rápido que las nominales, así que empieza a operar en lo que esté ready en lugar de esperar a todo.
Si tu código v1 o v2 controla insignias de UI basándose en el estado de verificación del customer, reescríbelo:
- “¿Puede operar en X?” se convierte en capability X con
status == "ready". - “¿Tiene que hacer algo?” se convierte en cualquier task con estado
action_required(la capability suele mostrarrestrictedconstatusReason.resolution: "complete_tasks"). - “¿Estamos esperando a Swipelux?” se convierte en tasks
in_review, capabilitypending.
1.4 El bucle de tareas
Todo lo que hacía la antigua superficie de documentos y KYC ahora es este único bucle: Propiedades clave:- Una task lleva
requirements[], las peticiones individuales. Cada una tiene unrequirementIdpor task, unakeyestable que nombra la petición (por ejemplo prueba de domicilio, deduplica tu UI por ella) y unarequesttipada que describe exactamente qué entrada se desea (texto, fecha, selección, documento, atestación, y demás). - Enviar está sujeto a revisión: nunca muta directamente el estado de la capability o la account, la aceptación sí. Una excepción: las respuestas
profilese propagan al perfil del customer al enviarse (2.3). Después de enviar, consulta la task o el recurso padre. taskRevision(eco delrevisionde la task) es un mecanismo de concurrencia: si la task cambió desde que la leíste, reléela y reconstruye tus respuestas.absencees una respuesta de primer nivel (“no tengo esto porque…”), úsala en lugar de dejar requirements sin responder.
1.5 Movimiento de dinero
Un solo flujo para payins, payouts y movimientos de stablecoin. No hay entrada de dirección, nunca declaras payin frente a payout. Las formas de moneda de entrada y salida derivan undirection de solo lectura en la quote y en la transfer: fiat_to_stablecoin (payin), stablecoin_to_fiat (payout) o stablecoin_move.
1.6 Una máquina de estado por recurso
Cada recurso con estado tiene su propio enum, y cada estado no exitoso lleva una razón estructurada. Accounts, applications y transfers comparten la forma{ code, message, actor, retryable }: accounts y applications la exponen como statusReason, transfers como stateDetail. actor indica quién debe actuar (customer, developer, provider, network, swipelux), retryable indica si reintentar puede ayudar. Las capabilities usan { code, resolution, message }, donde resolution (complete_tasks, wait, contact_support, none) indica qué hace avanzar la capability. Los valores de code forman un catálogo abierto y solo aditivo: ramifica según resolution (o actor más retryable), y tolera códigos que nunca hayas visto.
Los estados que esta guía no recorre (
rejected, suspended, disabled, failed, canceled) son terminales o gestionados por soporte; las definiciones por recurso están en la especificación.
Transfer, en detalle:
1.7 Convenciones
Reglas de idempotencia que conviene interiorizar antes de escribir código:
- Reutilizar una clave con un cuerpo distinto produce
409 idempotency_conflictmientras la clave se conserve (al menos 7 días), así que nunca planifiques reutilizar una clave. Genera un UUID nuevo por cada operación lógica y persístelo con tu job. - La repetición cubre también los errores: si la petición original terminó en un 4xx terminal, la misma clave más el cuerpo devuelven la misma respuesta de problema.
- Dos peticiones concurrentes con la misma clave: una gana, la otra recibe
409. Reintenta la perdedora tras estabilizarse la ganadora; la repetición devuelve la respuesta original.
1.8 La ruta dorada
Parte 2, la API
2.1 Customers
Creación, discriminada por
type (valores ilustrativos, nombres de campo según la especificación):
- La creación es progresiva:
{ "type": "individual" }por sí solo es una creación válida. Los datos que falten nunca invalidan al customer, aparecen luego como tasks de intake en las capabilities que los necesiten. - Las empresas llevan
businessmás datos de registro. El CRUD de accionistas de v1 se mapea a related parties, ampliado para cubrir directores, ejecutivos y propietarios: créalos en línea al crear el customer (cada uno recibe un id establerp_) o gestiónalos por los endpoints dedicados de related-parties. - No hay campo
statusen el customer, véase 1.3. - Los customers existentes se conservan: los customers creados en v1 o v2 son direccionables por el mismo id en los endpoints v3. La lectura v3 es una vista saneada, los valores heredados que no superen la validación v3 vuelven ausentes. Tras tu primera escritura v3, esa vista se vuelve permanente: los valores ausentes no reaparecen por sí solos. Enriquece pronto, planifica una pasada única que
PATCHee el perfil completo desde tus propios registros antes de confiar en las lecturas v3. Elmetadatade v1 es un espacio de nombres separado y no se conserva, vuélvelo a establecer en v3. externalIdes de primer nivel y único entre tus customers en v3, por entorno (409 duplicate_external_id). Archivar un customer no libera suexternalId, límpialo con PATCH antes de DELETE si piensas reutilizarlo.DELETEes un archivado en cascada (sin restauración; los ids nunca se reutilizan). Se bloquea con409 customer_has_active_resourcesmásblockingResources[]mientras exista cualquier account no archivada o transfer en curso.- Reglas de fusión de PATCH:
nullexplícito limpia un campo anulable, los arrays se reemplazan por completo (excepto related parties en línea, que se hacen upsert por id), las claves demetadatase fusionan. Los esquemas completos y los filtros de lista están en la especificación OpenAPI.
2.2 /rails, /banks, applications se convierten en Capabilities
- Una capability equivale a
method(ach,wire,rtp,pix,sepa,swift,spei,pse,transfers_3_0,faster_payments,sepa_instant,uaefts,card,stablecoin_transfers, etc.) másaccountType(pooledonamed,nullpara métodos no bancarios) másdirections(payinopayout). ElcapabilityIdpúblico es el par cualificado (sepa_pooled,ach_named) o el método simple paracardystablecoin_transfers. - Cada solicitud de capability genera una application, el registro por intento bajo
.../capabilities/{capabilityId}/applications(más/{applicationId}/history), con sus propios estados (1.6) ystatusReason. Es la traza de auditoría de una solicitud; en el día a día, consulta la propia capability. capabilities/supporteddevuelve disponibilidad (available,betaodisabled), elegibilidad e instituciones ofrecidas. La selección de banco ocurre en el momento de la solicitud a través del array opcionalinstitutions; no hay un recurso/banksseparado. Omitirlo (o enviar[]) selecciona todas las instituciones por defecto;isDefault: truees una bandera específica de customer y capability, no global. Una lista no vacía anula los valores por defecto, y una capability bancaria sin un valor por defecto aplicable devuelve422 capability_institutions_required. Los ids de institución son opacos, tolera los nuevos.stablecoin_transferses auto-otorgada al crear el customer y nace enready(por lo que nunca se solicita ni se cancela).cardes solo para individuals.openTaskIdsen la capability es tu puntero de “qué hago a continuación”. Abierto equivale aaction_requiredoin_review, y el rollup incluye tasks compartidas a nivel de customer accesibles a través de dependencias activas.cancelsolo funciona desdependingorestrictedy sin recursos bloqueantes, de lo contrario409 capability_not_cancelable, cuyo cuerpo del problema listablockingResources. Volver a solicitar tras cancelar es una nueva creación con una nueva clave de idempotencia.- Consulta el GET. El estado de la capability se actualiza al leerlo; consulta
GET .../capabilities/{capabilityId}o suscríbete acapability.status_changed, no lo caches. - Solicitar un método puede hacer disponibles métodos relacionados a la vez, trata las capabilities como un conjunto que releas, no como una sola fila que rastreas.
- Usa
tasks-previewpara mostrar las peticiones de incorporación antes de comprometerte con una solicitud. - La verificación no es única: pueden aparecer nuevas tasks en una capability ya en
ready(reverificación periódica o dirigida por eventos). Mantén el bucle de tasks activo durante todo el ciclo de vida del customer, no solo durante la incorporación.
2.3 Documentos y KYC se convierten en Tasks y Submissions
Nota sobre el nombre. Estos endpoints se publicaron brevemente como
requirements y fulfillments. Desde el 2026-08-02 los nombres públicos son tasks y submissions. El cambio de nombre cubrió solo los recursos y las rutas de endpoint; el array requirements[] dentro de una task y su requirementId conservan esos nombres.GET /v3/customers/{customerId}/tasks, responde con POST .../tasks/{taskId}/submissions.
En torno a ese bucle:
- Almacenamiento de archivos en bruto:
POST/GET/DELETE /v3/customers/{customerId}/documents(más/{documentId}), sube una vez con tu API key y luego referencia los ids de documento en las respuestas de submission. Esto reemplaza todos los intakes de upload-token y direct-upload. - Lecturas totalmente nuevas:
GET /v3/tasks(bandeja de entrada del comercio),GET /v3/transfers/{transferId}/tasks,GET .../tasks/{taskId}/history,GET .../tasks/{taskId}/submissions(más/{submissionId}).
- Tipos de respuesta:
profile,text,date,single_select,multi_select,boolean,attestation,document,resource_reference,absence. El objetorequestde cada requirement te dice qué tipo espera. - Una submission debe responder cada requirement accionable de la ronda actual, con el
taskRevisionexacto que leíste. Las submissions parciales son rechazadas. - Las respuestas
profilese propagan: actualizan el perfil del customer por la vía de validación normal y reevalúan de inmediato cada capability que referencia el mismo trabajo de intake. Las tasks de intake hermanas cuyos requirements están todos satisfechos se cierran automáticamente. - Los requirements pueden formar grupos alternativos (
alternativeKey): envía exactamente uno del grupo. changes_requestedincrementaremediationRoundy llevareviewFeedback. Relee la task, envía de nuevo con una nueva clave de idempotencia.- Las URLs de verificación alojada aparecen solo en el detalle de task por customer (
GET /v3/customers/{customerId}/tasks/{taskId}) y solo mientras la sesión sea accionable; las listas yGET /v3/tasks/{taskId}están deliberadamente sin URLs. - Los términos de servicio también son una task:
openTaskIdspuede incluir una task concategory: "terms_of_service"cuya página alojada de aceptación se enlaza del mismo modo (solo detalle por customer). Las submissions genéricas no pueden aceptar términos, y la aprobación de KYC nunca implica aceptación de términos. - Las tasks tienen ámbito por capability, por lo que la “misma” petición (por ejemplo prueba de domicilio) puede aparecer una vez por capability. Deduplica en tu UI por la
keydel requirement. - No hay capa de traducción: publicar en
/v1/documentsno desbloqueará las capabilities de v3. Una vez que un customer está en v3, canaliza todas las peticiones a través de tasks.
2.4 Accounts y wallets
Creación, discriminada por
origin más type. Las cuentas bancarias emitidas toman un único method; las cuentas bancarias externas toman en su lugar un array methods (enviar method allí es rechazado):
countryen las cuentas bancarias emitidas es opcional (por defecto según el método); en las cuentas bancarias externas proporciónalo explícitamente. Las cuentas de wallet no llevan país en absoluto.settlement.accountIdes obligatorio en las cuentas bancarias emitidas: identifica la cuenta de wallet emitida que recibe los fondos liquidados de los depósitos hechos en la cuenta bancaria.- Las cuentas emitidas exponen
details(IBAN o routing más account o address),routingversionado (las coordenadas de depósito pueden rotar, muestra siempre la última lectura),fees,balances. - Redes:
polygon,ethereum,base,arbitrum,optimism,bsc,avalanche. - La barrera de capability se aplica solo a las cuentas emitidas: crear una contra una capability no lista falla con un error codificado por capability, solicita primero la capability (2.2). Las cuentas externas no necesitan capability (ni aprobación del customer); obtienen solo validación del esquema de la petición y de los datos bancarios.
- Las cuentas bancarias emitidas nacen en
provisioningcondetails: null. Consulta la cuenta o escuchaaccount.status_changedhastaready. DELETEarchiva, nunca elimina de forma dura. Las cuentas referenciadas por transfers en curso devuelven409 account_has_active_transfers. Reintenta después de que esas transfers alcancen un estado terminal.- Nuevo en v3: Rules, instrucciones permanentes en una cuenta de wallet emitida (
POST/GET /v3/customers/{customerId}/rules,GET/PATCH/DELETE .../rules/{ruleId}) que barren automáticamente los fondos entrantes hacia otra cuenta o un destino de wallet. Sin equivalente en v1 o v2.
2.5 Recipients y destinations
v2 no tenía concepto de recipient. Si estás en v2 y pagas a terceros, esta es superficie nueva, no un cambio de nombre.
- Recipient equivale a quién:
individual(nombre y apellido) obusiness(nombre de empresa), conrelationshipobligatorio (employee,contractor,vendor,subsidiary,merchant,customer,landlord,family,other). Recipients y destinations son solo para terceros. Un payout de primera parte no usa un recipient en absoluto: apunta a una de las propias cuentasacc_del customer comodestinationIdde la quote (2.6). - Destination equivale a dónde: tipado por método,
sepa(iban, bic opcional),achowire(routing más account),swift(coordenadas completas más intermediario opcional),spei(clabe),pse,transfers_3_0(cbu), y demás, más destinos de wallet. Cada destination tiene su propio estado. Escuchadestination.status_changed. - Los destinos fiat requieren la
addresscompleta del recipient (calle, ciudad, código postal, país) antes de la creación. Las piezas faltantes fallan con422 recipient_address_required. Los destinos de wallet omiten la dirección pero requierenownershipde nivel superior (self_custodied, ocustodialcon el nombre de un custodio). - La precisión del nombre del beneficiario importa: los bancos receptores cotejan el nombre legal de la cuenta. Envía el nombre legal exacto y el apellido o el nombre de la empresa, no un alias de visualización.
- Los esquemas de campos de destination por método están en la especificación OpenAPI.
2.6 Quotes y transfers
destinationIdacepta un idacc_(cuenta del propio customer) odst_(destination de recipient). Las quotes financiadas con fiat (payins) deben apuntar a una cuentaacc_, un objetivodst_siempre significa un payout (422 quote_direction_invalidde lo contrario).externalIden quotes y transfers es una referencia de correlación no única (repetida en las lecturas, filtrable en las listas). La regla de unicidad por entorno (2.1) se aplica solo alexternalIddel customer.- Ejecuta una quote exactamente una vez, antes de
expiresAt. Una quote expirada falla con409 quote_expired, una segunda ejecución con409 quote_already_executed(el problema lleva eltransferIdexistente). - La cancelación de transfers aún no está soportada:
POST .../canceldevuelve409 transfer_not_cancelableen todos los estados. Las transferscanceledde hoy provienen de la expiración de la ventana de financiación en un payin sin financiar, no de este endpoint. - Los payins empiezan en
awaiting_funds: muestraGET .../instructionsal pagador, coordenadas bancarias más código de referencia o memo para fiat, dirección de depósito para cripto. El código de referencia es cómo se emparejará el depósito. Muéstralo siempre. statemásstateDetailpara subestados legibles por máquina;action_requiredsignifica que hay una task de cumplimiento adjunta (openTaskIds,GET .../tasks), respondida vía submissions.- Los depósitos entrantes detectados en las cuentas emitidas aparecen como transfers con
origin: "inbound_deposit"(frente a"quoted"). - Las referencias de red de pago se consolidan bajo
references:transactionHash,traceNumber,imad,uetr,explorerUrl,returnedTransferId.
Dos advertencias de migración:
- Las transfers no cruzan versiones. Las transfers creadas en v1 o v2 no son legibles desde v3. La lista las omite y
GET /v3/transfers/{transferId}responde 404. Migra primero la creación, mantén la ruta de lectura v1 hasta que esas transfers alcancen estados terminales, y luego elimínala. - Sin intercambios de tokens.
stablecoin_moverequiere la misma moneda de entrada y de salida: USDC a USDT falla con422 recipient_destination_invalidllevando un error de campocurrency_mismatch. Misma red en ambos lados, sin puentes, y los movimientos entre wallets solo soportan actualmente entrega sin comisiones: una quote cuya comisión de plataforma o de developer sea distinta de cero falla con422 amount_not_deliverable.
2.7 Webhooks
Catálogo de eventos:
customer.created, customer.updated, customer.archived, capability.created, capability.status_changed, application.status_changed, recipient.status_changed, destination.status_changed, account.created, account.status_changed, account.details_changed, transfer.created, transfer.state_changed, api.deprecation.
GET /v3/webhooks/portaldevuelve una URL de portal de gestión alojado para registros de entrega, reintentos y repetición manual.transfer.createdse entrega actualmente con la forma del payload heredado de v1 (el envelope de v3 se activa cuando los webhooks v1 se retiren). Trátalo puramente como una pista y haz GET a la transfer; no construyas contra su cuerpo.- Los eventos son pistas: al recibirlos, haz GET al recurso y actúa sobre la lectura. Nunca construyas estado a partir de los payloads o del orden de los eventos. La entrega es al menos una vez y puede retrasarse o reordenarse. Deduplica por id de evento, y recupera eventos perdidos con el filtro inclusivo
updatedAfterde cada listado. - Suscríbete a
api.deprecation, el canal automatizado para las retiradas de versión. - Sin evento
task.*hoy: después de enviar, consulta la task o su recurso padre.
2.8 Sandbox
Misma URL base; la clave de API del sandbox selecciona el entorno.
El sandbox de v3 simula el bucle de revisión de extremo a extremo: crea una task, envía contra ella,
review para accepted o rejected, observa cómo se desbloquea la capability. Ensaya tu UX de remediación antes de producción. Tanto las tasks creadas en sandbox como las tasks de intake habituales que aparecen en las capabilities solicitadas se revisan así; como en producción, no se disparan webhooks de task, consulta (2.7).
2.9 Endpoints heredados sin reemplazo en v3
Estos no tienen reemplazo en v3. La mayoría permanecen en v1 sin cambios (mantén tus llamadas existentes); dos se retiran directamente (véase Disposición):
Cualquier otro endpoint público de v1 o v2 aparece en alguna tabla de mapeo anterior.
2.10 Orden de migración sugerido
Cada paso se puede publicar de forma independiente; v1 o v2 y v3 conviven contra la misma base de customers. Ensaya cada paso contra tu clave de sandbox (2.8) antes de repetirlo en producción.1
Fontanería
Idempotency-Key en todas las peticiones con efectos (POST, PATCH, PUT, DELETE; endpoints de sandbox exentos); dinero como cadenas; ayudantes de paginación por cursor.2
Webhooks
Registra endpoints v3 por evento, incluyendo
api.deprecation. La configuración de único endpoint de v1 es una superficie separada, déjala en su sitio; ambas conviven hasta el drenaje del paso 9.3
Enriquecimiento del perfil
PATCH /v3/customers/{id} con el perfil completo que poseas (v1 recopilaba menos de lo que v3 expone) y vuelve a establecer metadata. Haz de esto deliberadamente la primera escritura v3 por customer: rellena la vista saneada antes de que esa vista se vuelva permanente (2.1).4
Lecturas
Apunta las lecturas de customer, capability y account a v3; reescribe la lógica de estado de customer según 1.3. Solo después del paso 3, las lecturas sin enriquecer regresan con los campos legado-inválidos ausentes.
5
Escrituras de onboarding
Crea vía
POST /v3/customers; solicita capabilities en lugar de /rails, /banks o applications; construye el bucle de tasks (el mayor trabajo de UI totalmente nuevo, tasks-preview ayuda a mostrar las peticiones por adelantado). A partir de este punto, deja de publicar /v1/documents para customers dirigidos por v3, no desbloquean capabilities (2.3).6
Cuentas
Emite vía v3; mueve las importaciones a
origin: external.7
Payouts
Recipients más destinations, luego quote y transfer.
8
Payins
Quote, transfer, instrucciones; sigue mostrando el código de referencia.
9
Drenaje
Las transfers no cruzan versiones (2.6). Mantén la ruta de lectura de v1 o v2 y el endpoint de webhook v1 para las transfers creadas allí, haz doble lectura hasta que alcancen estados terminales, luego elimina el cliente antiguo y la configuración del webhook v1.
2.11 Lista de escollos
- UUID nuevo por operación lógica, persistido con tu job y reutilizado en el reintento; nunca reutilices una clave con un cuerpo cambiado (
409 idempotency_conflict). Los endpoints de sandbox están exentos de la cabecera. - Enriquece los customers existentes (
PATCHel perfil completo, vuelve a establecermetadata, no se conserva) antes de cualquier otra escritura v3, la primera escritura v3 vuelve permanente la vista saneada. -
externalIdes único por entorno y no se libera al archivar, límpialo conPATCHantes deDELETEsi planeas reutilizarlo. - No existe campo
statusen el customer, deriva la preparación por capability. -
action_requiredein_reviewsignifican ambos una task abierta. - Las submissions están sujetas a revisión (enviar no equivale a desbloquear) y deben responder cada requirement accionable con el
taskRevisionexacto. En caso de desajuste, relee y reconstruye. - No existe webhook
task.*, consulta la task (o su padre) después de cada envío. - Reintento
changes_requestedequivale a releer la task, respuestas nuevas, clave de idempotencia nueva. - Publicar en
/v1/documentsnunca desbloquea una capability v3, una vez que un customer está en tasks, canaliza toda petición a través de tasks. - Pueden aparecer nuevas tasks en una capability ya en
ready, mantén el bucle de tasks activo después del onboarding, no solo durante este. -
cancelde capability solo funciona desdependingorestrictedsin recursos bloqueantes (409 capability_not_cancelable); volver a solicitar tras cancelar es una nueva creación con una nueva clave de idempotencia. - La capability debe estar
readyantes de emitir cuentas bajo ella o cotizar contra ella. - La quote tiene el importe en exactamente un lado; sin campo de dirección; se ejecuta exactamente una vez antes de
expiresAt(409 quote_expiredo409 quote_already_executed). - Los movimientos de stablecoin son solo misma moneda y misma red (USDC a USDT falla
422); wallet a wallet solo soporta entrega sin comisiones. -
DELETEarchiva, nunca elimina de forma dura. El delete de account se bloquea por transfers en curso (409 account_has_active_transfers); el delete de customer además por cualquier account no archivada (409 customer_has_active_resources,blockingResources[]los nombra). - Las transfers de v1 o v2 son invisibles a las lecturas de v3 (la lista las omite, GET 404s), haz doble lectura hasta drenarlas, luego elimina las rutas antiguas.
- El
routingde depósito y las instrucciones pueden rotar, muestra siempre el último GET y muestra siempre el código de referencia. - Los webhooks son pistas; el GET es la verdad, deduplica por id de evento, recupera eventos perdidos con
updatedAfter.