{"info":{"_postman_id":"7d1a1481-28e9-458a-847a-c0933a43fe5d","name":"Lynk Webhook","description":"<html><head></head><body><p>This allows merchants to receive real-time notifications about successful transactions and integrate this data into their own systems.</p>\n<h2 id=\"webhook-authentication-with-lynkid\">Webhook Authentication with Lynk.id</h2>\n<h2 id=\"authentication-flow\">Authentication Flow</h2>\n<p>Lynk.id webhooks use a token-based authentication method to secure webhook payloads. Here's how to verify incoming webhook requests:</p>\n<ol>\n<li><p>When you receive a webhook from Lynk.id, it will include a <code>X-Lynk-Signature</code> header</p>\n</li>\n<li><p>Use your <code>merchant key</code> to validate that the request is genuinely from Lynk.id</p>\n</li>\n</ol>\n<h2 id=\"verification-steps\">Verification Steps</h2>\n<ol>\n<li><p>Extract the <code>X-Lynk-Signature</code> from the request headers</p>\n</li>\n<li><p>Extract <code>refId</code>, <code>amount(grandTotal)</code>, and <code>message_id</code> from the request body</p>\n</li>\n<li><p>Use your <code>merchant key</code> (obtained from your Lynk.id dashboard)</p>\n</li>\n<li><p>Process the webhook only if the signature is valid</p>\n</li>\n</ol>\n<h2 id=\"security-tips\">Security Tips</h2>\n<ul>\n<li><p>Never share your <code>merchant key</code> with anyone</p>\n</li>\n<li><p>Always verify the signature before processing webhook data</p>\n</li>\n<li><p>Consider validating timestamps to prevent replay attacks</p>\n</li>\n<li><p>Store your <code>merchant key</code> securely in environment variables</p>\n</li>\n</ul>\n<p><strong>*Note:</strong> <strong><code>merchant key</code></strong> <strong>will be available once you saved a webhook URL.</strong></p>\n<h2 id=\"code-example-python\">Code Example Python</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-python\">import hashlib\ndef validate_lynk_signature(ref_id, amount, message_id, received_signature, secret_key):\n    signature_string = amount + ref_id + message_id + secret_key\n    calculated_signature = hashlib.sha256(signature_string.encode('utf-8')).hexdigest()\n    return calculated_signature == received_signature\n\n</code></pre>\n<h2 id=\"code-example-javascript-nodejs\">Code Example JavaScript (Node.js)</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-javascript\">const crypto = require('crypto');\nfunction validateLynkSignature(ref_id, amount, message_id, receivedSignature, secretKey) {\n  const signatureString = amount + ref_id + message_id + secretKey;\n  const calculatedSignature = crypto\n    .createHash('sha256')\n    .update(signatureString)\n    .digest('hex');\n  return calculatedSignature === receivedSignature;\n}\n\n</code></pre>\n<h2 id=\"code-example-go\">Code Example (Go)</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-go\">package main\nimport (\n    \"crypto/sha256\"\n    \"encoding/hex\"\n)\nfunc ValidateLynkSignature(refID, amount string, message_id string, receivedSignature, secretKey string) bool {\n    signatureString := amount + refID + message_id + secretKey\n    hash := sha256.New()\n    hash.Write([]byte(signatureString))\n    calculatedSignature := hex.EncodeToString(hash.Sum(nil))\n    return calculatedSignature == receivedSignature\n}\n\n</code></pre>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[],"owner":"3211564","collectionId":"7d1a1481-28e9-458a-847a-c0933a43fe5d","publishedId":"2sB2cVf2Kp","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2025-04-08T02:17:06.000Z"},"item":[{"name":"Webhook","item":[{"name":"Webhook POST","id":"61e14299-db58-4289-8557-da08632e2528","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"X-Lynk-Signature","value":"Token","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"event\": \"payment.received\",\n    \"data\": {\n        \"message_action\": \"SUCCESS\",\n        \"message_code\": \"0\",\n        \"message_data\": {\n            \"createdAt\": \"2025-04-10T14:30:45\",\n            \"customer\": {\n                \"email\": \"user@lynk.id\",\n                \"name\": \"Lynk User\",\n                \"phone\": \"0812345677889\"\n            },\n            \"items\": [\n                {\n                    \"addons\": [\n                        {\n                            \"id\": \"67c6b9a5593dd002a0ec4ab7-5498-4703872927-1741076901767\",\n                            \"name\": \"Iniprodukaddon\",\n                            \"price\": \"50,000\"\n                        }\n                    ],\n                    \"appointment_data\": {},\n                    \"pafId\": \"\",\n                    \"price\": 25000,\n                    \"public_affiliate_content\": {},\n                    \"qty\": 1,\n                    \"stock\": 1,\n                    \"title\": \"Digital Produk\",\n                    \"uuid\": \"63cfd869524d15196a557388-8244-36439\"\n                }\n            ],\n            \"refId\": \"13f8d23beeb2aacbbc01c94060cc88d7\",\n            \"shippingAddress\": \"\",\n            \"shippingInfo\": \"\",\n            \"totals\": {\n                \"affiliate\": 0,\n                \"convenienceFee\": -3000,\n                \"discount\": 0,\n                \"grandTotal\": 72000,\n                \"totalAddon\": 50000,\n                \"totalItem\": 1,\n                \"totalPrice\": 25000,\n                \"totalShipping\": 0\n            }\n        },\n        \"message_desc\": \"\",\n        \"message_id\": \"API_CALL_1744270275143115_4624014\",\n        \"message_title\": \"\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"webhook_url","description":"<p>The <strong>webhook_url</strong> is dynamically obtained from the <strong>user data</strong>. You'll need to replace this with an actual URL for testing.</p>\n","urlObject":{"host":["webhook_url"],"query":[],"variable":[]}},"response":[],"_postman_id":"61e14299-db58-4289-8557-da08632e2528"}],"id":"69125184-1743-463f-9b5a-2558c0b996a2","description":"<h2 id=\"about-webhook\"><strong>About Webhook</strong></h2>\n<p>Webhook provide a way for notifications to be delivered to an external web server whenever certain event occur in Lynk.</p>\n<h2 id=\"request-method\"><strong>Request Method</strong></h2>\n<p>The format prepared by the engine is ​JSON​. with Method use <code>POST</code> and <code>application/json</code> for Content-type.</p>\n<h2 id=\"event-type\"><strong>Event Type</strong></h2>\n<p>Message event webhooks can be triggered by several types of events:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th><strong>Event Name</strong></th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>payment.received</td>\n<td>Event triggered after the customer makes a payment / has completed the payment</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Event payment.received payload</strong></p>\n<p>payload that will be sent to the webhook server URL when there is a transaction</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"event\": \"payment.received\",\n    \"data\": {\n        \"message_action\": \"SUCCESS\",\n        \"message_code\": \"0\",\n        \"message_data\": {\n            \"createdAt\": \"2025-04-10T14:30:45\",\n            \"customer\": {\n                \"email\": \"user@lynk.id\",\n                \"name\": \"Lynk User\",\n                \"phone\": \"0812345677889\"\n            },\n            \"items\": [\n                {\n                    \"addons\": [\n                        {\n                            \"id\": \"67c6b9a5593dd002a0ec4ab7-5498-4703872927-1741076901767\",\n                            \"name\": \"Iniprodukaddon\",\n                            \"price\": \"50,000\"\n                        }\n                    ],\n                    \"appointment_data\": {},\n                    \"pafId\": \"\",\n                    \"price\": 25000,\n                    \"public_affiliate_content\": {},\n                    \"qty\": 1,\n                    \"stock\": 1,\n                    \"title\": \"Digital Produk\",\n                    \"uuid\": \"63cfd869524d15196a557388-8244-36439\"\n                }\n            ],\n            \"refId\": \"13f8d23beeb2aacbbc01c94060cc88d7\",\n            \"shippingAddress\": \"\",\n            \"shippingInfo\": \"\",\n            \"totals\": {\n                \"affiliate\": 0,\n                \"convenienceFee\": -3000,\n                \"discount\": 0,\n                \"grandTotal\": 72000,\n                \"totalAddon\": 50000,\n                \"totalItem\": 1,\n                \"totalPrice\": 25000,\n                \"totalShipping\": 0\n            }\n        },\n        \"message_desc\": \"\",\n        \"message_id\": \"API_CALL_1744270275143115_4624014\",\n        \"message_title\": \"\"\n    }\n}\n\n</code></pre>\n<p><strong>Description of fields:</strong></p>\n<p><strong>Root Level:</strong></p>\n<ul>\n<li><p><code>event</code>: (String) The name of the event that triggered the webhook. In this case, it's <code>\"payment.received\"</code>.</p>\n</li>\n<li><p><code>data</code>: (Object) Contains the details of the payment received event.</p>\n</li>\n</ul>\n<p><strong><code>data</code></strong> <strong>Object:</strong></p>\n<ul>\n<li><p><code>message_action</code>: (String) Indicates the status of the message. Example: <code>\"SUCCESS\"</code>.</p>\n</li>\n<li><p><code>message_code</code>: (String) A code representing the message status. Example: <code>\"0\"</code>.</p>\n</li>\n<li><p><code>message_data</code>: (Object) Contains the actual data related to the payment.</p>\n</li>\n<li><p><code>message_desc</code>: (String) A description of the message.</p>\n</li>\n<li><p><code>message_id</code>: (String) A unique identifier for the message. Example: <code>\"API_CALL_1744270275143115_4624014\"</code>.</p>\n</li>\n<li><p><code>message_title</code>: (String) A title for the message.</p>\n</li>\n</ul>\n<p><strong><code>message_data</code></strong> <strong>Object:</strong></p>\n<ul>\n<li><p><code>createdAt</code>: (String) Timestamp indicating when the payment was recorded, in ISO 8601 format. Example: <code>\"2025-04-10T14:30:45\"</code>.</p>\n</li>\n<li><p><code>customer</code>: (Object) Contains customer information.</p>\n</li>\n<li><p><code>items</code>: (Array of Objects) An array of items included in the payment.</p>\n</li>\n<li><p><code>refId</code>: (String) A reference ID for the payment. Example: <code>\"13f8d23beeb2aacbbc01c94060cc88d7\"</code>.</p>\n</li>\n<li><p><code>shippingAddress</code>: (String) The shipping address associated with the payment.</p>\n</li>\n<li><p><code>shippingInfo</code>: (String) Shipping information related to the payment.</p>\n</li>\n<li><p><code>totals</code>: (Object) Contains a breakdown of the payment totals.</p>\n</li>\n</ul>\n<p><strong><code>customer</code></strong> <strong>Object:</strong></p>\n<ul>\n<li><p><code>email</code>: (String) The customer's email address. Example: <code>\"user@lynk.id\"</code>.</p>\n</li>\n<li><p><code>name</code>: (String) The customer's name. Example: <code>\"Lynk User\"</code>.</p>\n</li>\n<li><p><code>phone</code>: (String) The customer's phone number. Example: <code>\"0812345677889\"</code>.</p>\n</li>\n</ul>\n<p><strong><code>items</code></strong> <strong>Array (each object in the array):</strong></p>\n<ul>\n<li><p><code>addons</code>: (Array of Objects) An array of addons associated with the item.</p>\n</li>\n<li><p><code>appointment_data</code>: (Object) Data related to appointments, if applicable.</p>\n</li>\n<li><p><code>pafId</code>: (String) Potentially an ID related to a public affiliate.</p>\n</li>\n<li><p><code>price</code>: (Number) The price of the item. Example: <code>25000</code>.</p>\n</li>\n<li><p><code>public_affiliate_content</code>: (Object) Content related to public affiliates.</p>\n</li>\n<li><p><code>qty</code>: (Number) The quantity of the item. Example: <code>1</code>.</p>\n</li>\n<li><p><code>stock</code>: (Number) The stock level of the item. Example: <code>1</code>.</p>\n</li>\n<li><p><code>title</code>: (String) The title of the item. Example: <code>\"Digital Produk\"</code>.</p>\n</li>\n<li><p><code>uuid</code>: (String) A unique identifier for the item. Example: <code>\"63cfd869524d15196a557388-8244-36439\"</code>.</p>\n</li>\n</ul>\n<p><strong><code>addons</code></strong> <strong>Array (each object in the array):</strong></p>\n<ul>\n<li><p><code>id</code>: (String) The ID of the addon. Example: <code>\"67c6b9a5593dd002a0ec4ab7-5498-4703872927-1741076901767\"</code>.</p>\n</li>\n<li><p><code>name</code>: (String) The name of the addon. Example: <code>\"Iniprodukaddon\"</code>.</p>\n</li>\n<li><p><code>price</code>: (String) The price of the addon. Example: <code>\"50,000\"</code>.</p>\n</li>\n</ul>\n<p><strong><code>totals</code></strong> <strong>Object:</strong></p>\n<ul>\n<li><p><code>affiliate</code>: (Number) The affiliate commission amount. Example: <code>0</code>.</p>\n</li>\n<li><p><code>convenienceFee</code>: (Number) The convenience fee amount. Example: <code>-3000</code>.</p>\n</li>\n<li><p><code>discount</code>: (Number) The discount amount. Example: <code>0</code>.</p>\n</li>\n<li><p><code>grandTotal</code>: (Number) The final net amount that the seller receives after deducting fees. . Example: <code>72000</code>.</p>\n</li>\n<li><p><code>totalAddon</code>: (Number) The total amount for addons. Example: <code>50000</code>.</p>\n</li>\n<li><p><code>totalItem</code>: (Number) The total number of items. Example: <code>1</code>.</p>\n</li>\n<li><p><code>totalPrice</code>: (Number) The total price of the items (excluding addons, shipping, etc.). Example: <code>25000</code>.</p>\n</li>\n<li><p><code>totalShipping</code>: (Number) The total shipping cost. Example: <code>0</code>.</p>\n</li>\n</ul>\n<p><strong>Expected Response:</strong></p>\n<p>A successful response (<code>200 OK</code>) would typically indicate that the webhook was received and processed correctly by the merchant's system. The exact response body will depend on the merchant's implementation.</p>\n<p><strong>Error Handling:</strong></p>\n<p>The code includes basic error handling. If the response.status_code is not 200, the code logs the error message and candidate for a retry.</p>\n","_postman_id":"69125184-1743-463f-9b5a-2558c0b996a2"}],"event":[{"listen":"prerequest","script":{"id":"6237b658-54c1-443c-90ea-ddc1a43f302c","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"736e17ec-c468-4673-9e8c-1a495183757e","type":"text/javascript","exec":[""]}}],"variable":[{"key":"baseUrl","value":"https://farming-simulator.pstmn.io"}]}