{
  "info": {
    "name": "Shukria Payments — MPGS API: Void",
    "description": "Void (reverse) a previous MPGS transaction. Works for every MPGS flow (Hosted Checkout, Hosted Session, Direct). A void typically only succeeds shortly after the original transaction, before it is settled.\n\nSet the collection variables before sending:\n- `merchant_api_key`: the merchant's API key (starts with `shkdirect_`).\n- `order_ref`: the MPGS order id (`pg_transactions.gateway_order_ref`, e.g. `SHK-1042`).\n- `target_txn_id`: the MPGS transaction to void (e.g. `SHK-1042-1`). Use \"Retrieve order\" in the MPGS-Retrieve-Order collection to find it.\n- `void_txn_id`: a new, unused transaction id for the void itself (e.g. `void-SHK-1042-1`). Re-sending the same id returns the original result rather than voiding twice.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      { "key": "token", "value": "{{merchant_api_key}}", "type": "string" }
    ]
  },
  "variable": [
    { "key": "base_url", "value": "https://shukriapg.ariticapp.com" },
    { "key": "pg_prefix", "value": "/pgpayments" },
    { "key": "merchant_api_key", "value": "YOUR_MERCHANT_API_KEY" },
    { "key": "order_ref", "value": "SHK-1042" },
    { "key": "target_txn_id", "value": "SHK-1042-1" },
    { "key": "void_txn_id", "value": "void-SHK-1042-1" }
  ],
  "item": [
    {
      "name": "Void transaction",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "",
              "pm.test('HTTP 200', () => pm.response.to.have.status(200));",
              "",
              "if (body.result === 'ERROR') {",
              "  pm.test('Error has a cause', () => pm.expect(body.error).to.have.property('cause'));",
              "} else {",
              "  pm.test('result is SUCCESS / FAILURE / PENDING / UNKNOWN', () =>",
              "    pm.expect(body.result).to.be.oneOf(['SUCCESS', 'FAILURE', 'PENDING', 'UNKNOWN']));",
              "  pm.test('merchant present', () => pm.expect(body.merchant).to.be.a('string'));",
              "  pm.test('order fields present', () => {",
              "    ['amount', 'creationTime', 'currency', 'id', 'totalAuthorizedAmount', 'totalCapturedAmount', 'totalRefundedAmount']",
              "      .forEach(f => pm.expect(body.order).to.have.property(f));",
              "  });",
              "  pm.test('order.id matches', () => pm.expect(body.order.id).to.eql(pm.variables.get('order_ref')));",
              "  pm.test('response.gatewayCode present', () => pm.expect(body.response.gatewayCode).to.be.a('string'));",
              "  pm.test('transaction fields present', () => {",
              "    ['amount', 'currency', 'id', 'type', 'acquirer'].forEach(f => pm.expect(body.transaction).to.have.property(f));",
              "  });",
              "  pm.test('transaction.id is the void id', () => pm.expect(body.transaction.id).to.eql(pm.variables.get('void_txn_id')));",
              "  pm.test('transaction.type is a VOID_* type', () => pm.expect(body.transaction.type).to.match(/^VOID_/));",
              "}"
            ]
          }
        }
      ],
      "request": {
        "method": "PUT",
        "header": [
          { "key": "Accept", "value": "application/json" },
          { "key": "Content-Type", "value": "application/json" }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"apiOperation\": \"VOID\",\n  \"transaction\": {\n    \"targetTransactionId\": \"{{target_txn_id}}\"\n  }\n}",
          "options": { "raw": { "language": "json" } }
        },
        "url": {
          "raw": "{{base_url}}{{pg_prefix}}/api/mpgs/order/{{order_ref}}/transaction/{{void_txn_id}}",
          "host": ["{{base_url}}{{pg_prefix}}"],
          "path": ["api", "mpgs", "order", "{{order_ref}}", "transaction", "{{void_txn_id}}"]
        },
        "description": "Calls MPGS Void (`PUT order/{orderid}/transaction/{transactionid}` with `apiOperation: VOID`) for the authenticated merchant.\n\n`{transactionid}` in the URL is the new id for the void itself; `transaction.targetTransactionId` is the transaction being voided.\n\nSuccess returns: merchant, result, order {amount, creationTime, currency, id, totalAuthorizedAmount, totalCapturedAmount, totalRefundedAmount}, response {gatewayCode}, transaction {acquirer {id}, amount, currency, id, type}.\n\nA decline is still HTTP 200, with `result: FAILURE` and the reason in `response.gatewayCode`.\n\nError returns: `{\"result\": \"ERROR\", \"error\": {cause, explanation, field, supportCode, validationType}}`."
      },
      "response": []
    },
    {
      "name": "Void — missing targetTransactionId (expect 400)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "pm.test('HTTP 400', () => pm.response.to.have.status(400));",
              "pm.test('result is ERROR', () => pm.expect(body.result).to.eql('ERROR'));",
              "pm.test('cause is INVALID_REQUEST', () => pm.expect(body.error.cause).to.eql('INVALID_REQUEST'));",
              "pm.test('field is transaction.targetTransactionId', () => pm.expect(body.error.field).to.eql('transaction.targetTransactionId'));",
              "pm.test('validationType is MISSING', () => pm.expect(body.error.validationType).to.eql('MISSING'));"
            ]
          }
        }
      ],
      "request": {
        "method": "PUT",
        "header": [
          { "key": "Accept", "value": "application/json" },
          { "key": "Content-Type", "value": "application/json" }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"apiOperation\": \"VOID\",\n  \"transaction\": {}\n}",
          "options": { "raw": { "language": "json" } }
        },
        "url": {
          "raw": "{{base_url}}{{pg_prefix}}/api/mpgs/order/{{order_ref}}/transaction/{{void_txn_id}}",
          "host": ["{{base_url}}{{pg_prefix}}"],
          "path": ["api", "mpgs", "order", "{{order_ref}}", "transaction", "{{void_txn_id}}"]
        },
        "description": "Rejected by CloudLayer before MPGS is called."
      },
      "response": []
    },
    {
      "name": "Void — wrong apiOperation (expect 400)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "pm.test('HTTP 400', () => pm.response.to.have.status(400));",
              "pm.test('field is apiOperation', () => pm.expect(body.error.field).to.eql('apiOperation'));",
              "pm.test('validationType is INVALID', () => pm.expect(body.error.validationType).to.eql('INVALID'));"
            ]
          }
        }
      ],
      "request": {
        "method": "PUT",
        "header": [
          { "key": "Accept", "value": "application/json" },
          { "key": "Content-Type", "value": "application/json" }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"apiOperation\": \"CAPTURE\",\n  \"transaction\": {\n    \"targetTransactionId\": \"{{target_txn_id}}\"\n  }\n}",
          "options": { "raw": { "language": "json" } }
        },
        "url": {
          "raw": "{{base_url}}{{pg_prefix}}/api/mpgs/order/{{order_ref}}/transaction/{{void_txn_id}}",
          "host": ["{{base_url}}{{pg_prefix}}"],
          "path": ["api", "mpgs", "order", "{{order_ref}}", "transaction", "{{void_txn_id}}"]
        },
        "description": "Only `VOID` and `REFUND` are accepted on this endpoint. Rejected by CloudLayer before MPGS is called."
      },
      "response": []
    },
    {
      "name": "Void — bad API key (expect 401)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 401', () => pm.response.to.have.status(401));",
              "pm.test('error is unauthorized', () => pm.expect(pm.response.json().error).to.eql('unauthorized'));"
            ]
          }
        }
      ],
      "request": {
        "auth": {
          "type": "bearer",
          "bearer": [
            { "key": "token", "value": "shkdirect_invalid", "type": "string" }
          ]
        },
        "method": "PUT",
        "header": [
          { "key": "Accept", "value": "application/json" },
          { "key": "Content-Type", "value": "application/json" }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"apiOperation\": \"VOID\",\n  \"transaction\": {\n    \"targetTransactionId\": \"{{target_txn_id}}\"\n  }\n}",
          "options": { "raw": { "language": "json" } }
        },
        "url": {
          "raw": "{{base_url}}{{pg_prefix}}/api/mpgs/order/{{order_ref}}/transaction/{{void_txn_id}}",
          "host": ["{{base_url}}{{pg_prefix}}"],
          "path": ["api", "mpgs", "order", "{{order_ref}}", "transaction", "{{void_txn_id}}"]
        },
        "description": "Rejected by MerchantApiAuthPlug."
      },
      "response": []
    }
  ]
}
