Especificación de Solana Pay v1.1

Resumen

Un protocolo estándar para codificar solicitudes de transacciones de Solana dentro de URLs para habilitar pagos y otros casos de uso.

Se ha alcanzado un consenso general sobre esta especificación, y existen implementaciones en Phantom, FTX y Slope.

Este estándar se inspira en BIP 21 y EIP 681.

Motivación

Un protocolo URL estándar para solicitar transferencias nativas de SOL, transferencias de tokens SPL y transacciones de Solana permite una mejor experiencia de usuario entre aplicaciones y billeteras en el ecosistema de Solana.

Estas URLs pueden codificarse en códigos QR o etiquetas NFC, o enviarse entre usuarios y aplicaciones para solicitar pagos y componer transacciones.

Las aplicaciones deben asegurarse de que una transacción haya sido confirmada y sea válida antes de liberar bienes o servicios que se están vendiendo, o conceder acceso a objetos o eventos.

Las billeteras móviles deben registrarse para manejar el esquema de URL para proporcionar una experiencia fluida pero segura cuando se encuentran URLs de Solana Pay en el entorno.

Al estandarizar un enfoque simple para resolver estos problemas, garantizamos una compatibilidad básica de aplicaciones y billeteras para que los desarrolladores puedan enfocarse en abstracciones de nivel superior.

Especificación: Solicitud de transferencia

Una URL de solicitud de transferencia de Solana Pay describe una solicitud no interactiva para una transferencia de SOL o tokens SPL.

solana:<recipient>
?amount=<amount>
&spl-token=<spl-token>
&reference=<reference>
&label=<label>
&message=<message>
&memo=<memo>

La solicitud es no interactiva porque los parámetros en la URL son utilizados por una billetera para componer directamente una transacción.

Destinatario

Se requiere un único campo recipient como ruta. El valor debe ser la pubkey codificada en base58 de una cuenta nativa de SOL. No se deben usar associated token accounts.

En su lugar, para solicitar una transferencia de SPL Token, se debe utilizar el campo spl-token para especificar un mint de SPL Token, a partir del cual se debe derivar la dirección de token asociada del destinatario.

Cantidad

Se permite un único campo amount como parámetro de consulta opcional. El valor debe ser un número entero no negativo o decimal de unidades de "usuario". Para SOL, eso es SOL y no lamports. Para tokens, utilice uiAmountString y no amount.

0 es un valor válido. Si el valor es un número decimal menor que 1, debe tener un 0 inicial antes del .. Se prohíbe la notación científica.

Si no se proporciona un valor, la billetera debe solicitar al usuario la cantidad. Si el número de decimales excede lo admitido para SOL (9) o el SPL Token (específico del mint), la billetera debe rechazar la URL como mal formada.

SPL Token

Se permite un único campo spl-token como parámetro de consulta opcional. El valor debe ser la clave pública codificada en base58 de una cuenta mint de SPL Token.

Si se proporciona el campo, se debe utilizar la convención de Associated Token Account, y la billetera debe incluir una instrucción TokenProgram.Transfer o TokenProgram.TransferChecked como la última instrucción de la transacción.

Si no se proporciona el campo, la URL describe una transferencia nativa de SOL, y la billetera debe incluir una instrucción SystemProgram.Transfer como la última instrucción de la transacción en su lugar.

La billetera debe derivar la dirección ATA a partir de los campos recipient y spl-token. No se admiten transferencias a cuentas de token auxiliares.

Referencia

Se permiten múltiples campos reference como parámetros de consulta opcionales. Los valores deben ser arreglos de 32 bytes codificados en base58. Estos pueden o no ser claves públicas, dentro o fuera de la curva, y pueden o no corresponder con cuentas en Solana.

Si se proporcionan los valores, la billetera debe incluirlos en el orden proporcionado como claves de solo lectura y sin firma en la instrucción SystemProgram.Transfer o TokenProgram.Transfer/TokenProgram.TransferChecked en la transacción de pago. Los valores pueden o no ser únicos para la solicitud de pago, y pueden o no corresponder a una cuenta en Solana.

Debido a que los validadores de Solana indexan las transacciones por estas claves de cuenta, los valores reference pueden utilizarse como IDs de cliente (IDs utilizables antes de conocer la eventual transacción de pago). El método RPC getSignaturesForAddress puede utilizarse para localizar transacciones de esta manera.

Etiqueta

Se permite un único campo label como parámetro de consulta opcional. El valor debe ser una cadena UTF-8 codificada en URL que describa el origen de la solicitud de transferencia.

Por ejemplo, esto podría ser el nombre de una marca, tienda, aplicación o persona que realiza la solicitud. La billetera debe decodificar la URL del valor y mostrar el valor decodificado al usuario.

Mensaje

Se permite un único campo message como parámetro de consulta opcional. El valor debe ser una cadena UTF-8 codificada en URL que describa la naturaleza de la solicitud de transferencia.

Por ejemplo, esto podría ser el nombre de un artículo que se está comprando, un ID de pedido o una nota de agradecimiento. La billetera debe decodificar la URL del valor y mostrar el valor decodificado al usuario.

Memo

Se permite un único campo memo como parámetro de consulta opcional. El valor debe ser una cadena UTF-8 codificada en URL que debe incluirse en una instrucción SPL Memo en la transacción de pago.

La billetera debe decodificar la URL del valor y debería mostrar el valor decodificado al usuario. El memo será registrado por los validadores y no debe incluir información privada o sensible.

Si se proporciona el campo, la billetera debe incluir una instrucción MemoProgram como la penúltima instrucción de la transacción, inmediatamente antes de la instrucción de transferencia de SOL o Token SPL, para evitar ambigüedad con otras instrucciones en la transacción.

Ejemplos

URL que describe una solicitud de transferencia de 1 SOL

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=1&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId12345

URL que describe una solicitud de transferencia de 0.01 USDC

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

URL que describe una solicitud de transferencia de SOL (se solicita al usuario el monto)

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?label=Michael

Especificación: Solicitud de Transacción

Una URL de solicitud de transacción de Solana Pay describe una solicitud interactiva para cualquier transacción de Solana.

solana:<link>

La solicitud es interactiva porque los parámetros en la URL son utilizados por una billetera para hacer una solicitud HTTP y componer una transacción.

Enlace

Se requiere un único campo link como pathname. El valor debe ser una URL HTTPS absoluta condicionalmente codificada en URL.

Si la URL contiene parámetros de consulta, debe estar codificada en URL. Los parámetros de consulta del protocolo pueden agregarse a esta especificación. Codificar el valor en URL previene conflictos con los parámetros del protocolo.

Si la URL no contiene parámetros de consulta, no debe estar codificada en URL. Esto produce una URL más corta y un código QR menos denso.

En cualquier caso, la billetera debe decodificar la URL el valor. Esto no tiene efecto si el valor no está codificado en URL. Si el valor decodificado no es una URL HTTPS absoluta, la billetera debe rechazarlo como mal formado.

Solicitud GET

La billetera debe realizar una solicitud JSON GET HTTP a la URL. La solicitud no debe identificar la billetera ni al usuario.

La billetera debe realizar la solicitud con un encabezado Accept-Encoding, y la aplicación debe responder con un encabezado Content-Encoding para la compresión HTTP.

La billetera debe mostrar el dominio de la URL mientras se realiza la solicitud.

Respuesta GET

La billetera debe manejar las respuestas HTTP de error del cliente, error del servidor y redirección. La aplicación debe responder con estas, o con una respuesta JSON HTTP OK con un cuerpo de:

{ "label": "<label>", "icon": "<icon>" }

El valor <label> debe ser una cadena UTF-8 que describa la fuente de la solicitud de transacción. Por ejemplo, esto podría ser el nombre de una marca, tienda, aplicación o persona que realiza la solicitud.

El valor <icon> debe ser una URL HTTP o HTTPS absoluta de una imagen de icono. El archivo debe ser una imagen SVG, PNG o WebP, o la billetera debe rechazarlo como malformado.

La billetera no debe almacenar en caché la respuesta excepto según lo indiquen las cabeceras de respuesta de almacenamiento en caché HTTP.

La billetera debe mostrar la etiqueta y renderizar la imagen del icono al usuario.

Solicitud POST

La billetera debe realizar una solicitud JSON HTTP POST a la URL con un cuerpo de:

{ "account": "<account>" }

El valor <account> debe ser la clave pública codificada en base58 de una cuenta que pueda firmar la transacción.

La billetera debe realizar la solicitud con una cabecera Accept-Encoding, y la aplicación debe responder con una cabecera Content-Encoding para la compresión HTTP.

La billetera debe mostrar el dominio de la URL mientras se realiza la solicitud. Si se realizó una solicitud GET, la billetera también debe mostrar la etiqueta y renderizar la imagen del icono de la respuesta.

Respuesta POST

La billetera debe manejar las respuestas HTTP de error del cliente, error del servidor y redirección. La aplicación debe responder con estas, o con una respuesta JSON HTTP OK con un cuerpo de:

{ "transaction": "<transaction>" }

El valor de <transaction> debe ser una transacción serializada codificada en base64. La billetera debe decodificar la transacción en base64 y deserializarla.

La aplicación puede responder con una transacción parcial o totalmente firmada. La billetera debe validar la transacción como no confiable.

Firmas Vacías

Si las signatures de la transacción están vacías:

  • La aplicación debe establecer el feePayer en el account de la solicitud, o en el valor cero (new PublicKey(0) o new PublicKey("11111111111111111111111111111111")).
  • La aplicación debe establecer el recentBlockhash en el blockhash más reciente, o en el valor cero (new PublicKey(0).toBase58() o "11111111111111111111111111111111").
  • La billetera debe ignorar el feePayer de la transacción y establecer el feePayer en el account de la solicitud.
  • La billetera debe ignorar el recentBlockhash de la transacción y establecer el recentBlockhash en el blockhash más reciente.

Si las signatures de la transacción no están vacías:

La billetera solo debe firmar la transacción con el account de la solicitud, y debe hacerlo únicamente si se espera una firma para el account de la solicitud.

Si se espera cualquier firma que no sea una firma para el account de la solicitud, la billetera debe rechazar la transacción como maliciosa.

La aplicación también puede incluir un campo opcional message en el cuerpo de la respuesta:

{ "message": "<message>", "transaction": "<transaction>" }

El valor <message> debe ser una cadena UTF-8 que describa la naturaleza de la respuesta de la transacción.

Por ejemplo, esto podría ser el nombre de un artículo que se está comprando, un descuento aplicado a la compra, o una nota de agradecimiento. La billetera debe mostrar el valor al usuario.

La billetera y la aplicación deben permitir campos adicionales en el cuerpo de la solicitud y en el cuerpo de la respuesta, que pueden ser añadidos por futuras especificaciones.

Ejemplo

URL que describe una solicitud de transacción.
solana:https://example.com/solana-pay
URL que describe una solicitud de transacción con parámetros de consulta.
solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345
Solicitud GET
GET /solana-pay?order=12345 HTTP/1.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate
Respuesta GET
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
Content-Length: 62
Content-Encoding: gzip
{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
Solicitud POST
POST /solana-pay?order=12345 HTTP/1.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate
Content-Type: application/json
Content-Length: 57
{"account":"mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN"}
Respuesta POST
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
Content-Length: 298
Content-Encoding: gzip
{"message":"Thanks for all the fish","transaction":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECC4JMKqNplIXybGb/GhK1ofdVWeuEjXnQor7gi0Y2hMcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAAAMAgAAAAAAAAAAAAAA"}

Extensiones

Formatos y campos adicionales pueden incorporarse a esta especificación para habilitar nuevos casos de uso mientras se garantiza la compatibilidad con aplicaciones y billeteras.

Por favor, abre un issue en Github para proponer cambios a la especificación con el fin de solicitar retroalimentación de desarrolladores de aplicaciones y billeteras.

Un ejemplo real de tal propuesta.

Is this page helpful?

Gestionado por

© 2026 Fundación Solana.
Todos los derechos reservados.
Conéctate