Flujos de consentimiento
Autorizar, rastrear y reutilizar el consentimiento de billetera para NuPay y PayPal Wallet.
En esta página
El consentimiento es la autorización del cliente que requiere una billetera compatible antes de que DEUNA pueda recuperar opciones de pago, almacenar una cuenta o completar una compra. DEUNA expone un contrato de consentimiento público al tiempo que adapta el flujo específico del proveedor detrás de él.
Proveedores admitidos y comportamiento#
| Proveedor | ¿Quién utiliza el consentimiento? | Experiencia de aprobación | Fuente de estado | Reutilizar |
|---|---|---|---|---|
| NuPay | Invitado o cliente autenticado, cuando esté habilitado para la conexión | El cliente aprueba en la experiencia Nubank | Webhook del proveedor; GET /merchants/orders/{order_token}/consent devuelve el último estado de DEUNA | Vinculado al pedido y a la identidad del cliente; la autorización caducada se puede actualizar cuando sea compatible |
| Cartera de PayPal | Cliente autenticado mediante PayPal Vault | Redirigir al cliente al devuelto redirect_url | DEUNA encuesta a PayPal cuando el consentimiento se vuelve elegible para verificación | La cuenta PayPal aprobada se expone como método de pago almacenado para compras posteriores. |
Otros métodos de pago pueden utilizar redireccionamientos, OTP o 3DS, pero no utilizan esta API de consentimiento. No llame a los puntos finales de consentimiento a menos que la conexión de billetera seleccionada esté configurada para el consentimiento.
Ciclo de vida#
La progresión normal del estado es pending funcione success. tratar failed y expired como terminales. Trate cualquier estado no reconocido o denegado como no exitoso y no envíe la compra con él.
Antes de empezar#
- Configure la conexión NuPay o PayPal Wallet para la tienda y el entorno correctos.
- Crear un pedido y conservar su
order_token. - Para cuentas de PayPal reutilizables, autentique al cliente y envíe el token de portador del usuario en las solicitudes de consentimiento.
- Lea la respuesta sobre el método de pago. Para la bóveda de PayPal,
authorization.required: trueyauthorization.flow: "consent"indicar que el cliente necesita consentimiento. Utilice los campos de sondeo devueltos en lugar de codificar una cadencia. - Configurar
order.webhook_urls.notify_orderpara que su backend reciba cambios de estado de consentimiento.
Crear consentimiento#
POST /merchants/orders/{order_token}/consent
La ruta pública API Gateway no incluye intencionalmente la ruta interna /api/v1 prefijo de servicio.
curl --request POST \
--url 'https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent' \
--header 'X-API-KEY: YOUR_PRIVATE_API_KEY' \
--header 'X-Store-Code: all' \
--header 'Authorization: Bearer USER_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"payment_method": "wallet",
"payment_method_id": "MERCHANT_PAYMENT_METHOD_ID",
"identity_document": "58188896454",
"identity_document_type": "CPF"
}'const response = await fetch("https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent", {
method: "POST",
headers: {
"X-API-KEY": "YOUR_PRIVATE_API_KEY",
"X-Store-Code": "all",
"Authorization": "Bearer USER_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
"payment_method": "wallet",
"payment_method_id": "MERCHANT_PAYMENT_METHOD_ID",
"identity_document": "58188896454",
"identity_document_type": "CPF"
})
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();import requests
response = requests.request(
"POST",
"https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent",
headers={
"X-API-KEY": "YOUR_PRIVATE_API_KEY",
"X-Store-Code": "all",
"Authorization": "Bearer USER_TOKEN",
"Content-Type": "application/json"
},
json={
"payment_method": "wallet",
"payment_method_id": "MERCHANT_PAYMENT_METHOD_ID",
"identity_document": "58188896454",
"identity_document_type": "CPF"
},
)
response.raise_for_status()
data = response.json()<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent",
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-API-KEY: YOUR_PRIVATE_API_KEY",
"X-Store-Code: all",
"Authorization: Bearer USER_TOKEN",
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode([
"payment_method" => "wallet",
"payment_method_id" => "MERCHANT_PAYMENT_METHOD_ID",
"identity_document" => "58188896454",
"identity_document_type" => "CPF"
])
]);
$response = curl_exec($curl);
curl_close($curl);import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent"))
.header("X-API-KEY", "YOUR_PRIVATE_API_KEY")
.header("X-Store-Code", "all")
.header("Authorization", "Bearer USER_TOKEN")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\n \"payment_method\": \"wallet\",\n \"payment_method_id\": \"MERCHANT_PAYMENT_METHOD_ID\",\n \"identity_document\": \"58188896454\",\n \"identity_document_type\": \"CPF\"\n }"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request, HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
request, err := http.NewRequest("POST", "https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent", strings.NewReader("{\n \"payment_method\": \"wallet\",\n \"payment_method_id\": \"MERCHANT_PAYMENT_METHOD_ID\",\n \"identity_document\": \"58188896454\",\n \"identity_document_type\": \"CPF\"\n }"))
if err != nil { panic(err) }
request.Header.Set("X-API-KEY", "YOUR_PRIVATE_API_KEY")
request.Header.Set("X-Store-Code", "all")
request.Header.Set("Authorization", "Bearer USER_TOKEN")
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil { panic(err) }
defer response.Body.Close()
body, _ := io.ReadAll(response.Body)
fmt.Println(string(body))
}| Campo | Requerido | Descripción |
|---|---|---|
payment_method | Recomendado | Uso wallet. Si se omite, DEUNA utiliza el método de pago del pedido. |
payment_method_id | Recomendado | Identificador de conexión devuelto por la respuesta del método de pago del pedido. Evita la ambigüedad cuando se habilita más de una conexión de billetera. |
identity_document | NuPay | Documento de identidad del cliente. Si se omite, DEUNA podrá derivarlo de la dirección del pedido cuando esté presente. |
identity_document_type | NuPay | Tipo de documento, como CPF. Si se omite, DEUNA podrá derivarlo de la dirección del pedido cuando esté presente. |
Para un usuario autenticado, el token de portador permite a DEUNA asociar el consentimiento exitoso con ese usuario y conexión. El consentimiento del huésped sigue estando vinculado al pedido.
Sobre de respuesta
{
"id": "1625a32a-df4c-4d9b-aec1-4510b3625865",
"type": "transaction.authentication.pending",
"created": "1740608931",
"data": {
"request_id": "req_01JQ7X",
"order": {
"order_token": "7e975d44-a061-4d70-af0f-673f6ee56445",
"transaction_id": "merchant-order-1042",
"external_transaction_id": ""
},
"consent": {
"id": "6fe9a045-9a46-4b25-8b60-d5a9586494c5",
"status": "pending",
"expires_at": "2026-10-02T18:30:00Z",
"authorization_id": "provider-authorization-id",
"redirect_url": "https://provider.example/approve"
}
}
}Tienda data.consent.id, pero conduce la interfaz de usuario desde data.consent.status. Abierto redirect_url sólo cuando está presente. NuPay puede requerir aprobación en la aplicación del proveedor sin devolver una redirección del navegador.
Aprobación completa del proveedor#
Para PayPal Wallet, envíe al cliente a data.consent.redirect_url. El proveedor regresa a través de la ruta de redireccionamiento de consentimiento de DEUNA y DEUNA verifica el estado final del proveedor. Si el cliente cancela, el consentimiento se marca como fallido y no debe utilizarse para la compra.
Para NuPay, indique al cliente que apruebe la solicitud en la experiencia Nubank. El webhook del proveedor actualiza el consentimiento almacenado por DEUNA.
Nunca cree usted mismo URL de aprobación de proveedores ni URL de redireccionamiento de DEUNA. Utilice las URL en la respuesta.
Leer el último estado#
GET /merchants/orders/{order_token}/consent
curl --request GET \
--url 'https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent?payment_method=wallet&payment_method_id=MERCHANT_PAYMENT_METHOD_ID' \
--header 'X-API-KEY: YOUR_PRIVATE_API_KEY' \
--header 'X-Store-Code: all' \
--header 'Authorization: Bearer USER_TOKEN'const response = await fetch("https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent?payment_method=wallet&payment_method_id=MERCHANT_PAYMENT_METHOD_ID", {
method: "GET",
headers: {
"X-API-KEY": "YOUR_PRIVATE_API_KEY",
"X-Store-Code": "all",
"Authorization": "Bearer USER_TOKEN"
}
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();import requests
response = requests.request(
"GET",
"https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent?payment_method=wallet&payment_method_id=MERCHANT_PAYMENT_METHOD_ID",
headers={
"X-API-KEY": "YOUR_PRIVATE_API_KEY",
"X-Store-Code": "all",
"Authorization": "Bearer USER_TOKEN"
},
)
response.raise_for_status()
data = response.json()<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent?payment_method=wallet&payment_method_id=MERCHANT_PAYMENT_METHOD_ID",
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-API-KEY: YOUR_PRIVATE_API_KEY",
"X-Store-Code: all",
"Authorization: Bearer USER_TOKEN"
]
]);
$response = curl_exec($curl);
curl_close($curl);import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent?payment_method=wallet&payment_method_id=MERCHANT_PAYMENT_METHOD_ID"))
.header("X-API-KEY", "YOUR_PRIVATE_API_KEY")
.header("X-Store-Code", "all")
.header("Authorization", "Bearer USER_TOKEN")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request, HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}package main
import (
"fmt"
"io"
"net/http"
)
func main() {
request, err := http.NewRequest("GET", "https://api.sandbox.deuna.io/merchants/orders/ORDER_TOKEN/consent?payment_method=wallet&payment_method_id=MERCHANT_PAYMENT_METHOD_ID", nil)
if err != nil { panic(err) }
request.Header.Set("X-API-KEY", "YOUR_PRIVATE_API_KEY")
request.Header.Set("X-Store-Code", "all")
request.Header.Set("Authorization", "Bearer USER_TOKEN")
response, err := http.DefaultClient.Do(request)
if err != nil { panic(err) }
defer response.Body.Close()
body, _ := io.ReadAll(response.Body)
fmt.Println(string(body))
}Uso authorization.start_polling_after_in_seconds y authorization.polling_interval_in_seconds de la respuesta del método de pago cuando se proporciona. Deje de sondear tan pronto como el estado ya no sea el mismo. pending, cuando expires_at se alcanza, o cuando el cliente abandona el flujo.
La respuesta GET utiliza el mismo sobre que crear consentimiento. Inspeccione siempre ambos data.consent.status y data.error; un resultado de terminal de nivel empresarial se puede representar en el sobre incluso cuando la solicitud HTTP se realizó correctamente.
Manejar webhooks de consentimiento#
DEUNA envía actualizaciones de consentimiento a la orden webhook_urls.notify_order URL. Manejar estos tipos de eventos:
| Tipo de evento | Significado |
|---|---|
transaction.authentication.pending | Se creó la autorización y aún necesita la acción del cliente o del proveedor. |
transaction.authentication.updated | La autorización fue exitosa; se puede utilizar el consentimiento. |
transaction.authentication.failed | La autorización falló o el cliente canceló. |
transaction.authentication.expired | El consentimiento expiró antes de que pudiera utilizarse. |
Responder con 2xx rápidamente, deduplicar por evento idy luego obtenga el consentimiento más reciente si su procesamiento depende del estado actual. La entrega de webhooks y el sondeo GET se complementan entre sí; su caja debe tolerar que llegue primero. Ver Ganchos web.
Utilice el consentimiento aprobado#
NuPay
después success, solicite los métodos de pago del pedido y las opciones de pago a plazos de NuPay. DEUNA utiliza la autorización de consentimiento válida al recuperar esas opciones y al procesar la compra de la billetera. Si la autorización ha caducado y el proveedor admite la actualización, DEUNA intenta actualizarla.
Cartera de PayPal
Para un usuario autenticado, la cuenta PayPal aprobada aparece en stored_payment_methods. Enviar ese identificador de método almacenado como la compra. payment_method; DEUNA verifica que el consentimiento pertenezca al mismo usuario, comerciante y conexión de PayPal antes de utilizarlo.
Al eliminar el método de pago de la billetera almacenado, también se elimina el consentimiento reutilizable asociado.
Eliminar una cuenta PayPal reutilizable
DELETE /users/payment-methods/{payment_method_id}/tokens/{payment_method}
Uso payment_method_id para el identificador de conexión de PayPal y payment_method para el identificador del método almacenado devuelto en stored_payment_methods. Este punto final autenticado por el usuario elimina la cuenta de billetera en el proveedor y elimina el consentimiento reutilizable correspondiente en DEUNA.
curl --request DELETE \
--url 'https://api.sandbox.deuna.io/users/payment-methods/MERCHANT_PAYMENT_METHOD_ID/tokens/STORED_PAYMENT_METHOD_ID' \
--header 'Authorization: Bearer USER_TOKEN' \
--header 'X-Merchant-ID: MERCHANT_ID'const response = await fetch("https://api.sandbox.deuna.io/users/payment-methods/MERCHANT_PAYMENT_METHOD_ID/tokens/STORED_PAYMENT_METHOD_ID", {
method: "DELETE",
headers: {
"Authorization": "Bearer USER_TOKEN",
"X-Merchant-ID": "MERCHANT_ID"
}
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();import requests
response = requests.request(
"DELETE",
"https://api.sandbox.deuna.io/users/payment-methods/MERCHANT_PAYMENT_METHOD_ID/tokens/STORED_PAYMENT_METHOD_ID",
headers={
"Authorization": "Bearer USER_TOKEN",
"X-Merchant-ID": "MERCHANT_ID"
},
)
response.raise_for_status()
data = response.json()<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.deuna.io/users/payment-methods/MERCHANT_PAYMENT_METHOD_ID/tokens/STORED_PAYMENT_METHOD_ID",
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer USER_TOKEN",
"X-Merchant-ID: MERCHANT_ID"
]
]);
$response = curl_exec($curl);
curl_close($curl);import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.deuna.io/users/payment-methods/MERCHANT_PAYMENT_METHOD_ID/tokens/STORED_PAYMENT_METHOD_ID"))
.header("Authorization", "Bearer USER_TOKEN")
.header("X-Merchant-ID", "MERCHANT_ID")
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request, HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}package main
import (
"fmt"
"io"
"net/http"
)
func main() {
request, err := http.NewRequest("DELETE", "https://api.sandbox.deuna.io/users/payment-methods/MERCHANT_PAYMENT_METHOD_ID/tokens/STORED_PAYMENT_METHOD_ID", nil)
if err != nil { panic(err) }
request.Header.Set("Authorization", "Bearer USER_TOKEN")
request.Header.Set("X-Merchant-ID", "MERCHANT_ID")
response, err := http.DefaultClient.Do(request)
if err != nil { panic(err) }
defer response.Body.Close()
body, _ := io.ReadAll(response.Body)
fmt.Println(string(body))
}Una eliminación exitosa regresa 204 No Content. Si el proveedor informa que la cuenta almacenada no es válida durante una compra, DEUNA también elimina el consentimiento reutilizable no válido para que no se vuelva a ofrecer.
Comportamiento de reintento seguro#
- Antes de crear un nuevo consentimiento, lea el estado actual si se perdió la respuesta anterior.
- Un aún válido
pendingosuccessEl consentimiento se reutiliza en lugar de crear otra autorización de proveedor. - no lo vuelvas a intentar
failedoexpiredindefinidamente. Inicie un nuevo intento impulsado por el cliente después de resolver la causa. - un
404significa que DEUNA no pudo encontrar el consentimiento para el pedido o el contexto del usuario. - un
400puede indicar campos no válidos, una conexión no compatible, un flujo de invitados deshabilitado o un resultado del proveedor de terminal. - Mantenga claves API privadas y tokens de usuario en superficies confiables. No registre encabezados de solicitudes ni datos de autorización del proveedor.
Lista de verificación de integración#
- El orden, la conexión, la moneda, la tienda y el entorno coinciden.
- El documento de identidad y el tipo están disponibles para NuPay.
- El cliente se autentica antes de crear un consentimiento reutilizable de PayPal.
- La aplicación admite experiencias de aprobación de aplicaciones y redireccionamiento de proveedores.
- El sondeo utiliza la cadencia devuelta por DEUNA y se detiene en los estados terminales.
notify_orderAcepta y deduplica eventos de autenticación.- La compra comienza sólo después
data.consent.statusessuccess. - Las rutas de falla, vencimiento, cancelación y reintento se prueban en la zona de pruebas.