PageSourceSearch

https://keploy.io/docs/assets/js/8e2fb8b4.a6d171de.js

js keploy.io collected 2026-10-02 11:08:05 UTC 46,080 bytes, 2 lines download raw bytes

1"use strict";(globalThis.webpackChunkkeploy_docs=globalThis.webpackChunkkeploy_docs||[]).push([[5878],{81285(e,t,s){s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>x,frontMatter:()=>d,metadata:()=>n,toc:()=>h});const n=JSON.parse('{"id":"running-keploy/api-testing-webhook","title":"Webhook Integration","description":"Integrate custom logic and external validations into your API testing lifecycle with Keploy\'s webhooks.","source":"@site/versioned_docs/version-4.0.0/running-keploy/api-testing-webhook.md","sourceDirName":"running-keploy","slug":"/running-keploy/api-testing-webhook","permalink":"/docs/running-keploy/api-testing-webhook","draft":false,"unlisted":false,"editUrl":"https://github.com/keploy/docs/blob/master/versioned_docs/version-4.0.0/running-keploy/api-testing-webhook.md","tags":[{"inline":true,"label":"API testing","permalink":"/docs/tags/api-testing"},{"inline":true,"label":"webhooks","permalink":"/docs/tags/webhooks"},{"inline":true,"label":"integration","permalink":"/docs/tags/integration"},{"inline":true,"label":"custom validation","permalink":"/docs/tags/custom-validation"},{"inline":true,"label":"policy enforcement","permalink":"/docs/tags/policy-enforcement"}],"version":"4.0.0","lastUpdatedBy":"Shubham Jain","lastUpdatedAt":1790780999000,"frontMatter":{"id":"api-testing-webhook","title":"Webhook Integration","sidebar_label":"Webhook Integration","description":"Integrate custom logic and external validations into your API testing lifecycle with Keploy\'s webhooks.","tags":["API testing","webhooks","integration","custom validation","policy enforcement"],"keywords":["webhook","API testing","PreExecute","PostExecute","external validation","custom logic"]},"sidebar":"sidebarExplanation","previous":{"title":"CI/CD Integration","permalink":"/docs/running-keploy/api-testing-cicd"},"next":{"title":"Test Run Reports","permalink":"/docs/running-keploy/api-testing-run-report"}}');var l=s(74848),i=s(28453),r=s(12483);const d={id:"api-testing-webhook",title:"Webhook Integration",sidebar_label:"Webhook Integration",description:"Integrate custom logic and external validations into your API testing lifecycle with Keploy's webhooks.",tags:["API testing","webhooks","integration","custom validation","policy enforcement"],keywords:["webhook","API testing","PreExecute","PostExecute","external validation","custom logic"]},o=void 0,c={},h=[{value:"Keploy ATG Webhook Integration Guide",id:"keploy-atg-webhook-integration-guide",level:2},{value:"1. Overview",id:"1-overview",level:3},{value:"2. Quick Start: A Demonstration Server",id:"2-quick-start-a-demonstration-server",level:3},{value:"To Run the Go Server:",id:"to-run-the-go-server",level:4},{value:"3. Core Concepts",id:"3-core-concepts",level:3},{value:"The Two Phases: <code>PreExecute</code> and <code>PostExecute</code>",id:"the-two-phases-preexecute-and-postexecute",level:4},{value:"The Golden Rule: Fail-Only Override",id:"the-golden-rule-fail-only-override",level:4},{value:"4. API Reference: Data Structures",id:"4-api-reference-data-structures",level:3},{value:"4.1 Top-Level Object: <code>WebhookReview</code>",id:"41-top-level-object-webhookreview",level:4},{value:"4.2 The <code>WebhookRequest</code> Payload",id:"42-the-webhookrequest-payload",level:4},{value:"4.3 The <code>WebhookResponse</code> Body (Your Server&#39;s Reply)",id:"43-the-webhookresponse-body-your-servers-reply",level:4},{value:"4.4 Detailed Object Definitions",id:"44-detailed-object-definitions",level:4},{value:"<code>TestSuite</code> Object",id:"testsuite-object",level:4},{value:"<code>APIStep</code> Object",id:"apistep-object",level:4},{value:"<code>APIRequest</code> Object",id:"apirequest-object",level:4},{value:"<code>APIResponse</code> Object",id:"apiresponse-object",level:4},{value:"<code>Assertion</code> Object",id:"assertion-object",level:4},{value:"<code>AssertionFailure</code> Object",id:"assertionfailure-object",level:4},{value:"<code>SuiteResult</code> Object",id:"suiteresult-object",level:4},{value:"5. Use Cases &amp; Examples",id:"5-use-cases--examples",level:3},{value:"Example 1: Denying a Request in PreExecute",id:"example-1-denying-a-request-in-preexecute",level:4},{value:"Example 2: Forcing a Failure in PostExecute",id:"example-2-forcing-a-failure-in-postexecute",level:4},{value:"6. Best Practices",id:"6-best-practices",level:3},{value:"Related",id:"related",level:2}];function a(e){const t={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(r.A,{tiers:"Scale, Enterprise",offerings:"Self-Hosted, Dedicated"}),"\n",(0,l.jsx)(t.h2,{id:"keploy-atg-webhook-integration-guide",children:"Keploy ATG Webhook Integration Guide"}),"\n",(0,l.jsx)(t.h3,{id:"1-overview",children:"1. Overview"}),"\n",(0,l.jsx)(t.p,{children:"This powerful feature allows you to integrate your own custom logic directly into the test generation and execution lifecycle."}),"\n",(0,l.jsx)(t.p,{children:"You can use webhooks to:"}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Enforce Custom Policies:"})," Deny certain types of requests from being executed (e.g., prevent ",(0,l.jsx)(t.code,{children:"DELETE"})," requests in a staging environment)."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Perform External Validation:"})," Force a test step to fail if the response doesn't meet external 
1criteria (e.g., check for a specific audit header)."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Trigger External Workflows:"})," Log test results to a third-party system, send notifications to Slack, or create tickets in Jira."]}),"\n"]}),"\n",(0,l.jsx)(t.p,{children:"This document provides all the information you need to build a server that can receive and respond to Keploy webhooks."}),"\n",(0,l.jsx)(t.h3,{id:"2-quick-start-a-demonstration-server",children:"2. Quick Start: A Demonstration Server"}),"\n",(0,l.jsxs)(t.p,{children:["To help you get started, we've provided a sample webhook server below. ",(0,l.jsx)(t.strong,{children:"Please note that this is just a demonstration and should not be considered a required baseline."})," You are free to implement your webhook server in any language or framework you choose (e.g., Python with Flask, Node.js with Express, Java with Spring, etc.)."]}),"\n",(0,l.jsx)(t.p,{children:"This particular example is written in Go for its simplicity and because it can be run as a single, self-contained file without external dependencies. It demonstrates how to:"}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsxs)(t.li,{children:["Correctly parse the incoming ",(0,l.jsx)(t.code,{children:"WebhookReview"})," JSON payload."]}),"\n",(0,l.jsxs)(t.li,{children:["Differentiate between the ",(0,l.jsx)(t.code,{children:"PreExecute"})," and ",(0,l.jsx)(t.code,{children:"PostExecute"})," phases."]}),"\n",(0,l.jsxs)(t.li,{children:["Return a valid ",(0,l.jsx)(t.code,{children:"WebhookResponse"})," object."]}),"\n"]}),"\n",(0,l.jsx)(t.p,{children:"This specific server also includes a random pass/fail logic, which is useful for testing how your Keploy instance handles unpredictable webhook behavior. You can use this code as a reference for building your own custom logic."}),"\n",(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-go",children:'package main\n\nimport (\n\t"encoding/json"\n\t"log"\n\t"math/rand"\n\t"net/http"\n\t"time"\n)\n\nconst failureProbability = 0.3\n\n// We will use a seeded random number generator for true randomness.\nvar rng *rand.Rand\n\ntype APIRequest struct {\n\tMethod  string            `json:"method"`\n\tURL     string            `json:"url"`\n\tHeaders map[string]string `json:"headers"`\n\tBody    string            `json:"body"`\n}\n\ntype APIResponse struct {\n\tStatus  int               `json:"status"`\n\tHeaders map[string]string `json:"headers"`\n\tBody    string            `json:"body"`\n}\n\ntype TestSuiteInfo struct {\n\tName string `json:"name"`\n}\n\ntype APIStepInfo struct {\n\tName string `json:"name"`\n}\n\ntype WebhookRequest struct {\n\tPhase            string        `json:"phase"`\n\tTestSuiteInfo    TestSuiteInfo `json:"testSuiteInfo"`\n\tCurrentStep      APIStepInfo   `json:"currentStep"`\n\tRequestToSend    *APIRequest   `json:"requestToSend,omitempty"`\n\tResponseReceived *APIResponse  `json:"responseReceived,omitempty"`\n\tStepPassed       *bool         `json:"stepPassed,omitempty"`\n}\n\ntype WebhookReview struct {\n\tRequest  *WebhookRequest  `json:"request"`\n\tResponse *WebhookResponse `json:"response,omitempty"`\n}\n\ntype WebhookResponse struct {\n\tPass   bool   `json:"pass"`\n\tReason string `json:"reason,omitempty"`\n}\n\nfunc webhookHandler(w http.ResponseWriter, r *http.Request) {\n\tif r.Method != http.MethodPost {\n\t\thttp.Error(w, "Only POST method is accepted", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\tvar review WebhookReview\n\tif err := json.NewDecoder(r.Body).Decode(&review); err != nil {\n\t\thttp.Error(w, "Invalid JSON payload", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif review.Request == nil {\n\t\thttp.Error(w, "Invalid payload format: missing \'request\' object", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tlog.Println("\\n\\n--- \u2705 Webhook Received ---")\n\tlog.Printf("Phase: %s", review.Request.Phase)\n\n\tswitch review.Request.Phase {\n\tcase "PreExecute":\n\t\tlog.Printf("Suite: %s, Step: %s", review.Request.TestSuiteInfo.Name, review.Request.CurrentStep.Name)\n\n\t\twebhookResp := WebhookReview{}\n\n\t\tif rng.Float64() < failureProbability {\n\t\t\tlog.Println("\ud83c\udfb2 RANDOMLY FAILING pre-execution step.")\n\t\t\twebhookResp.Response = &WebhookResponse{\n\t\t\t\tPass:   false,\n\t\t\t\tReason: "Step was randomly selected to fail by the pre-execution hook.",\n\t\t\t}\n\t\t\tsendJSONResponse(w, http.StatusOK, webhookResp)\n\t\t\treturn\n\t\t}\n\n\t\tlog.Println("\ud83c\udfb2 Random check passed. Approving request.")\n\n\t\twebhookResp.Response = &WebhookResponse{\n\t\t\tPass: true,\n\t\t}\n\n\t\tsendJSONResponse(w, http.StatusOK, webhookResp)\n\t\treturn\n\n\tcase "PostE
1xecute":\n\t\tlog.Printf("Suite: %s, Step: %s", review.Request.TestSuiteInfo.Name, review.Request.CurrentStep.Name)\n\t\tif review.Request.StepPassed != nil {\n\t\t\tlog.Printf("Initial Step Result: %t", *review.Request.StepPassed)\n\t\t}\n\n\t\twebhookResp := WebhookReview{}\n\n\t\tif review.Request.StepPassed != nil && *review.Request.StepPassed {\n\t\t\tif rng.Float64() < failureProbability {\n\t\t\t\tlog.Println("\ud83c\udfb2 RANDOMLY OVERRIDING a passing step to FAIL.")\n\t\t\t\twebhookResp.Response = &WebhookResponse{\n\t\t\t\t\tPass:   false,\n\t\t\t\t\tReason: "A passing step was randomly selected to be failed by the post-execution hook.",\n\t\t\t\t}\n\t\t\t\tsendJSONResponse(w, http.StatusOK, webhookResp)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Println("\ud83c\udfb2 Random check passed. Acknowledging successful step.")\n\t\t} else {\n\t\t\tlog.Println("Acknowledging an already failed step. No random check needed.")\n\t\t}\n\n\t\twebhookResp.Response = &WebhookResponse{\n\t\t\tPass: true,\n\t\t}\n\n\t\tsendJSONResponse(w, http.StatusOK, webhookResp)\n\t\treturn\n\n\tdefault:\n\t\tlog.Printf("Received unknown phase: %s", review.Request.Phase)\n\t\thttp.Error(w, "Unknown phase", http.StatusBadRequest)\n\t}\n}\n\nfunc sendJSONResponse(w http.ResponseWriter, statusCode int, payload interface{}) {\n\tw.Header().Set("Content-Type", "application/json")\n\tw.WriteHeader(statusCode)\n\tif err := json.NewEncoder(w).Encode(payload); err != nil {\n\t\tlog.Printf("Error encoding JSON response: %v", err)\n\t}\n}\n\nfunc main() {\n\trng = rand.New(rand.NewSource(time.Now().UnixNano()))\n\n\thttp.HandleFunc("/webhook", webhookHandler)\n\n\tport := "3001"\n\tlog.Printf("\ud83d\ude80 Go Random Webhook Server listening at http://localhost:%s", port)\n\tlog.Printf("Endpoint is http://localhost:%s/webhook", port)\n\tlog.Printf("Failure probability is set to %.0f%%", failureProbability*100)\n\n\tif err := http.ListenAndServe(":"+port, nil); err != nil {\n\t\tlog.Fatalf("Could not start server: %s\\n", err)\n\t}\n}\n'})}),"\n",(0,l.jsx)(t.h4,{id:"to-run-the-go-server",children:"To Run the Go Server:"}),"\n",(0,l.jsxs)(t.ol,{children:["\n",(0,l.jsxs)(t.li,{children:["Save the code above as ",(0,l.jsx)(t.code,{children:"main.go"})," in a new directory."]}),"\n",(0,l.jsxs)(t.li,{children:["Open your terminal, navigate to that directory, and run the command:","\n",(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"go run main.go\n"})}),"\n"]}),"\n",(0,l.jsxs)(t.li,{children:["Your server is now listening at ",(0,l.jsx)(t.code,{children:"http://localhost:3001/webhook"}),". Use this URL in the Keploy UI settings."]}),"\n"]}),"\n",(0,l.jsx)(t.h3,{id:"3-core-concepts",children:"3. Core Concepts"}),"\n",(0,l.jsxs)(t.h4,{id:"the-two-phases-preexecute-and-postexecute",children:["The Two Phases: ",(0,l.jsx)(t.code,{children:"PreExecute"})," and ",(0,l.jsx)(t.code,{children:"PostExecute"})]}),"\n",(0,l.jsx)(t.p,{children:"Keploy sends a webhook at two distinct points for every single test step:"}),"\n",(0,l.jsxs)(t.ol,{children:["\n",(0,l.jsxs)(t.li,{children:["\n",(0,l.jsxs)(t.p,{children:[(0,l.jsxs)(t.strong,{children:[(0,l.jsx)(t.code,{children:"PreExecute"}),":"]})," Sent ",(0,l.jsx)(t.strong,{children:"before"})," the API request is made."]}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Purpose:"})," To act as a gatekeeper. Your server can inspect the ",(0,l.jsx)(t.code,{children:"requestToSend"})," and decide whether to allow the step to proceed."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Your Response:"})," Your server must return ",(0,l.jsx)(t.code,{children:'{"pass": true}'})," to allow execution or ",(0,l.jsx)(t.code,{children:'{"pass": false}'})," to deny it, effectively failing the step before it even runs."]}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(t.li,{children:["\n",(0,l.jsxs)(t.p,{children:[(0,l.jsxs)(t.strong,{children:[(0,l.jsx)(t.code,{children:"PostExecute"}),":"]})," Sent ",(0,l.jsx)(t.strong,{children:"after"})," the API request has been made and Keploy has run its own internal assertions."]}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Purpose:"})," To act as a final validation layer. Your server can inspect the request, the response, and Keploy's initial pass/fail result."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Your Response:"})," Your server can return ",(0,l.jsx)(t.code,{children:'{"pass": false}'})," to override a passing step and force it to fail."]}),"\n"]}),"\n"]}),"\n"]}
1),"\n",(0,l.jsx)(t.h4,{id:"the-golden-rule-fail-only-override",children:"The Golden Rule: Fail-Only Override"}),"\n",(0,l.jsxs)(t.p,{children:["This is the most important rule: ",(0,l.jsx)(t.strong,{children:"A webhook can make a passing step fail, but it can never make a failing step pass."})]}),"\n",(0,l.jsx)(t.p,{children:"If Keploy's internal assertions determine a step has failed (e.g., a 500 status code was received when a 200 was expected), the step is permanently failed. Your webhook cannot reverse this decision. This protects the integrity of your test results."}),"\n",(0,l.jsx)(t.h3,{id:"4-api-reference-data-structures",children:"4. API Reference: Data Structures"}),"\n",(0,l.jsxs)(t.p,{children:["Your webhook server will receive an HTTP POST request with a ",(0,l.jsx)(t.code,{children:"Content-Type: application/json"})," header. The body of the request will be a single JSON object, the ",(0,l.jsx)(t.code,{children:"WebhookReview"}),"."]}),"\n",(0,l.jsxs)(t.p,{children:["Your server must respond with a ",(0,l.jsx)(t.code,{children:"200 OK"})," status and a JSON body matching the ",(0,l.jsx)(t.code,{children:"WebhookResponse"})," structure described below."]}),"\n",(0,l.jsxs)(t.h4,{id:"41-top-level-object-webhookreview",children:["4.1 Top-Level Object: ",(0,l.jsx)(t.code,{children:"WebhookReview"})]}),"\n",(0,l.jsx)(t.p,{children:"This is the outermost object of the JSON payload sent to your server."}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsx)(t.tbody,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"request"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"WebhookRequest"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.strong,{children:"Required."})," The main payload containing all event context. See ",(0,l.jsx)(t.code,{children:"WebhookRequest"})," object below."]})]})})]}),"\n",(0,l.jsxs)(t.h4,{id:"42-the-webhookrequest-payload",children:["4.2 The ",(0,l.jsx)(t.code,{children:"WebhookRequest"})," Payload"]}
1),"\n",(0,l.jsx)(t.p,{children:"This object contains all the context for the current event. Some fields are only present in specific phases."}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Presence"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"phase"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Always"}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:'"PreExecute" or "PostExecute".'})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"testSuiteInfo"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"TestSuite"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Always"}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The full definition of the test suite currently being executed. See ",(0,l.jsx)(t.code,{children:"TestSuite"})," object below."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"currentStep"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"APIStep"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Always"}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The definition of the API step this event pertains to. See ",(0,l.jsx)(t.code,{children:"APIStep"})," object below."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"stepIndex"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"int"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Always"}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The zero-based index of the current step within the test suite."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"executedSteps"})})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.code,{children:"array"})," of ",(0,l.jsx)(t.code,{children:"SuiteResult"})]}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Always"}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Results of previous steps in this suite, providing stateful context. Can be an empty array."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"requestToSend"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"APIRequest"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Always"}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The fully rendered request that Keploy intends to send or has already sent. See ",(0,l.jsx)(t.code,{children:"APIRequest"})," object below."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"responseReceived"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"APIResponse"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"PostExecute only"}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The actual response received from your application. See ",(0,l.jsx)(t.code,{children:"APIResponse"})," object below."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"stepPassed"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"boolean"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"PostExecute only"}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["Keploy's initial verdict. ",(0,l.jsx)(t.code,{children:"true"})," if all internal assertions passed, ",(0,l.jsx)(t.code,{children:"false"})," otherwise."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"assertionFailures"})})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.code,{children:"array"})," of ",(0,l.jsx)(t.code,{children:"AssertionFailure"})]}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"PostExecute only"}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["A list of failures if ",(0,l.jsx)(t.code,{children:"stepPassed"})," is ",(0,l.jsx)(t.code,{children:"false"}),". Will be absent or empty if the step passed."]})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"43-the-webhookresponse-body-your-servers-reply",children:["4.3 The ",(0,l.jsx)(t.code,{children:"WebhookResponse"})," Body (Your Server's Reply)"]}),"\n",(0,l.jsxs)(t.p,{children:["This is the JSON object your server ",(0,l.jsx)(t.strong,{children:"must"})," return in the response body."]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"pass"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"boolean"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.strong,{children:"Required."})," If ",(0,l.jsx)(t.code,{children:"false"}),", the step is failed. In ",(0,l.jsx)(t.code,{children:"PreExecute"}),", this stops the step. In ",(0,l.jsx)(t.code,{children:"PostExecute"}),", this overrides a ",(0,l.jsx)(t.code,{children:"true"})," result from Keploy."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.strong,{children:(0,l.jsx)(t.code,{children:"reason"})})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.strong,{children:"Optional."})," A message explaining why your webhook returned ",(0,l.jsx)(t.code,{children:"pass: false"}),". This reason will be included in the test report."]})]})]})]}),"\n",(0,l.jsx)(t.h4,{id:"44-detailed-object-definitions",children:"4.4 Detailed Object Definitions"}),"\n",(0,l.jsx)(t.p,{children:"These are the detailed structures for the complex objects referenced above."}),"\n",(0,l.jsxs)(t.h4,{id:"testsuite-object",children:[(0,l.jsx)(t.code,{children:"TestSuite"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"id"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The unique identifier of the test suite."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"name"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The name of the test suite."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"description"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A description of the test suite's purpose."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"steps"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.code,{children:"array"})," of ",(0,l.jsx)(t.code,{children:"APIStep"})]}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The ordered list of steps in this suite."})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"apistep-object",children:[(0,l.jsx)(t.code,{children:"APIStep"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"id"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The unique identifier of this test step."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"name"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The name of the step."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"description"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A description of the step's purpose."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"method"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:'The HTTP method (e.g., "GET", "POST").'})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"url"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The request URL, which may contain variable placeholders like ",(0,l.jsx)(t.code,{children:"{{var}}"}),"."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"body"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The request body."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"headers"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"object"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"}
1,children:"A key-value map of request headers. Values can contain placeholders."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"extract"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"object"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A key-value map defining variables to extract from the response."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"assert"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.code,{children:"array"})," of ",(0,l.jsx)(t.code,{children:"Assertion"})]}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The list of assertions to be checked against the response."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"resp"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"APIResponse"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The expected or recorded response for this step."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"deleteData"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"DeleteData"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Internal metadata related to deletion status."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"normalizeData"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"NormalizeTestRunData"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"Internal metadata related to normalization status."})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"apirequest-object",children:[(0,l.jsx)(t.code,{children:"APIRequest"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"method"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:'The HTTP method (e.g., "GET", "POST").'})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"url"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The final, rendered URL sent to the server."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"headers"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"object"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A key-value map of request headers."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"body"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The final, rendered request body."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"reqId"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A unique ID for this specific request execution."})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"apiresponse-object",children:[(0,l.jsx)(t.code,{children:"APIResponse"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"status"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"int"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The HTTP status code (e.g., 200, 404)."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"headers"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"object"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"}
1,children:"A key-value map of response headers."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"body"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The response body as a string."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"reqId"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The ID of the request that produced this response."})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"assertion-object",children:[(0,l.jsx)(t.code,{children:"Assertion"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"type"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:'The type of assertion (e.g., "STATUS_CODE", "JSON_CONTAINS").'})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"key"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The key to check (e.g., a header name or a JSON path)."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"expected"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"any"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The expected value (can be a number, string, or JSON object)."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"expected_string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A pre-stringified version of the expected value for convenience."})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"assertionfailure-object",children:[(0,l.jsx)(t.code,{children:"AssertionFailure"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"stepIndex"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"int"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The index of the ",(0,l.jsx)(t.code,{children:"APIStep"})," that failed."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"assertionIndex"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"int"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:["The index of the specific ",(0,l.jsx)(t.code,{children:"Assertion"})," that failed."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"type"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The type of the failed assertion."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"key"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The key of the failed assertion."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"expected"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The expected value."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"actual"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The actual value received from the response."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"error"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A general error message if the failure was not an assertion mismatch."})]})]})]}),"\n",(0,l.jsxs)(t.h4,{id:"suiteresult-object",children:[(0,l.jsx)(t.code,{children:"SuiteResult"})," Object"]}),"\n",(0,l.jsxs)(t.table,{children:[(0,l.jsx)(t.thead,{children:(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Field"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Type"}),(0,l.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,l.jsxs)(t.tbody,{children:[(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"stepName"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"string"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The name of the step that was executed."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"pass"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"boolean"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.code,{children:"true"})," if the step passed, ",(0,l.jsx)(t.code,{children:"false"})," otherwise."]})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"requestSent"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"APIRequest"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The request that was sent for this step."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"responseReceived"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"APIResponse"})}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"The response that was received for this step."})]}),(0,l.jsxs)(t.tr,{children:[(0,l.jsx)(t.td,{style:{textAlign:"left"},children:(0,l.jsx)(t.code,{children:"assertionFailures"})}),(0,l.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,l.jsx)(t.code,{children:"array"})," of ",(0,l.jsx)(t.code,{children:"AssertionFailure"})]}),(0,l.jsx)(t.td,{style:{textAlign:"left"},children:"A list of failures if the step did not pass."})]})]})]}),"\n",(0,l.jsx)(t.h3,{id:"5-use-cases--examples",children:"5. Use Cases & Examples"}),"\n",(0,l.jsx)(t.h4,{id:"example-1-denying-a-request-in-preexecute",children:"Example 1: Denying a Request in PreExecute"}),"\n",(0,l.jsxs)(t.p,{children:["To prevent any request to a ",(0,l.jsx)(t.code,{children:"/admin"})," endpoint from running:"]}),"\n",(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-go",children:'// Inside your webhookHandler\'s "PreExecute" case\nif strings.Contains(review.Request.RequestToSend.URL, "/admin") {\n    log.Println("\ud83d\udd25 DENYING request to admin endpoint.")\n    response := WebhookResponse{\n        Pass:   false,\n        Reason: "Policy: Cannot access /admin endpoints during this test.",\n    }\n    sendJSONResponse(w, http.StatusOK, response)\n    return\n}\n'})}),"\n",(0,l.jsx)(t.h4,{id:"example-2-forcing-a-failure-in-postexecute",children:"Example 2: Forcing a Failure in PostExecute"}),"\n",(0,l.jsxs)(t.p,{children:["To fail any step that passed but returned a response without a ",(0,l.jsx)(t.code,{children:"X-Trace-ID"})," header:"]}),"\n",(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-go",children:'// Inside your webhookHandler\'s "PostExecute" case\nif *review.Request.StepPassed { // Only check steps that initially passed\n    if _, ok := review.Request.ResponseReceived.Headers["X-Trace-Id"]; !ok {\n        log.Println("\ud83d\udd25 FORCING FAILURE due to missing X-Trace-Id header.")\n        response := WebhookResponse{\n            Pass:   false,\n            Reason: "Step failed custom validation: Missing X-Trace-Id header.",\n        }\n        sendJSONResponse(w, http.StatusOK, response)\n        return\n    }\n}\n'})}),"\n",(0,l.jsx)(t.h3,{id:"6-best-practices",children:"6. Best Practices"}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Be Stateless:"})," Design your webhook server to be stateless. Each request from Keploy contains all the context you need to make a decision."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Respond Quickly:"})," Keploy will wait for your webhook's response. A slow webhook will slow down your entire test run. Aim for response times under 500ms."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Log Everything:"})," Your webhook server should log every incoming request and the response it sends. This is invaluable for debugging."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.strong,{children:"Handle Errors Gracefully:"})," If your server is down or returns a non-200 status code, Keploy will treat it as a transport failure and ",(0,l.jsx)(t.strong,{children:"fail the test step"}),". Ensure your server is robust."]}),"\n"]}),"\n",(0,l.jsx)(t.h2,{id:"related",children:"Related"}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.a,{href:"/docs/running-keploy/api-testing-custom-assertions/",children:"Custom Assertions"})," \u2014 add validation logic within Keploy itself."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.a,{href:"/docs/running-keploy/api-testing-functions/",children:"Functions & Schema Assertions"})," \u2014 programmatic checks on responses."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.a,{href:"/docs/running-keploy/public-api/",children:"Public REST API"})," \u2014 trigger runs programmatically from external systems."]}),"\n",(0,l.jsxs)(t.li,{children:[(0,l.jsx)(t.a,{href:"/docs/running-keploy/api-testing-run-report/",children:"Test Run Reports"})," \u2014 see webhook pass/fail reasons in results."]}),"\n"]})]})}function x(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,l.jsx)(t,{...e,children:(0,l.jsx)(a,{...e})}):a(e)}}
1,12483(e,t,s){s.d(t,{A:()=>r});s(96540);var n=s(74848);const l={label:"Free",color:"#059669",bg:"rgba(16, 185, 129, 0.1)"},i={free:l,teams:{label:"Teams",color:"#0891b2",bg:"rgba(6, 182, 212, 0.1)"},scale:{label:"Scale",color:"#4f46e5",bg:"rgba(99, 102, 241, 0.1)"},enterprise:{label:"Enterprise",color:"#7c3aed",bg:"rgba(139, 92, 246, 0.1)"},"open source":l,oss:l,cloud:{label:"Cloud",color:"#2563eb",bg:"rgba(59, 130, 246, 0.1)"},"self-hosted":{label:"Self-Hosted",color:"#6b7280",bg:"rgba(107, 114, 128, 0.08)"},dedicated:{label:"Dedicated",color:"#6b7280",bg:"rgba(107, 114, 128, 0.08)"},local:{label:"Local",color:"#6b7280",bg:"rgba(107, 114, 128, 0.08)"}},r=({tiers:e,offerings:t})=>{const s=[...e?Array.isArray(e)?e:e.split(",").map(e=>e.trim()):[],...t?Array.isArray(t)?t:t.split(",").map(e=>e.trim()):[]];return 0===s.length?null:(0,n.jsxs)("div",{className:"product-tier-chips",children:[s.map((e,t)=>{const s=e.toLowerCase().trim(),l=i[s]||{label:e.trim(),color:"#6b7280",bg:"rgba(107, 114, 128, 0.08)"};return(0,n.jsx)("span",{className:"product-tier-chip",style:{color:l.color,background:l.bg},children:l.label},t)}),(0,n.jsx)("style",{children:'\n        .product-tier-chips {\n          display: inline-flex;\n          flex-wrap: wrap;\n          gap: 0.375rem;\n          margin-bottom: 0;\n        }\n        .product-tier-chip {\n          display: inline-flex;\n          align-items: center;\n          padding: 0.1875rem 0.5rem;\n          font-size: 0.6875rem;\n          font-weight: 600;\n          border-radius: 4px;\n          white-space: nowrap;\n          letter-spacing: 0.01em;\n        }\n        html[data-theme="dark"] .product-tier-chip {\n          background: rgba(255, 255, 255, 0.15) !important;\n        }\n      '})]})}},28453(e,t,s){s.d(t,{R:()=>r,x:()=>d});var n=s(96540);const l={},i=n.createContext(l);function r(e){const t=n.useContext(i);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:r(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]);
2//# sourceMappingURL=8e2fb8b4.a6d171de.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.