Especificación de Solana Pay v1

Resumen

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

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

Motivación

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

Estas URLs pueden ser codificadas en códigos QR o etiquetas NFC, o enviadas 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 gestionar el esquema de URL y proporcionar una experiencia fluida pero segura cuando se encuentren URLs de Solana Pay en el entorno.

Al estandarizar un enfoque simple para resolver estos problemas, aseguramos la 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 el pathname. El valor debe ser la clave pública codificada en base58 de una cuenta nativa de SOL. No se deben usar cuentas de token asociadas.

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

Cantidad

Se permite un solo campo amount como parámetro de consulta opcional. El valor debe ser un número entero no negativo o un número decimal en unidades de "usuario". Para SOL, eso es SOL y no lamports. Para tokens, utiliza 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 .. La notación científica está prohibida.

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 malformada.

SPL Token

Se permite un solo campo spl-token como parámetro de consulta opcional. El valor debe ser la clave pública codificada en base58 de una cuenta de 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 de los campos recipient e spl-token. No se admiten transferencias a cuentas de tokens auxiliares.

Referencia

Se permiten múltiples campos reference como parámetros de consulta opcionales. Los valores deben ser matrices de 32 bytes codificadas 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 ser o no únicos para la solicitud de pago, y pueden corresponder o no a una cuenta en Solana.

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

Etiqueta

Se permite un solo campo label como parámetro de consulta opcional. El valor debe ser una cadena UTF-8 codificada en URL que describa la fuente 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 solo 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 solo 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üedades 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 realizar una solicitud HTTP y componer una transacción.

Enlace

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

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

Si la URL no contiene parámetros de consulta, no debería 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 del valor. Esto no tiene efecto si el valor no está codificado en URL. Si el valor decodificado no es una URL absoluta HTTPS, la billetera debe rechazarlo como malformado.

Solicitud GET

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

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

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

Respuesta GET

La billetera debe manejar los errores del cliente HTTP, errores del servidor, y respuestas de redireccionamiento. La aplicación debe responder con estos, 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 rechazarla como malformada.

La billetera no debe almacenar en caché la respuesta excepto según lo indiquen los encabezados 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 puede firmar la transacción.

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. 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 los errores del cliente HTTP, errores del servidor, y respuestas de redireccionamiento. La aplicación debe responder con estos, o con una respuesta JSON HTTP OK con un cuerpo de:

{ "transaction": "<transaction>" }

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

La aplicación puede responder con una transacción parcial o totalmente firmada. La wallet 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 al account en la solicitud, o el valor cero (new PublicKey(0) o new PublicKey("11111111111111111111111111111111")).
  • La aplicación debe establecer el recentBlockhash al blockhash más reciente, o el valor cero (new PublicKey(0).toBase58() o "11111111111111111111111111111111").
  • La wallet debe ignorar el feePayer en la transacción y establecer el feePayer al account en la solicitud.
  • La wallet debe ignorar el recentBlockhash en la transacción y establecer el recentBlockhash al blockhash más reciente.

Firmas No Vacías

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

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

Si se espera cualquier firma excepto una firma para el account en la solicitud, la wallet debe rechazar la transacción como maliciosa.

Campo de Mensaje Opcional

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, este 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 el cuerpo de la respuesta, que pueden ser agregados por especificaciones futuras.

Ejemplos

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

Ejemplo de Solicitud GET

GET /solana-pay?order=12345 HTTP/1.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate

Ejemplo de 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"}

Ejemplo de 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"}

Ejemplo de 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

Pueden incorporarse formatos y campos adicionales en 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 los desarrolladores de aplicaciones y billeteras.

Un ejemplo real de tal propuesta.

Ver También

Is this page helpful?

Gestionado por

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