Signing Requests For AI agents: visit https://docs.payb.is/llms.txt for an index of all pages formatted in Markdown and endpoints in OpenAPI. Jump to Content Status page GuidesRecipesAPI ReferenceChangelog v4.1.12Status page API Reference v4.1.12GuidesRecipesAPI ReferenceChangelog Signing Requests JUMP TO Powered by Signing Requests Copy Page All requests to the server should be signed with the private RSA key using the RSASSA_PSS_SHA_512 signing algorithm. Paybis will use the public key to verify the signature and authenticity of your request. 📘 Keys are generated by the Partner, and the public key is provided to Paybis integration manager. 🚧 If the private key was lost, you need to notify the integration team: the related public key stored on the Paybis end should be revoked and the new key pair should be generated. Forming signature A signature should be generated from the private 4096-bit RSA key and HTTP request body hash using the RSASSA_PSS_SHA_512 asymmetric signing algorithm. After that, the signature is encoded with Base64. Signature = Base64(RSASSA_PSS_SHA_512(PRIVATE_KEY, SHA512(requestBody))) Note: Whenever the request body is changed, a new signature should be generated. Requests with empty bodies should not be signed (the GET methods requests). Generating a signature sample code: PHP PHP <?php use phpseclib\Crypt\RSA; $privateKey = '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'; $requestBody = '{ "partnerUserId": "1bc166bd-1808-4009-8454-aceb47ba8753", "cryptoWalletAddress": null, "email": "[email protected]", "applicantSumsubToken": "token_hash", "locale": "en" }'; $requestBodyHash = hash('sha512', $requestBody); $verifier = new RSA(); $verifier->setSignatureMode(RSA::SIGNATURE_PSS); $verifier->setHash('sha512'); $verifier->setMGFHash('sha512'); $verifier->loadKey($privateKey); $signature = base64_encode($verifier->sign($requestBodyHash)); echo $signature . PHP_EOL; composer require phpseclib/phpseclib; Generating a signature sample code: Node.js Node.js const crypto = require("crypto") const privateKey = `-----BEGIN RSA PRIVATE KEY----- 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 -----END RSA PRIVATE KEY-----` // Request body to sign const verifiableData = '{"cryptoWalletAddress":{"address":"valid_btc_crypto_wallet_address","currencyCode":"BTC"},"locale":"en","partnerUserId":"johnDoe1","email":"[email protected]","quoteId":"7604aac0-7938-4e54-8a80-c3172a043c44"}' const hash = crypto.createHash('sha512'); const hashedData = hash.update(verifiableData, 'utf-8').digest('hex'); // The signature method takes the data we want to sign, the // hashing algorithm, and the padding scheme, and generates // a signature in the form of bytes const signature = crypto.sign("sha512", Buffer.from(hashedData), { key: privateKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST, }) console.log(signature.toString("base64")) Verify a signature sample code: Node.js Node.js const crypto = require("crypto") const publicKey = `-----BEGIN RSA PUBLIC KEY----- MIICCgKCAgEAut917lnm3PFcVqbqmVGu+GPHfk5jeebukMekdrrJEuJnQf4Slu6Q +wwAneHDoJVEKa3ecyLjYp9D1wxXCL2m3Cu+Ev4ueOwIKaAFv+ZHl5naHV6T114h C3dIXW31qT9t8n6WvYVz7aAdhRLZBry4eVe0HDabFujM7g+N2eS+XM38zhJvHO1w 5TZcK7EQP25NuLSzyp/QDG/3vb8f4ZrYAgbtmXRnDfu5b88iB2noPfTJcruJ/rr0 +/yic8ytUi5dzOfXGbpDtpcry8DeeJeG9efLsNL7IoTcFgrgTvhKtxbLy3QmPHgA xKvGdP4jSWLJJfMAlIFz8jPuUSxuPKSoKocXZaHb+Zpt6PQl6qotwkHH4Acb/uha jb1sBLbZBbqyjaOZyuWt7yMcdkdkbV14h3S6eaBsLXeeZ/kI+y3j2MKajDQ7k8kM q8wY7Ypco+TAP04EIySuNlrwZlUhZaDpGO77i8yreUCrLerAqikyGygo9jcbsJ93 JsYkvWG5f7qb0+/JsZ0YdoIs19aA4H46rz/eWJT7HPsMk9P+eX4S6xSY/Xjj873v nKHyFsg3Ovq3sb5ovtmJfbLXeWFlvtn/EWXjvyuyf6wJWQK8TAPg3bdpS3DyNm/D Ru94PjdPAQ2mX86dz0D7OWqrhlXHdwn1vopiTjmKtBGdAoR4lsZKTy0CAwEAAQ== -----END RSA PUBLIC KEY-----` const verifiableData = '{"cryptoWalletAddress":{"address":"valid_btc_crypto_wallet_address","currencyCode":"BTC"},"locale":"en","partnerUserId":"johnDoe1","email":"[email protected]","quoteId":"7604aac0-7938-4e54-8a80-c3172a043c44"}' const hash = crypto.createHash('sha512'); const hashedData = hash.update(verifiableData, 'utf-8').digest('hex'); const signature = 'B+Dyfoaeb8YkTHPIAJ54baa8XD14fCdPUhOq1A+9togM2DsyfaYq7qnswy9/LS00x8JzXkIdb7WGGk90qEXEKWUpc8KJ2epHi/sVAMFtudAGulWf/ib2BvRt1us0bylBCtwcXfh9lB4EnjSdoMvCCejSG5Jc5CYIX+v72HCimTjVwaiizIE9/RyBDbe97+1kA/l1CfzQL2QOcX5MjQn7ED6A5r/7tAQNp1KJLLKb8yeTpqppEGvOj6HIe0dZs1lEs1lXWhmBFllQmChSsjf94BDuJK780PePwlIUDKDra/ntQnGOaDZd41ugAjlPnPCC9UhACHL+PG+yKH1a6hIVdA0ZldTzq0kh+Ft1jBY1g21AUS8/Tcqr0Tw3ETchdl2OdxrypOwsZS8VCc+22DSY7MYeKSTHC1xzyS+Arw4VBu08E8d8z9sb9XxiMk1kbBgTNS5OEkYRXwGWy9q76S1xqPZpU9PRpbj1DRfGrcm2sY4rkGrpIT0o78LfeXQ5BPXPdVmObR29s6mDqQ+vwWMX4UiH2o9I58GqDk4/dz3LZLmCzdgUdUmdg7V2FUdQ8/c7Gi5kXLyN5UIJSPfSguMtZZLHTpVorTUY5M6THuctFepGv14b0IlzH/VLgHLUAkONL8/qcK0lv4oubVsisTxr2082M6Bj7J+BLhSLPuAx1YI=' // To verify the data, we provide the same hashing algorithm and // padding scheme we provided to generate the signature, along // with the signature itself, the data that we want to // verify against the signature, and the public key const isVerified = crypto.verify( "sha512", Buffer.from(hashedData), { key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST, }, Buffer.from(signature, 'base64') ) // isVerified should be `true` if the signature is valid console.log("signature verified: ", isVerified) Example signature: mVuJJRvdDJMPWkDHMx0Fj0lOs021Usv6iEHpJVRzX/hNfEawOtJEIGU5hfu6GXrqwWj/+JuGjejNQo2pkoN+OUREv9gylD91GROaLA7zbaQLyiIch97UVi4iyg9d4mVHXtr3kbuxwYDBSOgHV+4mJuGM2jOOXY86bidKdrt+UdcdQlt62DkvmHTLIqfXrLQevTEEs0nzSTorfZkMLKwmXTu+1qJv3+R3QxWFhf2QqMi GR4Y8BiMp/URo7y6fVlI4dbVnqoOU37izXguheDR17R/KFe/SyhtltsAvhVBrbrTd9y34efbTCtNgDe9qdwTolgp7DnDSqHGW9zLrjQdbYdGlLzjbok5tfmtcQUcBhXiEOPmKO+s5ZSR46NAURxg9oh9BjscmG+moMQj244WtT3AAkJVPsTItwnUriZahYDplrppZz9BZXHGjcRf/nh/Xvd3aNv4HKyKPQnpYGNqV9ZvDXYkTdjFp57/vY5h48dg9wOd4BiLJ7FiOWpgtpwUUS1+gbzjvDvgpOPCFVRpgeYqq/LNIfcN1nfqcDSKSvjMzJlsX1xZN/ezinyqGZNaLRiil+wX02ihdMtVknco/ne4MsJvhNg2uTyjBv0VSji8rMDzeYLiDiapj0nm47lQHhH1vthd8BH83oosHBDLaJuPo4M4WuIfdgxfRjohHFKI= This example is generated using the data and PHP sample code provided above. Generating RSA keys To generate the key pair on the Partner's end and share the public key with Paybis, use the following commands: Generate a private 4096-bit RSA key. OpenSSL openssl genrsa -out private.key 4096 Create a public key from a private one. OpenSSL openssl rsa -in private.key -outform PEM -pubout -out public.pub Signing HTTP Requests The signature is passed in the X-Request-Signature header. Paybis decodes and verifies the signature with the public RSA key. If the request signature validation fails, 403 HTTP error code is returned. Updated 8 months ago Did this page help you? Yes No Updated 8 months ago Did this page help you? Yes No Forming signature Generating RSA keys Signing HTTP Requests