[{"data":1,"prerenderedAt":2230},["ShallowReactive",2],{"navigation":3,"page:\u002Fguides\u002Fside-effect-safety":1019,"surround:\u002Fguides\u002Fside-effect-safety":2221},[4,21,82,133,154,1010],[5,6,7,8],"Getting started","\u002Fgetting-started","i-lucide-rocket",[9,12,15,18],[10,6,11,11],"What Kaabist is",0,[13,14,11,11],"API keys and modes","keys-and-modes",[16,17,11,11],"Your first job","first-job",[19,20,11,11],"Understanding the envelope","envelope",[22,23,24,25],"Concepts","\u002Fconcepts","i-lucide-book-open",[26,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79],[27,23,11,11],"Overview",[29,30,11,11],"Programs and versions","programs-and-versions",[32,33,11,11],"Tiers and escalation","tiers-and-escalation",[35,36,11,11],"The http tier","http-tier",[38,39,11,11],"The browser tier","browser-tier",[41,42,11,11],"Sessions","sessions",[44,45,11,11],"Human in the loop","human-in-the-loop",[47,48,11,11],"How healing works","self-healing",[50,51,11,11],"Obstacles and captchas","obstacles",[53,54,11,11],"Validation and warnings","validation-and-warnings",[56,57,11,11],"Credits and billing","credits-and-billing",[59,60,11,11],"Limits","limits",[62,63,11,11],"Locators","locators",[65,66,11,11],"Snapshots","snapshots",[68,69,11,11],"Egress and proxies","egress-and-proxies",[71,72,11,11],"Queueing and fairness","queueing",[74,75,11,11],"Accounts, organisations and roles","accounts-and-roles",[77,78,11,11],"Data retention","data-retention",[80,81,11,11],"Documents and PDFs","documents-and-pdfs",[83,84,85,86],"Guides","\u002Fguides","i-lucide-map",[87,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130],[27,84,11,11],[89,90,11,11],"Authenticated flows","authenticated-flows",[92,93,11,11],"Hosted resolve pages","hosted-resolve",[95,96,11,11],"Lists and pagination","lists-and-pagination",[98,99,11,11],"JSON and network locators","json-and-network-locators",[101,102,11,11],"Schedules and change detection","schedules-and-change-detection",[104,105,11,11],"Webhooks","webhooks",[107,108,11,11],"Bring your own providers","byo-providers",[110,111,11,11],"Testing: replay, dry-run and test mode","testing",[113,114,11,11],"Side-effect safety","side-effect-safety",[116,117,11,11],"Security & data handling","security-and-data",[119,120,11,11],"Migrating from other tools","migrating",[122,123,11,11],"Drift detection and canaries","drift-and-canaries",[125,126,11,11],"SDKs","sdks",[128,129,11,11],"The kaab CLI","cli",[131,132,11,11],"Coding agents (MCP)","mcp",[134,135,136,137],"Panel","\u002Fpanel","i-lucide-layout-dashboard",[138,139,142,145,148,151],[27,135,11,11],[140,141,11,11],"The program builder","builder",[143,144,11,11],"Picking and recording","picking-and-recording",[146,147,11,11],"Taking over a job","takeover",[149,150,11,11],"Getting help","support",[152,153,11,11],"Referrals","referrals",[155,156,157,158],"Reference","\u002Freference","i-lucide-library",[159,160,520,834,837,840,1006,1007],[27,156,11,11],[161,162,11,163],"API","api",[164,166,169,212,222,274,297,316,347,376,389,396,403,410,426,447,454],[27,165,11,11],"\u002Freference\u002Fapi",[167,168,11,11],"Interactive reference","explorer",[170,171,11,172],"Jobs","jobs",[173,176,179,182,185,188,191,194,197,200,203,206,209],[174,175,11,11],"Create job","create-job",[177,178,11,11],"List jobs","list-jobs",[180,181,11,11],"Create job batch","create-job-batch",[183,184,11,11],"Estimate job","estimate-job",[186,187,11,11],"Get job","get-job",[189,190,11,11],"List job steps","list-job-steps",[192,193,11,11],"Get job snapshot","get-job-snapshot",[195,196,11,11],"Get job screenshot","get-job-screenshot",[198,199,11,11],"Get job artifact","get-job-artifact",[201,202,11,11],"Submit job input","submit-job-input",[204,205,11,11],"Resume job","resume-job",[207,208,11,11],"Takeover job","takeover-job",[210,211,11,11],"Cancel job","cancel-job",[213,214,11,215],"Batches","batches",[216,219],[217,218,11,11],"Get batch","get-batch",[220,221,11,11],"List batch jobs","list-batch-jobs",[223,224,11,225],"Programs","programs",[226,229,232,235,238,241,244,247,250,253,256,259,262,265,268,271],[227,228,11,11],"Create program","create-program",[230,231,11,11],"List programs","list-programs",[233,234,11,11],"Lint program","lint-program",[236,237,11,11],"Get program","get-program",[239,240,11,11],"Update program","update-program",[242,243,11,11],"Delete program","delete-program",[245,246,11,11],"List program versions","list-program-versions",[248,249,11,11],"Create program version","create-program-version",[251,252,11,11],"Update program version","update-program-version",[254,255,11,11],"Delete program version","delete-program-version",[257,258,11,11],"Get program version","get-program-version",[260,261,11,11],"Publish program version","publish-program-version",[263,264,11,11],"Diff program version","diff-program-version",[266,267,11,11],"Replay program version","replay-program-version",[269,270,11,11],"Set program alias","set-program-alias",[272,273,11,11],"Delete program alias","delete-program-alias",[41,42,11,275],[276,279,282,285,288,291,294],[277,278,11,11],"Create session","create-session",[280,281,11,11],"List sessions","list-sessions",[283,284,11,11],"Get session","get-session",[286,287,11,11],"Update session","update-session",[289,290,11,11],"Delete session","delete-session",[292,293,11,11],"Verify session","verify-session",[295,296,11,11],"Refresh session","refresh-session",[298,299,11,300],"Proposals","proposals",[301,304,307,310,313],[302,303,11,11],"List proposals","list-proposals",[305,306,11,11],"Get proposal","get-proposal",[308,309,11,11],"Approve proposal","approve-proposal",[311,312,11,11],"Reject proposal","reject-proposal",[314,315,11,11],"Edit proposal","edit-proposal",[317,318,11,319],"Schedules","schedules",[320,323,326,329,332,335,338,341,344],[321,322,11,11],"Create schedule","create-schedule",[324,325,11,11],"List schedules","list-schedules",[327,328,11,11],"Get schedule","get-schedule",[330,331,11,11],"Update schedule","update-schedule",[333,334,11,11],"Delete schedule","delete-schedule",[336,337,11,11],"Pause schedule","pause-schedule",[339,340,11,11],"Resume schedule","resume-schedule",[342,343,11,11],"List schedule runs","list-schedule-runs",[345,346,11,11],"Get schedule run diff","get-schedule-run-diff",[104,105,11,348],[349,352,355,358,361,364,367,370,373],[350,351,11,11],"Create webhook","create-webhook",[353,354,11,11],"List webhooks","list-webhooks",[356,357,11,11],"Get webhook","get-webhook",[359,360,11,11],"Update webhook","update-webhook",[362,363,11,11],"Delete webhook","delete-webhook",[365,366,11,11],"Rotate webhook secret","rotate-webhook-secret",[368,369,11,11],"List webhook deliveries","list-webhook-deliveries",[371,372,11,11],"Resend webhook delivery","resend-webhook-delivery",[374,375,11,11],"Test webhook","test-webhook",[377,378,11,379],"Organisation","org",[380,383,386],[381,382,11,11],"Rotate org webhook secret","rotate-org-webhook-secret",[384,385,11,11],"Get org","get-org",[387,388,11,11],"Request data deletion","request-data-deletion",[390,391,11,392],"Credits","credits",[393],[394,395,11,11],"Get credits","get-credits",[397,398,11,399],"Ledger","ledger",[400],[401,402,11,11],"List ledger entries","list-ledger-entries",[404,405,11,406],"Usage","usage",[407],[408,409,11,11],"Get usage","get-usage",[411,412,11,413],"API keys","api-keys",[414,417,420,423],[415,416,11,11],"List API keys","list-api-keys",[418,419,11,11],"Create API key","create-api-key",[421,422,11,11],"Rotate API key","rotate-api-key",[424,425,11,11],"Revoke API key","revoke-api-key",[427,108,11,428],"BYO providers",[429,432,435,438,441,444],[430,431,11,11],"List BYO providers","list-byo-providers",[433,434,11,11],"Create BYO provider","create-byo-provider",[436,437,11,11],"Get BYO provider","get-byo-provider",[439,440,11,11],"Update BYO provider","update-byo-provider",[442,443,11,11],"Delete BYO provider","delete-byo-provider",[445,446,11,11],"Test BYO provider","test-byo-provider",[448,449,11,450],"Sites","sites",[451],[452,453,11,11],"Get site profile","get-site-profile",[455,456,11,457],"Objects","schemas",[458,460,463,466,469,470,473,476,479,482,485,487,490,493,496,499,502,505,508,511,514,517],[27,459,11,11],"\u002Freference\u002Fapi\u002Fschemas",[461,462,11,11],"ApiKey","api-key",[464,465,11,11],"Batch","batch",[467,468,11,11],"ByoProvider","byo-provider",[390,391,11,11],[471,472,11,11],"ErrorResponse","error-response",[474,475,11,11],"ExtractSchema","extract-schema",[477,478,11,11],"Job","job",[480,481,11,11],"LedgerEntry","ledger-entry",[483,484,11,11],"LintResult","lint-result",[486,378,11,11],"Org",[488,489,11,11],"Program","program",[491,492,11,11],"ProgramDefinition","program-definition",[494,495,11,11],"ProgramVersion","program-version",[497,498,11,11],"Proposal","proposal",[500,501,11,11],"Schedule","schedule",[503,504,11,11],"Session","session",[506,507,11,11],"SiteProfile","site-profile",[509,510,11,11],"StepRecord","step-record",[512,513,11,11],"Webhook","webhook",[515,516,11,11],"WebhookDelivery","webhook-delivery",[518,519,11,11],"WebhookEvent","webhook-event",[521,522,11,523],"DSL","dsl",[524,526,529,532,535,538,603,637,640,751,754,756],[27,525,11,11],"\u002Freference\u002Fdsl",[527,528,11,11],"Inputs","inputs",[530,531,11,11],"Options","options",[533,534,11,11],"Policies","policies",[536,537,11,11],"Steps","steps",[539,540,11,541],"Actions","actions",[542,544,546,548,550,552,554,556,558,560,562,565,568,570,573,575,577,579,582,585,587,589,591,594,596,598,600],[27,543,11,11],"\u002Freference\u002Fdsl\u002Factions",[545,545,11,11],"fill",[547,547,11,11],"click",[549,549,11,11],"press",[551,551,11,11],"hover",[553,553,11,11],"select",[555,555,11,11],"check",[557,557,11,11],"uncheck",[559,559,11,11],"upload",[561,561,11,11],"scroll",[563,564,11,11],"wait_for","wait-for",[566,567,11,11],"set_session","set-session",[569,569,11,11],"extract",[571,572,11,11],"capture_response","capture-response",[574,574,11,11],"evaluate",[576,576,11,11],"paginate",[578,578,11,11],"download",[580,581,11,11],"read_pdf","read-pdf",[583,584,11,11],"set_vars","set-vars",[586,586,11,11],"sleep",[588,588,11,11],"reload",[590,590,11,11],"goto",[592,593,11,11],"await_input","await-input",[595,595,11,11],"checkpoint",[597,597,11,11],"screenshot",[599,599,11,11],"when",[601,602,11,11],"loop_until","loop-until",[604,605,11,606],"Conditions","conditions",[607,609,611,613,615,617,619,621,623,625,627,629,631,633,635],[27,608,11,11],"\u002Freference\u002Fdsl\u002Fconditions",[610,610,11,11],"url",[612,612,11,11],"title",[614,614,11,11],"visible",[616,616,11,11],"hidden",[618,618,11,11],"exists",[620,620,11,11],"absent",[622,622,11,11],"text",[624,624,11,11],"count",[626,626,11,11],"network",[628,628,11,11],"var",[630,630,11,11],"landmark",[632,632,11,11],"all",[634,634,11,11],"any",[636,636,11,11],"not",[638,639,11,11],"Targets","targets",[641,642,11,643],"Fields","fields",[644,646,649,651,654,656,659,661,663,666,668,671,672,674,677,679,681,683,685,687,690,693,695,698,701,703,704,707,709,712,714,716,718,720,722,724,726,728,731,733,734,736,738,740,743,745,747,749],[27,645,11,11],"\u002Freference\u002Fdsl\u002Ffields",[647,648,11,11],"allow_suffix","allow-suffix",[650,650,11,11],"attr",[652,653,11,11],"base_url","base-url",[655,655,11,11],"candidates",[657,658,11,11],"case_insensitive","case-insensitive",[660,660,11,11],"country",[662,662,11,11],"currency",[664,665,11,11],"date_format","date-format",[667,667,11,11],"decimal",[669,670,11,11],"false_values","false-values",[642,642,11,11],[673,673,11,11],"flags",[675,676,11,11],"follow_redirects","follow-redirects",[678,678,11,11],"frame",[680,680,11,11],"json",[682,682,11,11],"locale",[684,684,11,11],"many",[686,686,11,11],"max",[688,689,11,11],"max_items","max-items",[691,692,11,11],"max_length","max-length",[694,694,11,11],"min",[696,697,11,11],"min_items","min-items",[699,700,11,11],"min_length","min-length",[702,702,11,11],"name",[626,626,11,11],[705,706,11,11],"null_markers","null-markers",[708,708,11,11],"nullable",[710,711,11,11],"on_invalid","on-invalid",[713,713,11,11],"pattern",[715,715,11,11],"presence",[717,717,11,11],"regex",[719,719,11,11],"required",[721,721,11,11],"role",[723,723,11,11],"sample",[725,725,11,11],"selector",[727,727,11,11],"source",[729,730,11,11],"strip_fragment","strip-fragment",[732,732,11,11],"testid",[622,622,11,11],[735,735,11,11],"thousands",[737,737,11,11],"timezone",[739,739,11,11],"transforms",[741,742,11,11],"true_values","true-values",[744,744,11,11],"type",[746,746,11,11],"unique",[748,748,11,11],"values",[750,750,11,11],"xpath",[752,753,11,11],"Assertions","assertions",[755,739,11,11],"Transforms",[757,758,11,759],"Lint codes","lint",[760,762,765,768,771,774,777,780,783,786,789,792,795,798,801,804,807,810,813,816,819,822,825,828,831],[27,761,11,11],"\u002Freference\u002Fdsl\u002Flint",[763,764,11,11],"E001","e001",[766,767,11,11],"E002","e002",[769,770,11,11],"E003","e003",[772,773,11,11],"E004","e004",[775,776,11,11],"E005","e005",[778,779,11,11],"E006","e006",[781,782,11,11],"E007","e007",[784,785,11,11],"E008","e008",[787,788,11,11],"E009","e009",[790,791,11,11],"E010","e010",[793,794,11,11],"E011","e011",[796,797,11,11],"E012","e012",[799,800,11,11],"E013","e013",[802,803,11,11],"E014","e014",[805,806,11,11],"W001","w001",[808,809,11,11],"W002","w002",[811,812,11,11],"W003","w003",[814,815,11,11],"W004","w004",[817,818,11,11],"W005","w005",[820,821,11,11],"W006","w006",[823,824,11,11],"W007","w007",[826,827,11,11],"W008","w008",[829,830,11,11],"W009","w009",[832,833,11,11],"W010","w010",[835,836,11,11],"Codes","codes",[838,839,11,11],"Events","events",[841,129,11,842],"CLI",[843,845,847,850,853,856,859,862,865,868,871,874,877,880,883,886,889,892,895,898,901,904,907,910,913,916,919,922,925,928,931,934,937,940,943,946,949,952,955,958,961,964,967,970,973,976,979,982,985,988,991,994,997,1000,1003],[27,844,11,11],"\u002Freference\u002Fcli",[846,846,11,11],"kaab",[848,849,11,11],"kaab auth","kaab-auth",[851,852,11,11],"kaab auth login","kaab-auth-login",[854,855,11,11],"kaab auth logout","kaab-auth-logout",[857,858,11,11],"kaab auth status","kaab-auth-status",[860,861,11,11],"kaab completion","kaab-completion",[863,864,11,11],"kaab completion bash","kaab-completion-bash",[866,867,11,11],"kaab completion fish","kaab-completion-fish",[869,870,11,11],"kaab completion powershell","kaab-completion-powershell",[872,873,11,11],"kaab completion zsh","kaab-completion-zsh",[875,876,11,11],"kaab credits","kaab-credits",[878,879,11,11],"kaab jobs","kaab-jobs",[881,882,11,11],"kaab jobs cancel","kaab-jobs-cancel",[884,885,11,11],"kaab jobs get","kaab-jobs-get",[887,888,11,11],"kaab jobs input","kaab-jobs-input",[890,891,11,11],"kaab jobs list","kaab-jobs-list",[893,894,11,11],"kaab jobs resume","kaab-jobs-resume",[896,897,11,11],"kaab jobs run","kaab-jobs-run",[899,900,11,11],"kaab jobs snapshot","kaab-jobs-snapshot",[902,903,11,11],"kaab jobs steps","kaab-jobs-steps",[905,906,11,11],"kaab jobs takeover","kaab-jobs-takeover",[908,909,11,11],"kaab open","kaab-open",[911,912,11,11],"kaab open job","kaab-open-job",[914,915,11,11],"kaab programs","kaab-programs",[917,918,11,11],"kaab programs alias","kaab-programs-alias",[920,921,11,11],"kaab programs alias set","kaab-programs-alias-set",[923,924,11,11],"kaab programs diff","kaab-programs-diff",[926,927,11,11],"kaab programs lint","kaab-programs-lint",[929,930,11,11],"kaab programs list","kaab-programs-list",[932,933,11,11],"kaab programs pull","kaab-programs-pull",[935,936,11,11],"kaab programs push","kaab-programs-push",[938,939,11,11],"kaab proposals","kaab-proposals",[941,942,11,11],"kaab proposals approve","kaab-proposals-approve",[944,945,11,11],"kaab proposals list","kaab-proposals-list",[947,948,11,11],"kaab proposals reject","kaab-proposals-reject",[950,951,11,11],"kaab proposals show","kaab-proposals-show",[953,954,11,11],"kaab schedules","kaab-schedules",[956,957,11,11],"kaab schedules create","kaab-schedules-create",[959,960,11,11],"kaab schedules list","kaab-schedules-list",[962,963,11,11],"kaab schedules pause","kaab-schedules-pause",[965,966,11,11],"kaab schedules resume","kaab-schedules-resume",[968,969,11,11],"kaab schedules runs","kaab-schedules-runs",[971,972,11,11],"kaab sessions","kaab-sessions",[974,975,11,11],"kaab sessions create","kaab-sessions-create",[977,978,11,11],"kaab sessions delete","kaab-sessions-delete",[980,981,11,11],"kaab sessions list","kaab-sessions-list",[983,984,11,11],"kaab sessions verify","kaab-sessions-verify",[986,987,11,11],"kaab usage","kaab-usage",[989,990,11,11],"kaab version","kaab-version",[992,993,11,11],"kaab webhooks","kaab-webhooks",[995,996,11,11],"kaab webhooks create","kaab-webhooks-create",[998,999,11,11],"kaab webhooks deliveries","kaab-webhooks-deliveries",[1001,1002,11,11],"kaab webhooks list","kaab-webhooks-list",[1004,1005,11,11],"kaab webhooks test","kaab-webhooks-test",[125,126,11,11],[1008,1009,11,11],"Plans and pricing","plans",[1011,1012,1013,1014],"Changelog","\u002Fchangelog","i-lucide-history",[1015,1016],[27,1012,11,11],[1017,1018,11,11],"Deprecations","deprecations",{"id":1020,"title":113,"body":1021,"breaking":2212,"date":2213,"description":2214,"extension":2215,"generated":2212,"meta":2216,"navigation":1854,"path":2217,"seo":2218,"stem":2219,"version":2213,"__hash__":2220},"docs\u002F3.guides\u002F09.side-effect-safety.md",{"type":1022,"value":1023,"toc":2197},"minimark",[1024,1028,1033,1045,1054,1061,1066,1085,1096,1107,1111,1130,1134,1144,1148,1155,1202,1205,1217,1221,1239,1243,1246,1261,1276,1290,1294,1305,1755,1768,1771,2082,2092,2096,2143,2146,2193],[1025,1026,1027],"p",{},"A side effect is a step the world remembers: an order placed, a message sent, a form submitted.\nKaabist cannot undo those, so it guards each one with a fence, refuses to repeat it, and parks the\njob for a person whenever it cannot tell whether the step happened.",[1029,1030,1032],"h2",{"id":1031},"when-to-use-it","When to use it",[1025,1034,1035,1036,1040,1041,1044],{},"Mark a step ",[1037,1038,1039],"code",{},"side_effect: true"," whenever running it twice would do harm: a submit that creates\nsomething, a button that sends, pays, books or deletes. Pair it with an ",[1037,1042,1043],{},"Idempotency-Key"," on the\nrequest that creates the job whenever your own code may retry that request.",[1025,1046,1047,1048,1050,1051,1053],{},"A program that only reads pages (",[1037,1049,590],{}," and ",[1037,1052,569],{},") needs none of this. Do not mark a step as a\nside effect \"to be safe\": a fenced step cannot be retried, cannot be optional, and turns an\ninterruption into a parked job that a person has to resolve.",[1029,1055,1057,1058,1060],{"id":1056},"what-side_effect-true-changes","What ",[1037,1059,1039],{}," changes",[1062,1063,1065],"h3",{"id":1064},"the-fence","The fence",[1025,1067,1068,1069,1073,1074,1077,1078,1081,1082,1084],{},"Before a side-effect step acts, Kaabist records that the step is ",[1070,1071,1072],"em",{},"about to execute",". After the\nstep's ",[1037,1075,1076],{},"expect"," holds, it records that the step ",[1070,1079,1080],{},"executed",". The next ",[1037,1083,595],{}," closes the fence.",[1025,1086,1087,1088,1091,1092,1095],{},"If the run is interrupted between those two records (the worker restarts, the browser crashes, the\nconnection drops while the site is still answering), nobody can know whether the action went\nthrough. Kaabist never guesses: instead of running the step again, it parks the job in\n",[1037,1089,1090],{},"needs_attention"," with the reason ",[1037,1093,1094],{},"side_effect_ambiguous",", and a person decides.",[1025,1097,1098,1099,1102,1103,1106],{},"While a fence is open, the job cannot be canceled: ",[1037,1100,1101],{},"POST \u002Fv1\u002Fjobs\u002F{id}\u002Fcancel"," answers\n",[1037,1104,1105],{},"409 fence_open",".",[1062,1108,1110],{"id":1109},"no-retries-no-optional","No retries, no optional",[1025,1112,1113,1114,1117,1118,1121,1122,1126,1127,1129],{},"A side-effect step may not carry ",[1037,1115,1116],{},"retry"," or ",[1037,1119,1120],{},"optional: true",". Both would let the engine run the\naction again, or carry on as if it had not happened, so lint refuses them with\n",[1123,1124,793],"a",{"href":1125},"\u002Freference\u002Fdsl\u002Flint\u002Fe011"," and the program cannot be published. If the submit is flaky,\nmake the step's ",[1037,1128,1076],{}," precise and let the job park instead.",[1062,1131,1133],{"id":1132},"a-checkpoint-after-every-side-effect","A checkpoint after every side effect",[1025,1135,1136,1137,1139,1140,1143],{},"End every side effect with a ",[1037,1138,595],{}," before the next one. Without it, lint warns with\n",[1123,1141,814],{"href":1142},"\u002Freference\u002Fdsl\u002Flint\u002Fw004",": the job has no safe place to restart from after the action, and a\nlater problem could only be resolved by rewinding past it, which Kaabist refuses.",[1062,1145,1147],{"id":1146},"resuming-a-parked-job","Resuming a parked job",[1025,1149,1150,1151,1154],{},"A parked job restarts from a checkpoint (see ",[1123,1152,45],{"href":1153},"\u002Fconcepts\u002Fhuman-in-the-loop","), and\nthe fences decide where it may restart:",[1156,1157,1158,1170,1179,1194],"ul",{},[1159,1160,1161,1167,1168,1106],"li",{},[1162,1163,1164],"strong",{},[1037,1165,1166],{},"retry_from"," may name only a checkpoint after the last side effect that executed. A checkpoint\nat or before it would place the order again, so the request is refused with ",[1037,1169,1105],{},[1159,1171,1172,1175,1176,1178],{},[1162,1173,1174],{},"An open fence"," (the step was dispatched but never confirmed) blocks every restart at or before\nthat step: a resume that would start there parks the job ",[1037,1177,1094],{}," again instead of\ntouching the site.",[1159,1180,1181,1186,1187,1189,1190,1193],{},[1162,1182,1183],{},[1037,1184,1185],{},"skip_step"," on a ",[1037,1188,1094],{}," park restarts ",[1070,1191,1192],{},"after"," the fenced step: you are telling\nKaabist that the action went through.",[1159,1195,1196,1201],{},[1162,1197,1198],{},[1037,1199,1200],{},"abort"," cancels the job.",[1025,1203,1204],{},"A run that replays from an earlier checkpoint, for example because the checkpoint's page no longer\nopens, never replays across an executed side effect. The data extracted before the park stays in\nthe result.",[1025,1206,1207,1208,1210,1211,1213,1214,1216],{},"To resolve ",[1037,1209,1094],{},", check the site first. If the action went through, ",[1037,1212,1185],{},"\ntells Kaabist so and the job carries on after the fenced step. If it did not, ",[1037,1215,1200],{}," the job and\ncreate a new one, with a new idempotency key: within 24 hours the old key returns the aborted job.",[1062,1218,1220],{"id":1219},"dry-runs","Dry runs",[1025,1222,1223,1226,1227,1230,1231,1234,1235,1238],{},[1037,1224,1225],{},"dry_run: true"," on job creation runs the program until the first side-effect step and stops there.\nThe job ends ",[1037,1228,1229],{},"succeeded"," with ",[1037,1232,1233],{},"meta.dry_run = true"," and nothing changed on the site. The program builder's\n",[1162,1236,1237],{},"Dry run"," does the same.",[1029,1240,1242],{"id":1241},"idempotency-keys","Idempotency keys",[1025,1244,1245],{},"A fence protects the steps inside a job. An idempotency key protects the request that creates the\njob: a client that times out and tries again must not start a second job that places a second\norder.",[1025,1247,1248,1249,1252,1253,1256,1257,1260],{},"Send ",[1037,1250,1251],{},"Idempotency-Key: \u003Cstring of at most 255 characters>"," on ",[1037,1254,1255],{},"POST \u002Fv1\u002Fjobs"," or\n",[1037,1258,1259],{},"POST \u002Fv1\u002Fjobs\u002Fbatch",". For 24 hours, per organisation:",[1156,1262,1263,1270],{},[1159,1264,1265,1266,1269],{},"the same key with the same body returns the original response, marked\n",[1037,1267,1268],{},"Idempotent-Replayed: true",", and queues nothing;",[1159,1271,1272,1273,1106],{},"the same key with a different body is refused with ",[1037,1274,1275],{},"409 idempotency_conflict",[1025,1277,1278,1279,1050,1282,1285,1286,1289],{},"Use one key per thing you mean to do (one order, one message) and store it with that thing on your\nside, so a retry after a crash or a deploy sends the same key. The SDKs send a fresh key on every\n",[1037,1280,1281],{},"jobs.create",[1037,1283,1284],{},"jobs.batch"," when you give none, which makes their own automatic retries safe;\npass your own key to make ",[1070,1287,1288],{},"your"," retries safe too.",[1029,1291,1293],{"id":1292},"worked-example","Worked example",[1025,1295,1296,1297,1300,1301,1304],{},"Take an order form at ",[1037,1298,1299],{},"https:\u002F\u002Fcheckout.example.com"," that places orders through a ",[1037,1302,1303],{},"POST \u002Forders","\nthat is not idempotent: every submission is a new order. The program fills the order form, fences the submit, checkpoints\nright after it, and reads the confirmation page:",[1306,1307,1308],"code-group",{},[1309,1310,1316],"pre",{"className":1311,"code":1312,"filename":1313,"language":1314,"meta":1315,"style":1315},"language-ts shiki shiki-themes kaab-code kaab-code kaab-code","const definition = {\n  kaab: \"1\",\n  name,\n  inputs: { sku: \"string\", qty: { type: \"number\", default: 1, min: 1, max: 40 } },\n  options: { max_tier: \"browser\" },\n  steps: [\n    { goto: `${site}\u002Forders\u002Fnew`, expect: { visible: \"#order-form\" } },\n    { fill: \"input[name=sku]\", value: \"{{inputs.sku}}\" },\n    { fill: \"input[name=qty]\", value: \"{{inputs.qty}}\" },\n    {\n      \u002F\u002F Never retried or replayed blindly: if the run is cut here, the job parks instead.\n      click: \"#order-form button[type=submit]\",\n      side_effect: true,\n      expect: { url: \"**\u002Forders\u002F*\" },\n    },\n    \u002F\u002F Anything after this resumes from here, not from the start: the order is not placed again.\n    { checkpoint: \"order-placed\" },\n    {\n      extract: { order: \"h1\", sku: \"#order-sku\", qty: { selector: \"#order-qty\", type: \"integer\" } },\n    },\n  ],\n};\nawait kaab.programs.create({ name, definition, publish: true });\n","TypeScript","ts","",[1037,1317,1318,1338,1355,1363,1429,1450,1461,1503,1528,1551,1557,1564,1577,1590,1610,1618,1624,1639,1644,1698,1705,1713,1719],{"__ignoreMap":1315},[1319,1320,1323,1327,1331,1334],"span",{"class":1321,"line":1322},"line",1,[1319,1324,1326],{"class":1325},"sqn18","const",[1319,1328,1330],{"class":1329},"sHJIl"," definition",[1319,1332,1333],{"class":1325}," =",[1319,1335,1337],{"class":1336},"sTzsn"," {\n",[1319,1339,1341,1344,1347,1351],{"class":1321,"line":1340},2,[1319,1342,1343],{"class":1336},"  kaab",[1319,1345,1346],{"class":1325},":",[1319,1348,1350],{"class":1349},"suOy4"," \"1\"",[1319,1352,1354],{"class":1353},"sQm2-",",\n",[1319,1356,1358,1361],{"class":1321,"line":1357},3,[1319,1359,1360],{"class":1336},"  name",[1319,1362,1354],{"class":1353},[1319,1364,1366,1369,1371,1374,1376,1379,1382,1385,1387,1390,1392,1395,1397,1400,1402,1405,1407,1410,1412,1414,1416,1419,1421,1424,1427],{"class":1321,"line":1365},4,[1319,1367,1368],{"class":1336},"  inputs",[1319,1370,1346],{"class":1325},[1319,1372,1373],{"class":1336}," { sku",[1319,1375,1346],{"class":1325},[1319,1377,1378],{"class":1349}," \"string\"",[1319,1380,1381],{"class":1353},",",[1319,1383,1384],{"class":1336}," qty",[1319,1386,1346],{"class":1325},[1319,1388,1389],{"class":1336}," { type",[1319,1391,1346],{"class":1325},[1319,1393,1394],{"class":1349}," \"number\"",[1319,1396,1381],{"class":1353},[1319,1398,1399],{"class":1336}," default",[1319,1401,1346],{"class":1325},[1319,1403,1404],{"class":1329}," 1",[1319,1406,1381],{"class":1353},[1319,1408,1409],{"class":1336}," min",[1319,1411,1346],{"class":1325},[1319,1413,1404],{"class":1329},[1319,1415,1381],{"class":1353},[1319,1417,1418],{"class":1336}," max",[1319,1420,1346],{"class":1325},[1319,1422,1423],{"class":1329}," 40",[1319,1425,1426],{"class":1336}," } }",[1319,1428,1354],{"class":1353},[1319,1430,1432,1435,1437,1440,1442,1445,1448],{"class":1321,"line":1431},5,[1319,1433,1434],{"class":1336},"  options",[1319,1436,1346],{"class":1325},[1319,1438,1439],{"class":1336}," { max_tier",[1319,1441,1346],{"class":1325},[1319,1443,1444],{"class":1349}," \"browser\"",[1319,1446,1447],{"class":1336}," }",[1319,1449,1354],{"class":1353},[1319,1451,1453,1456,1458],{"class":1321,"line":1452},6,[1319,1454,1455],{"class":1336},"  steps",[1319,1457,1346],{"class":1325},[1319,1459,1460],{"class":1336}," [\n",[1319,1462,1464,1467,1469,1472,1475,1478,1481,1484,1486,1489,1491,1494,1496,1499,1501],{"class":1321,"line":1463},7,[1319,1465,1466],{"class":1336},"    { goto",[1319,1468,1346],{"class":1325},[1319,1470,1471],{"class":1349}," `",[1319,1473,1474],{"class":1325},"${",[1319,1476,1477],{"class":1336},"site",[1319,1479,1480],{"class":1325},"}",[1319,1482,1483],{"class":1349},"\u002Forders\u002Fnew`",[1319,1485,1381],{"class":1353},[1319,1487,1488],{"class":1336}," expect",[1319,1490,1346],{"class":1325},[1319,1492,1493],{"class":1336}," { visible",[1319,1495,1346],{"class":1325},[1319,1497,1498],{"class":1349}," \"#order-form\"",[1319,1500,1426],{"class":1336},[1319,1502,1354],{"class":1353},[1319,1504,1506,1509,1511,1514,1516,1519,1521,1524,1526],{"class":1321,"line":1505},8,[1319,1507,1508],{"class":1336},"    { fill",[1319,1510,1346],{"class":1325},[1319,1512,1513],{"class":1349}," \"input[name=sku]\"",[1319,1515,1381],{"class":1353},[1319,1517,1518],{"class":1336}," value",[1319,1520,1346],{"class":1325},[1319,1522,1523],{"class":1349}," \"{{inputs.sku}}\"",[1319,1525,1447],{"class":1336},[1319,1527,1354],{"class":1353},[1319,1529,1531,1533,1535,1538,1540,1542,1544,1547,1549],{"class":1321,"line":1530},9,[1319,1532,1508],{"class":1336},[1319,1534,1346],{"class":1325},[1319,1536,1537],{"class":1349}," \"input[name=qty]\"",[1319,1539,1381],{"class":1353},[1319,1541,1518],{"class":1336},[1319,1543,1346],{"class":1325},[1319,1545,1546],{"class":1349}," \"{{inputs.qty}}\"",[1319,1548,1447],{"class":1336},[1319,1550,1354],{"class":1353},[1319,1552,1554],{"class":1321,"line":1553},10,[1319,1555,1556],{"class":1336},"    {\n",[1319,1558,1560],{"class":1321,"line":1559},11,[1319,1561,1563],{"class":1562},"sKog0","      \u002F\u002F Never retried or replayed blindly: if the run is cut here, the job parks instead.\n",[1319,1565,1567,1570,1572,1575],{"class":1321,"line":1566},12,[1319,1568,1569],{"class":1336},"      click",[1319,1571,1346],{"class":1325},[1319,1573,1574],{"class":1349}," \"#order-form button[type=submit]\"",[1319,1576,1354],{"class":1353},[1319,1578,1580,1583,1585,1588],{"class":1321,"line":1579},13,[1319,1581,1582],{"class":1336},"      side_effect",[1319,1584,1346],{"class":1325},[1319,1586,1587],{"class":1329}," true",[1319,1589,1354],{"class":1353},[1319,1591,1593,1596,1598,1601,1603,1606,1608],{"class":1321,"line":1592},14,[1319,1594,1595],{"class":1336},"      expect",[1319,1597,1346],{"class":1325},[1319,1599,1600],{"class":1336}," { url",[1319,1602,1346],{"class":1325},[1319,1604,1605],{"class":1349}," \"**\u002Forders\u002F*\"",[1319,1607,1447],{"class":1336},[1319,1609,1354],{"class":1353},[1319,1611,1613,1616],{"class":1321,"line":1612},15,[1319,1614,1615],{"class":1336},"    }",[1319,1617,1354],{"class":1353},[1319,1619,1621],{"class":1321,"line":1620},16,[1319,1622,1623],{"class":1562},"    \u002F\u002F Anything after this resumes from here, not from the start: the order is not placed again.\n",[1319,1625,1627,1630,1632,1635,1637],{"class":1321,"line":1626},17,[1319,1628,1629],{"class":1336},"    { checkpoint",[1319,1631,1346],{"class":1325},[1319,1633,1634],{"class":1349}," \"order-placed\"",[1319,1636,1447],{"class":1336},[1319,1638,1354],{"class":1353},[1319,1640,1642],{"class":1321,"line":1641},18,[1319,1643,1556],{"class":1336},[1319,1645,1647,1650,1652,1655,1657,1660,1662,1665,1667,1670,1672,1674,1676,1679,1681,1684,1686,1689,1691,1694,1696],{"class":1321,"line":1646},19,[1319,1648,1649],{"class":1336},"      extract",[1319,1651,1346],{"class":1325},[1319,1653,1654],{"class":1336}," { order",[1319,1656,1346],{"class":1325},[1319,1658,1659],{"class":1349}," \"h1\"",[1319,1661,1381],{"class":1353},[1319,1663,1664],{"class":1336}," sku",[1319,1666,1346],{"class":1325},[1319,1668,1669],{"class":1349}," \"#order-sku\"",[1319,1671,1381],{"class":1353},[1319,1673,1384],{"class":1336},[1319,1675,1346],{"class":1325},[1319,1677,1678],{"class":1336}," { selector",[1319,1680,1346],{"class":1325},[1319,1682,1683],{"class":1349}," \"#order-qty\"",[1319,1685,1381],{"class":1353},[1319,1687,1688],{"class":1336}," type",[1319,1690,1346],{"class":1325},[1319,1692,1693],{"class":1349}," \"integer\"",[1319,1695,1426],{"class":1336},[1319,1697,1354],{"class":1353},[1319,1699,1701,1703],{"class":1321,"line":1700},20,[1319,1702,1615],{"class":1336},[1319,1704,1354],{"class":1353},[1319,1706,1708,1711],{"class":1321,"line":1707},21,[1319,1709,1710],{"class":1336},"  ]",[1319,1712,1354],{"class":1353},[1319,1714,1716],{"class":1321,"line":1715},22,[1319,1717,1718],{"class":1336},"};\n",[1319,1720,1722,1725,1728,1731,1733,1736,1739,1741,1743,1745,1748,1750,1752],{"class":1321,"line":1721},23,[1319,1723,1724],{"class":1325},"await",[1319,1726,1727],{"class":1329}," kaab",[1319,1729,1106],{"class":1730},"sJugJ",[1319,1732,224],{"class":1329},[1319,1734,1735],{"class":1730},".create",[1319,1737,1738],{"class":1336},"({ name",[1319,1740,1381],{"class":1353},[1319,1742,1330],{"class":1336},[1319,1744,1381],{"class":1353},[1319,1746,1747],{"class":1336}," publish",[1319,1749,1346],{"class":1325},[1319,1751,1587],{"class":1329},[1319,1753,1754],{"class":1336}," });\n",[1025,1756,1757,1758,1760,1761,1763,1764,1767],{},"The click on the submit button carries ",[1037,1759,1039],{}," and an ",[1037,1762,1076],{}," on the order URL, so the\nfence closes only once the confirmation page has loaded. The ",[1037,1765,1766],{},"order-placed"," checkpoint is where any\nlater restart begins: a problem while reading the confirmation never places the order again.",[1025,1769,1770],{},"Creating the job with an idempotency key makes the request itself safe to repeat:",[1306,1772,1773],{},[1309,1774,1776],{"className":1311,"code":1775,"filename":1313,"language":1314,"meta":1315,"style":1315},"\u002F\u002F One key per order you mean to place; store it with the order on your side.\nconst idempotencyKey = `order-${name}`;\nconst request = { program: name, inputs: { sku: \"HP-1037\", qty: 2 } };\n\nconst first = await kaab.jobs.create({ ...request, idempotencyKey });\n\u002F\u002F A retry (after a timeout, a crash, a deploy) sends the same key and the same body…\nconst again = await kaab.jobs.create({ ...request, idempotencyKey });\n\u002F\u002F …and gets the same job back: nothing new is queued, no second order.\nconsole.log(`${first.id} === ${again.id}: ${first.id === again.id}`);\n\nconst done = await kaab.jobs.wait(first.id, { timeoutMs: 120_000 });\nconsole.log(`${done.id}: ${done.status} ${JSON.stringify(done.data)}`);\n",[1037,1777,1778,1783,1807,1850,1856,1890,1895,1924,1929,1988,1992,2030],{"__ignoreMap":1315},[1319,1779,1780],{"class":1321,"line":1322},[1319,1781,1782],{"class":1562},"\u002F\u002F One key per order you mean to place; store it with the order on your side.\n",[1319,1784,1785,1787,1790,1792,1795,1797,1799,1801,1804],{"class":1321,"line":1340},[1319,1786,1326],{"class":1325},[1319,1788,1789],{"class":1329}," idempotencyKey",[1319,1791,1333],{"class":1325},[1319,1793,1794],{"class":1349}," `order-",[1319,1796,1474],{"class":1325},[1319,1798,702],{"class":1336},[1319,1800,1480],{"class":1325},[1319,1802,1803],{"class":1349},"`",[1319,1805,1806],{"class":1336},";\n",[1319,1808,1809,1811,1814,1816,1819,1821,1824,1826,1829,1831,1833,1835,1838,1840,1842,1844,1847],{"class":1321,"line":1357},[1319,1810,1326],{"class":1325},[1319,1812,1813],{"class":1329}," request",[1319,1815,1333],{"class":1325},[1319,1817,1818],{"class":1336}," { program",[1319,1820,1346],{"class":1325},[1319,1822,1823],{"class":1336}," name",[1319,1825,1381],{"class":1353},[1319,1827,1828],{"class":1336}," inputs",[1319,1830,1346],{"class":1325},[1319,1832,1373],{"class":1336},[1319,1834,1346],{"class":1325},[1319,1836,1837],{"class":1349}," \"HP-1037\"",[1319,1839,1381],{"class":1353},[1319,1841,1384],{"class":1336},[1319,1843,1346],{"class":1325},[1319,1845,1846],{"class":1329}," 2",[1319,1848,1849],{"class":1336}," } };\n",[1319,1851,1852],{"class":1321,"line":1365},[1319,1853,1855],{"emptyLinePlaceholder":1854},true,"\n",[1319,1857,1858,1860,1863,1865,1868,1870,1872,1874,1876,1879,1882,1885,1887],{"class":1321,"line":1431},[1319,1859,1326],{"class":1325},[1319,1861,1862],{"class":1329}," first",[1319,1864,1333],{"class":1325},[1319,1866,1867],{"class":1325}," await",[1319,1869,1727],{"class":1329},[1319,1871,1106],{"class":1730},[1319,1873,171],{"class":1329},[1319,1875,1735],{"class":1730},[1319,1877,1878],{"class":1336},"({ ",[1319,1880,1881],{"class":1325},"...",[1319,1883,1884],{"class":1336},"request",[1319,1886,1381],{"class":1353},[1319,1888,1889],{"class":1336}," idempotencyKey });\n",[1319,1891,1892],{"class":1321,"line":1452},[1319,1893,1894],{"class":1562},"\u002F\u002F A retry (after a timeout, a crash, a deploy) sends the same key and the same body…\n",[1319,1896,1897,1899,1902,1904,1906,1908,1910,1912,1914,1916,1918,1920,1922],{"class":1321,"line":1463},[1319,1898,1326],{"class":1325},[1319,1900,1901],{"class":1329}," again",[1319,1903,1333],{"class":1325},[1319,1905,1867],{"class":1325},[1319,1907,1727],{"class":1329},[1319,1909,1106],{"class":1730},[1319,1911,171],{"class":1329},[1319,1913,1735],{"class":1730},[1319,1915,1878],{"class":1336},[1319,1917,1881],{"class":1325},[1319,1919,1884],{"class":1336},[1319,1921,1381],{"class":1353},[1319,1923,1889],{"class":1336},[1319,1925,1926],{"class":1321,"line":1505},[1319,1927,1928],{"class":1562},"\u002F\u002F …and gets the same job back: nothing new is queued, no second order.\n",[1319,1930,1931,1934,1937,1940,1942,1944,1947,1950,1952,1955,1957,1960,1962,1964,1967,1969,1971,1974,1977,1979,1981,1983,1985],{"class":1321,"line":1530},[1319,1932,1933],{"class":1329},"console",[1319,1935,1936],{"class":1730},".log",[1319,1938,1939],{"class":1336},"(",[1319,1941,1803],{"class":1349},[1319,1943,1474],{"class":1325},[1319,1945,1946],{"class":1329},"first",[1319,1948,1949],{"class":1336},".id",[1319,1951,1480],{"class":1325},[1319,1953,1954],{"class":1349}," === ",[1319,1956,1474],{"class":1325},[1319,1958,1959],{"class":1329},"again",[1319,1961,1949],{"class":1336},[1319,1963,1480],{"class":1325},[1319,1965,1966],{"class":1349},": ",[1319,1968,1474],{"class":1325},[1319,1970,1946],{"class":1329},[1319,1972,1973],{"class":1336},".id ",[1319,1975,1976],{"class":1325},"===",[1319,1978,1901],{"class":1329},[1319,1980,1949],{"class":1336},[1319,1982,1480],{"class":1325},[1319,1984,1803],{"class":1349},[1319,1986,1987],{"class":1336},");\n",[1319,1989,1990],{"class":1321,"line":1553},[1319,1991,1855],{"emptyLinePlaceholder":1854},[1319,1993,1994,1996,1999,2001,2003,2005,2007,2009,2012,2014,2016,2018,2020,2023,2025,2028],{"class":1321,"line":1559},[1319,1995,1326],{"class":1325},[1319,1997,1998],{"class":1329}," done",[1319,2000,1333],{"class":1325},[1319,2002,1867],{"class":1325},[1319,2004,1727],{"class":1329},[1319,2006,1106],{"class":1730},[1319,2008,171],{"class":1329},[1319,2010,2011],{"class":1730},".wait",[1319,2013,1939],{"class":1336},[1319,2015,1946],{"class":1329},[1319,2017,1949],{"class":1336},[1319,2019,1381],{"class":1353},[1319,2021,2022],{"class":1336}," { timeoutMs",[1319,2024,1346],{"class":1325},[1319,2026,2027],{"class":1329}," 120_000",[1319,2029,1754],{"class":1336},[1319,2031,2032,2034,2036,2038,2040,2042,2045,2047,2049,2051,2053,2055,2058,2060,2063,2066,2069,2071,2073,2076,2078,2080],{"class":1321,"line":1566},[1319,2033,1933],{"class":1329},[1319,2035,1936],{"class":1730},[1319,2037,1939],{"class":1336},[1319,2039,1803],{"class":1349},[1319,2041,1474],{"class":1325},[1319,2043,2044],{"class":1329},"done",[1319,2046,1949],{"class":1336},[1319,2048,1480],{"class":1325},[1319,2050,1966],{"class":1349},[1319,2052,1474],{"class":1325},[1319,2054,2044],{"class":1329},[1319,2056,2057],{"class":1336},".status",[1319,2059,1480],{"class":1325},[1319,2061,2062],{"class":1325}," ${",[1319,2064,2065],{"class":1329},"JSON",[1319,2067,2068],{"class":1730},".stringify",[1319,2070,1939],{"class":1336},[1319,2072,2044],{"class":1329},[1319,2074,2075],{"class":1336},".data)",[1319,2077,1480],{"class":1325},[1319,2079,1803],{"class":1349},[1319,2081,1987],{"class":1336},[1025,2083,2084,2085,2087,2088,2091],{},"The second ",[1037,2086,1281],{}," sends the same key and the same body, gets the first job back, and the\nsite receives one order, not two. A ",[1037,2089,2090],{},"dry_run"," of the same program fills the form and stops before\nthe submit, and the site receives no order at all.",[1029,2093,2095],{"id":2094},"pitfalls","Pitfalls",[1156,2097,2098,2113,2119,2125,2134],{},[1159,2099,2100,2106,2107,2109,2110,2112],{},[1162,2101,2102,2103,2105],{},"An ",[1037,2104,1076],{}," that is too loose."," The fence closes when the step's ",[1037,2108,1076],{}," holds. An ",[1037,2111,1076],{},"\nthat holds before the site has answered (a spinner, the same URL) closes it too early; one that\nnever holds parks the job even though the order went through. Wait for the page or element that\nonly exists after success.",[1159,2114,2115,2118],{},[1162,2116,2117],{},"Several side effects without checkpoints between them."," Lint warns (W004), and an interruption\nafter the second one leaves no restart point between the two.",[1159,2120,2121,2124],{},[1162,2122,2123],{},"A new idempotency key per retry."," A key generated inside the retry loop protects nothing. Make\nit once, from your own record of the order.",[1159,2126,2127,2130,2131,2133],{},[1162,2128,2129],{},"Reusing a key for different work."," Within 24 hours the same key with a different body is\n",[1037,2132,1275],{},", not a new job.",[1159,2135,2136,2139,2140,2142],{},[1162,2137,2138],{},"Expecting cancel to work at any moment."," Inside an open fence it is refused with ",[1037,2141,1105],{},"; cancel again once the step has finished.",[1029,2144,155],{"id":2145},"reference",[1156,2147,2148,2161,2168,2183],{},[1159,2149,2150,2154,2155],{},[1123,2151,2153],{"href":2152},"\u002Freference\u002Fdsl\u002Fsteps","Steps: common keys"," and the ",[1123,2156,2158,2160],{"href":2157},"\u002Freference\u002Fdsl\u002Factions\u002Fcheckpoint",[1037,2159,595],{}," action",[1159,2162,2163,2164,1050,2166],{},"Lint ",[1123,2165,793],{"href":1125},[1123,2167,814],{"href":1142},[1159,2169,2170,2174,2175,1354,2179],{},[1123,2171,2173],{"href":2172},"\u002Freference\u002Fapi\u002Fjobs\u002Fcreate-job","Create a job",", ",[1123,2176,2178],{"href":2177},"\u002Freference\u002Fapi\u002Fjobs\u002Fresume-job","resume a job",[1123,2180,2182],{"href":2181},"\u002Freference\u002Fapi\u002Fjobs\u002Fcancel-job","cancel a job",[1159,2184,2185,1050,2189],{},[1123,2186,2188],{"href":2187},"\u002Freference\u002Fcodes#attention-reasons","Attention reasons",[1123,2190,2192],{"href":2191},"\u002Freference\u002Fcodes#errors","error codes",[2194,2195,2196],"style",{},"html pre.shiki code .sqn18, html code.shiki .sqn18{--shiki-light:var(--kaab-code-token-keyword);--shiki-default:var(--kaab-code-token-keyword);--shiki-dark:var(--kaab-code-token-keyword)}html pre.shiki code .sHJIl, html code.shiki .sHJIl{--shiki-light:var(--kaab-code-token-constant);--shiki-default:var(--kaab-code-token-constant);--shiki-dark:var(--kaab-code-token-constant)}html pre.shiki code .sTzsn, html code.shiki .sTzsn{--shiki-light:var(--kaab-code-foreground);--shiki-default:var(--kaab-code-foreground);--shiki-dark:var(--kaab-code-foreground)}html pre.shiki code .suOy4, html code.shiki .suOy4{--shiki-light:var(--kaab-code-token-string-expression);--shiki-default:var(--kaab-code-token-string-expression);--shiki-dark:var(--kaab-code-token-string-expression)}html pre.shiki code .sQm2-, html code.shiki .sQm2-{--shiki-light:var(--kaab-code-token-punctuation);--shiki-default:var(--kaab-code-token-punctuation);--shiki-dark:var(--kaab-code-token-punctuation)}html pre.shiki code .sKog0, html code.shiki .sKog0{--shiki-light:var(--kaab-code-token-comment);--shiki-default:var(--kaab-code-token-comment);--shiki-dark:var(--kaab-code-token-comment)}html pre.shiki code .sJugJ, html code.shiki .sJugJ{--shiki-light:var(--kaab-code-token-function);--shiki-default:var(--kaab-code-token-function);--shiki-dark:var(--kaab-code-token-function)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":1315,"searchDepth":1357,"depth":1357,"links":2198},[2199,2200,2208,2209,2210,2211],{"id":1031,"depth":1340,"text":1032},{"id":1056,"depth":1340,"text":2201,"children":2202},"What side_effect: true changes",[2203,2204,2205,2206,2207],{"id":1064,"depth":1357,"text":1065},{"id":1109,"depth":1357,"text":1110},{"id":1132,"depth":1357,"text":1133},{"id":1146,"depth":1357,"text":1147},{"id":1219,"depth":1357,"text":1220},{"id":1241,"depth":1340,"text":1242},{"id":1292,"depth":1340,"text":1293},{"id":2094,"depth":1340,"text":2095},{"id":2145,"depth":1340,"text":155},false,null,"Mark the steps that change something, checkpoint after them, and send an idempotency key, so an order is never placed twice.","md",{},"\u002Fguides\u002Fside-effect-safety",{"title":113,"description":2214},"3.guides\u002F09.side-effect-safety","RWPKyPgyfh05IklfckuC6zKYMwdWQ4x3snHAvIcvExM",[2222,2226],{"title":110,"path":2223,"stem":2224,"description":2225,"children":-1},"\u002Fguides\u002Ftesting","3.guides\u002F08.testing","Test programs without spending credits or touching live data: test keys, cost estimates, lint, dry runs and replays against stored pages.",{"title":116,"path":2227,"stem":2228,"description":2229,"children":-1},"\u002Fguides\u002Fsecurity-and-data","3.guides\u002F10.security-and-data","What Kaabist stores about your jobs, how secrets and sessions are protected, how long data is kept, and how to delete it.",1793593417401]