[{"data":1,"prerenderedAt":1768},["ShallowReactive",2],{"navigation":3,"/sdks/go":258,"/sdks/go-surround":1763},[4,22,63,85,115,131,219,245],{"title":5,"path":6,"stem":7,"children":8,"page":21},"Getting Started","/getting-started","1.getting-started",[9,13,17],{"title":10,"path":11,"stem":12},"Introduction","/getting-started/introduction","1.getting-started/1.introduction",{"title":14,"path":15,"stem":16},"Quick Start","/getting-started/quick-start","1.getting-started/2.quick-start",{"title":18,"path":19,"stem":20},"Key Concepts","/getting-started/key-concepts","1.getting-started/3.key-concepts",false,{"title":23,"path":24,"stem":25,"children":26,"page":21},"Guides","/guides","2.guides",[27,31,35,39,43,47,51,55,59],{"title":28,"path":29,"stem":30},"Quick Share Guide","/guides/quick-share","2.guides/1.quick-share",{"title":32,"path":33,"stem":34},"Slack Integration","/guides/slack-integration","2.guides/2.slack-integration",{"title":36,"path":37,"stem":38},"Enterprise Setup","/guides/enterprise-setup","2.guides/3.enterprise-setup",{"title":40,"path":41,"stem":42},"Creating a Share","/guides/creating-a-share","2.guides/4.creating-a-share",{"title":44,"path":45,"stem":46},"Zero-Knowledge Custody","/guides/zero-knowledge-custody","2.guides/5.zero-knowledge-custody",{"title":48,"path":49,"stem":50},"Secure Requests","/guides/secure-requests","2.guides/6.secure-requests",{"title":52,"path":53,"stem":54},"Receiving a Secure Request","/guides/receiving-a-secure-request","2.guides/7.receiving-a-secure-request",{"title":56,"path":57,"stem":58},"SecurePaste","/guides/securepaste","2.guides/8.securepaste",{"title":60,"path":61,"stem":62},"Notifications","/guides/notifications","2.guides/9.notifications",{"title":64,"icon":65,"path":66,"stem":67,"children":68,"page":21},"Account","i-lucide-user-cog","/account","3.account",[69,73,77,81],{"title":70,"path":71,"stem":72},"Signing In","/account/signing-in","3.account/1.signing-in",{"title":74,"path":75,"stem":76},"Plans and Share Allowance","/account/plans-and-share-allowance","3.account/2.plans-and-share-allowance",{"title":78,"path":79,"stem":80},"Billing and Subscription","/account/billing-and-subscription","3.account/3.billing-and-subscription",{"title":82,"path":83,"stem":84},"Plans and Limits","/account/plans-and-limits","3.account/4.plans-and-limits",{"title":86,"icon":87,"path":88,"stem":89,"children":90,"page":21},"Teams","i-lucide-users","/teams","4.teams",[91,95,99,103,107,111],{"title":92,"path":93,"stem":94},"Teams and Contexts","/teams/teams-and-contexts","4.teams/1.teams-and-contexts",{"title":96,"path":97,"stem":98},"Members, Roles and Seats","/teams/members-roles-and-seats","4.teams/2.members-roles-and-seats",{"title":100,"path":101,"stem":102},"Joining a Team","/teams/joining-a-team","4.teams/3.joining-a-team",{"title":104,"path":105,"stem":106},"Custom Branding","/teams/custom-branding","4.teams/4.custom-branding",{"title":108,"path":109,"stem":110},"Policy and Audit","/teams/policy-and-audit","4.teams/5.policy-and-audit",{"title":112,"path":113,"stem":114},"Zero-Knowledge for Teams","/teams/zero-knowledge-for-teams","4.teams/6.zero-knowledge-for-teams",{"title":116,"path":117,"stem":118,"children":119,"icon":130},"Help","/help","5.help/0.index",[120,122,126],{"title":121,"path":117,"stem":118},"Help and Support",{"title":123,"path":124,"stem":125},"Link Not Working","/help/link-not-working","5.help/1.link-not-working",{"title":127,"path":128,"stem":129},"Error Messages","/help/error-messages","5.help/2.error-messages","i-lucide-life-buoy",{"title":132,"path":133,"stem":134,"children":135},"API Reference","/api","6.api/0.index",[136,137,141,167,189,193,211,215],{"title":132,"path":133,"stem":134},{"title":138,"path":139,"stem":140},"Authentication","/api/authentication","6.api/1.authentication",{"title":142,"path":143,"stem":144,"children":145},"Shares","/api/shares","6.api/2.shares/0.index",[146,147,151,155,159,163],{"title":142,"path":143,"stem":144},{"title":148,"path":149,"stem":150},"Create a share","/api/shares/create","6.api/2.shares/1.create",{"title":152,"path":153,"stem":154},"List shares","/api/shares/list","6.api/2.shares/2.list",{"title":156,"path":157,"stem":158},"Retrieve a share","/api/shares/retrieve","6.api/2.shares/3.retrieve",{"title":160,"path":161,"stem":162},"Expire a share","/api/shares/delete","6.api/2.shares/4.delete",{"title":164,"path":165,"stem":166},"Client-side encryption","/api/shares/client-side-encryption","6.api/2.shares/5.client-side-encryption",{"title":168,"path":169,"stem":170,"children":171},"Secure requests","/api/requests","6.api/3.requests/0.index",[172,173,177,181,185],{"title":168,"path":169,"stem":170},{"title":174,"path":175,"stem":176},"Create a request","/api/requests/create","6.api/3.requests/1.create",{"title":178,"path":179,"stem":180},"List and retrieve requests","/api/requests/list","6.api/3.requests/2.list",{"title":182,"path":183,"stem":184},"Read submissions","/api/requests/submissions","6.api/3.requests/3.submissions",{"title":186,"path":187,"stem":188},"Expire or delete a request","/api/requests/delete","6.api/3.requests/4.delete",{"title":190,"path":191,"stem":192},"Stats","/api/stats","6.api/4.stats",{"title":194,"path":195,"stem":196,"children":197},"Webhooks","/api/webhooks","6.api/5.webhooks/0.index",[198,199,203,207],{"title":194,"path":195,"stem":196},{"title":200,"path":201,"stem":202},"Event reference","/api/webhooks/events","6.api/5.webhooks/1.events",{"title":204,"path":205,"stem":206},"Verifying signatures","/api/webhooks/verifying-signatures","6.api/5.webhooks/2.verifying-signatures",{"title":208,"path":209,"stem":210},"Delivery and retries","/api/webhooks/delivery-and-retries","6.api/5.webhooks/3.delivery-and-retries",{"title":212,"path":213,"stem":214},"MCP server","/api/mcp","6.api/6.mcp",{"title":216,"path":217,"stem":218},"Errors and Rate Limits","/api/errors-and-limits","6.api/7.errors-and-limits",{"title":220,"path":221,"stem":222,"children":223},"SDKs","/sdks","7.sdks/0.index",[224,225,229,233,237,241],{"title":220,"path":221,"stem":222},{"title":226,"path":227,"stem":228},"Node SDK","/sdks/node","7.sdks/1.node",{"title":230,"path":231,"stem":232},"Python SDK","/sdks/python","7.sdks/2.python",{"title":234,"path":235,"stem":236},"Go SDK","/sdks/go","7.sdks/3.go",{"title":238,"path":239,"stem":240},"Rust SDK","/sdks/rust","7.sdks/4.rust",{"title":242,"path":243,"stem":244},"Conformance vectors","/sdks/conformance-vectors","7.sdks/5.conformance-vectors",{"title":246,"path":247,"stem":248,"children":249,"page":21},"Security","/security","8.security",[250,254],{"title":251,"path":252,"stem":253},"Encryption","/security/encryption","8.security/1.encryption",{"title":255,"path":256,"stem":257},"Compliance","/security/compliance","8.security/2.compliance",{"id":259,"title":234,"api":260,"body":261,"description":1758,"extension":1759,"links":260,"meta":1760,"navigation":372,"path":235,"seo":1761,"stem":236,"__hash__":1762},"docs/7.sdks/3.go.md",null,{"type":262,"value":263,"toc":1747},"minimark",[264,274,287,292,317,328,347,351,704,710,733,737,759,797,839,843,923,930,941,948,952,1088,1113,1120,1135,1139,1334,1344,1350,1374,1390,1417,1421,1510,1523,1537,1541,1544,1699,1703,1706,1726,1743],[265,266,267],"p",{},[268,269,273],"a",{"href":270,"rel":271},"https://github.com/CredenShare/credenshare-sdk-go",[272],"nofollow","github.com/CredenShare/credenshare-sdk-go",[265,275,276,277,281,282,286],{},"Go 1.21 and above. ",[278,279,280],"strong",{},"Standard library only"," — HKDF is forty lines of ",[283,284,285],"code",{},"crypto/hmac"," rather than a module, because a security client earning a dependency for that is a poor trade.",[288,289,291],"h2",{"id":290},"installing","Installing",[293,294,299],"pre",{"className":295,"code":296,"language":297,"meta":298,"style":298},"language-bash shiki shiki-themes github-light github-dark github-dark","go get github.com/CredenShare/credenshare-sdk-go\n","bash","",[283,300,301],{"__ignoreMap":298},[302,303,306,310,314],"span",{"class":304,"line":305},"line",1,[302,307,309],{"class":308},"shcOC","go",[302,311,313],{"class":312},"sfrk1"," get",[302,315,316],{"class":312}," github.com/CredenShare/credenshare-sdk-go\n",[265,318,319,320,323,324,327],{},"A Go module resolves straight from its repository through the proxy, so there was never a registry to wait for. Name a version if you want one — ",[283,321,322],{},"@v0.1.3"," — otherwise ",[283,325,326],{},"go get"," takes the latest tag.",[329,330,333],"callout",{"color":331,"icon":332},"info","i-lucide-info",[265,334,335,336,339,340,342,343,346],{},"The proxy's ",[283,337,338],{},"@v/list"," endpoint lags behind a fresh tag by a while, so a version can be missing from that listing and still resolve perfectly — ",[283,341,326],{}," and ",[283,344,345],{},"@latest"," fetch on demand. If a brand-new version appears absent, ask for it by name rather than assuming it failed to publish.",[288,348,350],{"id":349},"quickstart","Quickstart",[293,352,356],{"className":353,"code":354,"filename":355,"language":309,"meta":298,"style":298},"language-go shiki shiki-themes github-light github-dark github-dark","package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"os\"\n\n    credenshare \"github.com/CredenShare/credenshare-sdk-go\"\n)\n\nfunc main() {\n    client, err := credenshare.New(os.Getenv(\"CREDENSHARE_KEY\"), nil)\n    if err != nil {\n        panic(err)\n    }\n\n    share, err := client.CreateShare(context.Background(), credenshare.CreateParams{\n        Title: \"Staging deploy credentials\",\n        Fields: []credenshare.Field{\n            {Key: \"Username\", Value: \"deploy-bot\", Type: \"text\"},\n            {Key: \"Password\", Value: \"correct horse\", Type: \"password\"},\n        },\n    })\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Println(share.Link)\n    // https://crs.sh/aB3dEf12#1xK9...\n}\n","main.go",[283,357,358,367,374,384,396,406,416,421,434,440,445,457,493,511,520,526,531,566,578,593,617,637,643,649,662,669,674,679,691,698],{"__ignoreMap":298},[302,359,360,364],{"class":304,"line":305},[302,361,363],{"class":362},"so5gQ","package",[302,365,366],{"class":308}," main\n",[302,368,370],{"class":304,"line":369},2,[302,371,373],{"emptyLinePlaceholder":372},true,"\n",[302,375,377,380],{"class":304,"line":376},3,[302,378,379],{"class":362},"import",[302,381,383],{"class":382},"slsVL"," (\n",[302,385,387,390,393],{"class":304,"line":386},4,[302,388,389],{"class":312},"    \"",[302,391,392],{"class":308},"context",[302,394,395],{"class":312},"\"\n",[302,397,399,401,404],{"class":304,"line":398},5,[302,400,389],{"class":312},[302,402,403],{"class":308},"fmt",[302,405,395],{"class":312},[302,407,409,411,414],{"class":304,"line":408},6,[302,410,389],{"class":312},[302,412,413],{"class":308},"os",[302,415,395],{"class":312},[302,417,419],{"class":304,"line":418},7,[302,420,373],{"emptyLinePlaceholder":372},[302,422,424,427,430,432],{"class":304,"line":423},8,[302,425,426],{"class":382},"    credenshare ",[302,428,429],{"class":312},"\"",[302,431,273],{"class":308},[302,433,395],{"class":312},[302,435,437],{"class":304,"line":436},9,[302,438,439],{"class":382},")\n",[302,441,443],{"class":304,"line":442},10,[302,444,373],{"emptyLinePlaceholder":372},[302,446,448,451,454],{"class":304,"line":447},11,[302,449,450],{"class":362},"func",[302,452,453],{"class":308}," main",[302,455,456],{"class":382},"() {\n",[302,458,460,463,466,469,472,475,478,481,484,487,491],{"class":304,"line":459},12,[302,461,462],{"class":382},"    client, err ",[302,464,465],{"class":362},":=",[302,467,468],{"class":382}," credenshare.",[302,470,471],{"class":308},"New",[302,473,474],{"class":382},"(os.",[302,476,477],{"class":308},"Getenv",[302,479,480],{"class":382},"(",[302,482,483],{"class":312},"\"CREDENSHARE_KEY\"",[302,485,486],{"class":382},"), ",[302,488,490],{"class":489},"suiK_","nil",[302,492,439],{"class":382},[302,494,496,499,502,505,508],{"class":304,"line":495},13,[302,497,498],{"class":362},"    if",[302,500,501],{"class":382}," err ",[302,503,504],{"class":362},"!=",[302,506,507],{"class":489}," nil",[302,509,510],{"class":382}," {\n",[302,512,514,517],{"class":304,"line":513},14,[302,515,516],{"class":308},"        panic",[302,518,519],{"class":382},"(err)\n",[302,521,523],{"class":304,"line":522},15,[302,524,525],{"class":382},"    }\n",[302,527,529],{"class":304,"line":528},16,[302,530,373],{"emptyLinePlaceholder":372},[302,532,534,537,539,542,545,548,551,554,557,560,563],{"class":304,"line":533},17,[302,535,536],{"class":382},"    share, err ",[302,538,465],{"class":362},[302,540,541],{"class":382}," client.",[302,543,544],{"class":308},"CreateShare",[302,546,547],{"class":382},"(context.",[302,549,550],{"class":308},"Background",[302,552,553],{"class":382},"(), ",[302,555,556],{"class":308},"credenshare",[302,558,559],{"class":382},".",[302,561,562],{"class":308},"CreateParams",[302,564,565],{"class":382},"{\n",[302,567,569,572,575],{"class":304,"line":568},18,[302,570,571],{"class":382},"        Title: ",[302,573,574],{"class":312},"\"Staging deploy credentials\"",[302,576,577],{"class":382},",\n",[302,579,581,584,586,588,591],{"class":304,"line":580},19,[302,582,583],{"class":382},"        Fields: []",[302,585,556],{"class":308},[302,587,559],{"class":382},[302,589,590],{"class":308},"Field",[302,592,565],{"class":382},[302,594,596,599,602,605,608,611,614],{"class":304,"line":595},20,[302,597,598],{"class":382},"            {Key: ",[302,600,601],{"class":312},"\"Username\"",[302,603,604],{"class":382},", Value: ",[302,606,607],{"class":312},"\"deploy-bot\"",[302,609,610],{"class":382},", Type: ",[302,612,613],{"class":312},"\"text\"",[302,615,616],{"class":382},"},\n",[302,618,620,622,625,627,630,632,635],{"class":304,"line":619},21,[302,621,598],{"class":382},[302,623,624],{"class":312},"\"Password\"",[302,626,604],{"class":382},[302,628,629],{"class":312},"\"correct horse\"",[302,631,610],{"class":382},[302,633,634],{"class":312},"\"password\"",[302,636,616],{"class":382},[302,638,640],{"class":304,"line":639},22,[302,641,642],{"class":382},"        },\n",[302,644,646],{"class":304,"line":645},23,[302,647,648],{"class":382},"    })\n",[302,650,652,654,656,658,660],{"class":304,"line":651},24,[302,653,498],{"class":362},[302,655,501],{"class":382},[302,657,504],{"class":362},[302,659,507],{"class":489},[302,661,510],{"class":382},[302,663,665,667],{"class":304,"line":664},25,[302,666,516],{"class":308},[302,668,519],{"class":382},[302,670,672],{"class":304,"line":671},26,[302,673,525],{"class":382},[302,675,677],{"class":304,"line":676},27,[302,678,373],{"emptyLinePlaceholder":372},[302,680,682,685,688],{"class":304,"line":681},28,[302,683,684],{"class":382},"    fmt.",[302,686,687],{"class":308},"Println",[302,689,690],{"class":382},"(share.Link)\n",[302,692,694],{"class":304,"line":693},29,[302,695,697],{"class":696},"sCsY4","    // https://crs.sh/aB3dEf12#1xK9...\n",[302,699,701],{"class":304,"line":700},30,[302,702,703],{"class":382},"}\n",[265,705,706,709],{},[278,707,708],{},"That link is the secret."," The key rides in the fragment, which browsers never transmit. Anyone holding the link can read the content; we cannot, and cannot recover it for you.",[265,711,712,713,716,717,720,721,724,725,728,729,732],{},"Note that ",[283,714,715],{},"fmt.Println(share)"," prints ",[283,718,719],{},"\u003CShare aB3dEf12 (link withheld)>"," — the ",[283,722,723],{},"String"," method deliberately withholds the link, so ",[283,726,727],{},"%v"," in a log will not leak it. Print ",[283,730,731],{},"share.Link"," when you actually want it.",[288,734,736],{"id":735},"the-field-object","The field object",[265,738,739,742,743,746,747,750,751,754,755,758],{},[283,740,741],{},"Field.Key"," is the ",[278,744,745],{},"visible label",", not an identifier — it is what the recipient reads. Go's types stop the ",[283,748,749],{},"label:"," spelling that catches the dynamic clients, but a caller unmarshalling from JSON with the wrong member name lands in the same place: ",[283,752,753],{},"Key"," empty, every field rendered blank, nothing erroring. ",[283,756,757],{},"ValidateFields"," refuses that before anything is sent.",[265,760,761,764,765,768,769,768,772,768,775,768,778,768,781,784,785,788,789,791,792,796],{},[283,762,763],{},"Type"," is one of ",[283,766,767],{},"text",", ",[283,770,771],{},"password",[283,773,774],{},"date",[283,776,777],{},"multiline",[283,779,780],{},"markdown",[283,782,783],{},"source_code",", exported as ",[283,786,787],{},"FieldTypes",". Validation checks only that ",[283,790,763],{}," is ",[793,794,795],"em",{},"present",", not that it is a member of that set.",[329,798,799],{"color":331,"icon":332},[265,800,801,804,805,807,808,811,812,768,815,818,819,821,822,342,825,828,829,832,833,836,837,559],{},[278,802,803],{},"Optional field members survive."," ",[283,806,590],{}," carries an ",[283,809,810],{},"Extra map[string]json.RawMessage"," overflow map, so members this client does not name — ",[283,813,814],{},"selectedProgrammingLanguage",[283,816,817],{},"filename",", anything a newer sender adds — are kept on decrypt and written back on re-encrypt. The cost is that ",[283,820,590],{}," is no longer comparable — ",[283,823,824],{},"f1 == f2",[283,826,827],{},"map[Field]T"," do not compile against this version. Use ",[283,830,831],{},"Field.Equal(other)",", which compares the three known members plus ",[283,834,835],{},"Extra"," as raw bytes, and key maps on ",[283,838,741],{},[288,840,842],{"id":841},"creating","Creating",[293,844,846],{"className":353,"code":845,"language":309,"meta":298,"style":298},"share, err := client.CreateShare(ctx, credenshare.CreateParams{\n    Title:    \"Production database\",\n    Fields:   []credenshare.Field{{Key: \"Password\", Value: \"s3cr3t\", Type: \"password\"}},\n    Passcode: \"hunter2\",\n})\n",[283,847,848,870,880,908,918],{"__ignoreMap":298},[302,849,850,853,855,857,859,862,864,866,868],{"class":304,"line":305},[302,851,852],{"class":382},"share, err ",[302,854,465],{"class":362},[302,856,541],{"class":382},[302,858,544],{"class":308},[302,860,861],{"class":382},"(ctx, ",[302,863,556],{"class":308},[302,865,559],{"class":382},[302,867,562],{"class":308},[302,869,565],{"class":382},[302,871,872,875,878],{"class":304,"line":369},[302,873,874],{"class":382},"    Title:    ",[302,876,877],{"class":312},"\"Production database\"",[302,879,577],{"class":382},[302,881,882,885,887,889,891,894,896,898,901,903,905],{"class":304,"line":376},[302,883,884],{"class":382},"    Fields:   []",[302,886,556],{"class":308},[302,888,559],{"class":382},[302,890,590],{"class":308},[302,892,893],{"class":382},"{{Key: ",[302,895,624],{"class":312},[302,897,604],{"class":382},[302,899,900],{"class":312},"\"s3cr3t\"",[302,902,610],{"class":382},[302,904,634],{"class":312},[302,906,907],{"class":382},"}},\n",[302,909,910,913,916],{"class":304,"line":386},[302,911,912],{"class":382},"    Passcode: ",[302,914,915],{"class":312},"\"hunter2\"",[302,917,577],{"class":382},[302,919,920],{"class":304,"line":398},[302,921,922],{"class":382},"})\n",[265,924,925,926,929],{},"A passcode is mixed into the ",[278,927,928],{},"content key derivation",", not just checked by the server — so it is not a server-side gate you could bypass, and a passcode-protected share cannot be opened from the link alone. The server receives only a one-way verifier. Send the link and the passcode over different channels.",[265,931,932,933,936,937,940],{},"Set ",[283,934,935],{},"Custody: true"," to also wrap the content key to the custody public key derived from your credential's third part, which keeps the share readable from your dashboard rather than only from its link. ",[283,938,939],{},"Credential.WrapToCustody"," computes it locally; the custody secret never leaves your machine.",[265,942,943,944,947],{},"Requires the ",[283,945,946],{},"shares:write"," scope.",[288,949,951],{"id":950},"listing-and-expiring","Listing and expiring",[293,953,955],{"className":353,"code":954,"language":309,"meta":298,"style":298},"page, err := client.ListShares(ctx, 50, 1)\nfmt.Println(page.Total, page.HasMore())\n\nerr = client.IterateShares(ctx, 100, func(s credenshare.ShareSummary) error {\n    fmt.Println(s.ShortCode, s.ExpiredAt)\n    return nil\n})\n\nerr = client.ExpireShare(ctx, \"aB3dEf12\")\n",[283,956,957,981,997,1001,1045,1054,1062,1066,1070],{"__ignoreMap":298},[302,958,959,962,964,966,969,971,974,976,979],{"class":304,"line":305},[302,960,961],{"class":382},"page, err ",[302,963,465],{"class":362},[302,965,541],{"class":382},[302,967,968],{"class":308},"ListShares",[302,970,861],{"class":382},[302,972,973],{"class":489},"50",[302,975,768],{"class":382},[302,977,978],{"class":489},"1",[302,980,439],{"class":382},[302,982,983,986,988,991,994],{"class":304,"line":369},[302,984,985],{"class":382},"fmt.",[302,987,687],{"class":308},[302,989,990],{"class":382},"(page.Total, page.",[302,992,993],{"class":308},"HasMore",[302,995,996],{"class":382},"())\n",[302,998,999],{"class":304,"line":376},[302,1000,373],{"emptyLinePlaceholder":372},[302,1002,1003,1006,1009,1011,1014,1016,1019,1021,1023,1025,1029,1032,1034,1037,1040,1043],{"class":304,"line":386},[302,1004,1005],{"class":382},"err ",[302,1007,1008],{"class":362},"=",[302,1010,541],{"class":382},[302,1012,1013],{"class":308},"IterateShares",[302,1015,861],{"class":382},[302,1017,1018],{"class":489},"100",[302,1020,768],{"class":382},[302,1022,450],{"class":362},[302,1024,480],{"class":382},[302,1026,1028],{"class":1027},"sQHwn","s",[302,1030,1031],{"class":308}," credenshare",[302,1033,559],{"class":382},[302,1035,1036],{"class":308},"ShareSummary",[302,1038,1039],{"class":382},") ",[302,1041,1042],{"class":362},"error",[302,1044,510],{"class":382},[302,1046,1047,1049,1051],{"class":304,"line":398},[302,1048,684],{"class":382},[302,1050,687],{"class":308},[302,1052,1053],{"class":382},"(s.ShortCode, s.ExpiredAt)\n",[302,1055,1056,1059],{"class":304,"line":408},[302,1057,1058],{"class":362},"    return",[302,1060,1061],{"class":489}," nil\n",[302,1063,1064],{"class":304,"line":418},[302,1065,922],{"class":382},[302,1067,1068],{"class":304,"line":423},[302,1069,373],{"emptyLinePlaceholder":372},[302,1071,1072,1074,1076,1078,1081,1083,1086],{"class":304,"line":436},[302,1073,1005],{"class":382},[302,1075,1008],{"class":362},[302,1077,541],{"class":382},[302,1079,1080],{"class":308},"ExpireShare",[302,1082,861],{"class":382},[302,1084,1085],{"class":312},"\"aB3dEf12\"",[302,1087,439],{"class":382},[265,1089,1090,342,1092,1095,1096,1099,1100,342,1102,1095,1104,1106,1107,1109,1110,1112],{},[283,1091,968],{},[283,1093,1094],{},"GetShare"," need ",[283,1097,1098],{},"shares:read","; ",[283,1101,544],{},[283,1103,1080],{},[283,1105,946],{},". There is no hierarchy between them, so a key minted with only ",[283,1108,946],{}," fails on ",[283,1111,968],{}," with a permission error — the most common first surprise.",[265,1114,1115,1116,1119],{},"Both return ",[278,1117,1118],{},"metadata only",", never content and never a key. A short code belonging to another account reports exactly as one that does not exist.",[265,1121,1122,804,1124,1127,1128,1130,1131,1134],{},[283,1123,1080],{},[278,1125,1126],{},"removes"," the share rather than flagging it, so a later ",[283,1129,1094],{}," returns ",[283,1132,1133],{},"ErrNotFound",". A share you expired and one that never existed are indistinguishable afterwards.",[288,1136,1138],{"id":1137},"verifying-webhooks","Verifying webhooks",[293,1140,1142],{"className":353,"code":1141,"language":309,"meta":298,"style":298},"import \"github.com/CredenShare/credenshare-sdk-go/webhooks\"\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n    body, err := io.ReadAll(r.Body)   // the RAW bytes, before any decoding\n    if err != nil {\n        w.WriteHeader(http.StatusBadRequest)\n        return\n    }\n\n    if err := webhooks.Verify(body, r.Header.Get(webhooks.SignatureHeader),\n        []string{os.Getenv(\"WEBHOOK_SECRET\")}, nil); err != nil {\n        w.WriteHeader(http.StatusBadRequest)\n        return\n    }\n    // ...\n}\n",[283,1143,1144,1156,1160,1199,1218,1230,1241,1246,1250,1254,1277,1309,1317,1321,1325,1330],{"__ignoreMap":298},[302,1145,1146,1148,1151,1154],{"class":304,"line":305},[302,1147,379],{"class":362},[302,1149,1150],{"class":312}," \"",[302,1152,1153],{"class":308},"github.com/CredenShare/credenshare-sdk-go/webhooks",[302,1155,395],{"class":312},[302,1157,1158],{"class":304,"line":369},[302,1159,373],{"emptyLinePlaceholder":372},[302,1161,1162,1164,1167,1169,1172,1175,1177,1180,1182,1185,1188,1191,1193,1196],{"class":304,"line":376},[302,1163,450],{"class":362},[302,1165,1166],{"class":308}," handler",[302,1168,480],{"class":382},[302,1170,1171],{"class":1027},"w",[302,1173,1174],{"class":308}," http",[302,1176,559],{"class":382},[302,1178,1179],{"class":308},"ResponseWriter",[302,1181,768],{"class":382},[302,1183,1184],{"class":1027},"r",[302,1186,1187],{"class":362}," *",[302,1189,1190],{"class":308},"http",[302,1192,559],{"class":382},[302,1194,1195],{"class":308},"Request",[302,1197,1198],{"class":382},") {\n",[302,1200,1201,1204,1206,1209,1212,1215],{"class":304,"line":386},[302,1202,1203],{"class":382},"    body, err ",[302,1205,465],{"class":362},[302,1207,1208],{"class":382}," io.",[302,1210,1211],{"class":308},"ReadAll",[302,1213,1214],{"class":382},"(r.Body)   ",[302,1216,1217],{"class":696},"// the RAW bytes, before any decoding\n",[302,1219,1220,1222,1224,1226,1228],{"class":304,"line":398},[302,1221,498],{"class":362},[302,1223,501],{"class":382},[302,1225,504],{"class":362},[302,1227,507],{"class":489},[302,1229,510],{"class":382},[302,1231,1232,1235,1238],{"class":304,"line":408},[302,1233,1234],{"class":382},"        w.",[302,1236,1237],{"class":308},"WriteHeader",[302,1239,1240],{"class":382},"(http.StatusBadRequest)\n",[302,1242,1243],{"class":304,"line":418},[302,1244,1245],{"class":362},"        return\n",[302,1247,1248],{"class":304,"line":423},[302,1249,525],{"class":382},[302,1251,1252],{"class":304,"line":436},[302,1253,373],{"emptyLinePlaceholder":372},[302,1255,1256,1258,1260,1262,1265,1268,1271,1274],{"class":304,"line":442},[302,1257,498],{"class":362},[302,1259,501],{"class":382},[302,1261,465],{"class":362},[302,1263,1264],{"class":382}," webhooks.",[302,1266,1267],{"class":308},"Verify",[302,1269,1270],{"class":382},"(body, r.Header.",[302,1272,1273],{"class":308},"Get",[302,1275,1276],{"class":382},"(webhooks.SignatureHeader),\n",[302,1278,1279,1282,1285,1288,1290,1292,1295,1298,1300,1303,1305,1307],{"class":304,"line":447},[302,1280,1281],{"class":382},"        []",[302,1283,1284],{"class":362},"string",[302,1286,1287],{"class":382},"{os.",[302,1289,477],{"class":308},[302,1291,480],{"class":382},[302,1293,1294],{"class":312},"\"WEBHOOK_SECRET\"",[302,1296,1297],{"class":382},")}, ",[302,1299,490],{"class":489},[302,1301,1302],{"class":382},"); err ",[302,1304,504],{"class":362},[302,1306,507],{"class":489},[302,1308,510],{"class":382},[302,1310,1311,1313,1315],{"class":304,"line":459},[302,1312,1234],{"class":382},[302,1314,1237],{"class":308},[302,1316,1240],{"class":382},[302,1318,1319],{"class":304,"line":495},[302,1320,1245],{"class":362},[302,1322,1323],{"class":304,"line":513},[302,1324,525],{"class":382},[302,1326,1327],{"class":304,"line":522},[302,1328,1329],{"class":696},"    // ...\n",[302,1331,1332],{"class":304,"line":528},[302,1333,703],{"class":382},[265,1335,1336,1339,1340,1343],{},[278,1337,1338],{},"Verify the raw body."," Read it with ",[283,1341,1342],{},"io.ReadAll"," and verify those bytes. Re-serialising decoded JSON changes them — key order, spacing, escapes — and the signature will not match.",[265,1345,1346,1349],{},[278,1347,1348],{},"Pass both secrets while rotating."," For 24 hours after a rotation, deliveries carry both signatures:",[293,1351,1353],{"className":353,"code":1352,"language":309,"meta":298,"style":298},"webhooks.Verify(body, header, []string{newSecret, oldSecret}, nil)\n",[283,1354,1355],{"__ignoreMap":298},[302,1356,1357,1360,1362,1365,1367,1370,1372],{"class":304,"line":305},[302,1358,1359],{"class":382},"webhooks.",[302,1361,1267],{"class":308},[302,1363,1364],{"class":382},"(body, header, []",[302,1366,1284],{"class":362},[302,1368,1369],{"class":382},"{newSecret, oldSecret}, ",[302,1371,490],{"class":489},[302,1373,439],{"class":382},[265,1375,1376,1378,1379,1381,1382,1385,1386,1389],{},[283,1377,1267],{}," returns only an ",[283,1380,1042],{},". A ",[283,1383,1384],{},"(bool, error)"," signature invites ",[283,1387,1388],{},"ok, _ := Verify(...)",", and a receiver that ignores the error accepts everything while looking like it checks.",[265,1391,1392,1393,1396,1397,1400,1401,1404,1405,1408,1409,1412,1413,1416],{},"The header name is ",[283,1394,1395],{},"webhooks.SignatureHeader"," and the ±5-minute window is ",[283,1398,1399],{},"webhooks.DefaultTolerance",". ",[283,1402,1403],{},"Options.Tolerance"," is a ",[283,1406,1407],{},"*time.Duration",", so nil means the default and zero genuinely means zero: use ",[283,1410,1411],{},"webhooks.ToleranceOf(30 * time.Second)"," for a custom window, or ",[283,1414,1415],{},"webhooks.NoTolerance()"," to demand an exact timestamp.",[288,1418,1420],{"id":1419},"configuration","Configuration",[293,1422,1424],{"className":353,"code":1423,"language":309,"meta":298,"style":298},"client, err := credenshare.New(credential, &credenshare.Options{\n    BaseURL:    \"https://api.credenshare.io/v1\",\n    LinkOrigin: \"https://crs.sh\",\n    HTTPClient: myClient,\n    MaxRetries: credenshare.Retries(2),\n    Timeout:    30 * time.Second,\n})\n",[283,1425,1426,1452,1462,1472,1477,1493,1506],{"__ignoreMap":298},[302,1427,1428,1431,1433,1435,1437,1440,1443,1445,1447,1450],{"class":304,"line":305},[302,1429,1430],{"class":382},"client, err ",[302,1432,465],{"class":362},[302,1434,468],{"class":382},[302,1436,471],{"class":308},[302,1438,1439],{"class":382},"(credential, ",[302,1441,1442],{"class":362},"&",[302,1444,556],{"class":308},[302,1446,559],{"class":382},[302,1448,1449],{"class":308},"Options",[302,1451,565],{"class":382},[302,1453,1454,1457,1460],{"class":304,"line":369},[302,1455,1456],{"class":382},"    BaseURL:    ",[302,1458,1459],{"class":312},"\"https://api.credenshare.io/v1\"",[302,1461,577],{"class":382},[302,1463,1464,1467,1470],{"class":304,"line":376},[302,1465,1466],{"class":382},"    LinkOrigin: ",[302,1468,1469],{"class":312},"\"https://crs.sh\"",[302,1471,577],{"class":382},[302,1473,1474],{"class":304,"line":386},[302,1475,1476],{"class":382},"    HTTPClient: myClient,\n",[302,1478,1479,1482,1485,1487,1490],{"class":304,"line":398},[302,1480,1481],{"class":382},"    MaxRetries: credenshare.",[302,1483,1484],{"class":308},"Retries",[302,1486,480],{"class":382},[302,1488,1489],{"class":489},"2",[302,1491,1492],{"class":382},"),\n",[302,1494,1495,1498,1501,1503],{"class":304,"line":408},[302,1496,1497],{"class":382},"    Timeout:    ",[302,1499,1500],{"class":489},"30",[302,1502,1187],{"class":362},[302,1504,1505],{"class":382}," time.Second,\n",[302,1507,1508],{"class":304,"line":418},[302,1509,922],{"class":382},[265,1511,1512,1515,1516,1518,1519,1522],{},[283,1513,1514],{},"LinkOrigin"," changes only the links ",[283,1517,544],{}," hands back; it is never sent to the API. The SDK reads no environment variables — ",[283,1520,1521],{},"os.Getenv"," above is your own read.",[265,1524,1525,1528,1529,1532,1533,1536],{},[283,1526,1527],{},"Options.Timeout"," sets the per-attempt timeout, defaulting to ",[283,1530,1531],{},"credenshare.DefaultTimeout"," (30 seconds). It also applies to an ",[283,1534,1535],{},"HTTPClient"," you supply that has no timeout of its own; one that already sets a timeout keeps it.",[288,1538,1540],{"id":1539},"rough-edges","Rough edges",[265,1542,1543],{},"Real behaviour worth knowing before it surprises you.",[1545,1546,1547,1570,1606,1629,1641,1647,1667,1676,1693],"ul",{},[1548,1549,1550,1555,1556,342,1558,1560,1561,1563,1564,1567,1568,559],"li",{},[278,1551,1552,1554],{},[283,1553,590],{}," is no longer comparable."," The overflow map that preserves optional members means ",[283,1557,824],{},[283,1559,827],{}," stop compiling. ",[283,1562,831],{}," replaces ",[283,1565,1566],{},"==","; key maps on ",[283,1569,741],{},[1548,1571,1572,1578,1579,768,1581,768,1584,1587,1588,1591,1592,1595,1596,1599,1600,342,1603,559],{},[278,1573,1574,1577],{},[283,1575,1576],{},"errors.Is(err, ErrAPI)"," matches every refusal",", and the specific sentinels — ",[283,1580,1133],{},[283,1582,1583],{},"ErrRateLimited",[283,1585,1586],{},"ErrIdempotencyConflict"," and the rest — still match through ",[283,1589,1590],{},"Unwrap",". Use ",[283,1593,1594],{},"errors.As"," for ",[283,1597,1598],{},"*credenshare.APIError"," when you want to read ",[283,1601,1602],{},".Status",[283,1604,1605],{},".Code",[1548,1607,1608,1611,1612,1615,1616,1619,1620,1622,1623,1626,1627,559],{},[278,1609,1610],{},"The idempotency key is generated per call and never surfaced."," It protects a same-process network retry, which the client performs itself. It does not protect a ",[793,1613,1614],{},"re-run"," — a job that crashes after POSTing generates a fresh key next time and mints a second copy of the secret. Set ",[283,1617,1618],{},"IdempotencyKey"," yourself if you need that, and note that doing so does not make a second ",[283,1621,544],{}," a no-op: salt and IV are fresh per call, so the body differs and the API answers ",[283,1624,1625],{},"409"," with ",[283,1628,1586],{},[1548,1630,1631,1636,1637,1640],{},[278,1632,1633,1635],{},[283,1634,1013],{}," can fail for a paging reason."," Ask for page 3, get a response claiming page 1, and it stops with an error wrapping ",[283,1638,1639],{},"ErrAPI"," rather than looping. It otherwise walks until a page comes back short, or until the reported total is reached — unlike Node, Python and Rust it carries no absolute page ceiling, which only matters against a server that returns full pages indefinitely.",[1548,1642,1643,1646],{},[278,1644,1645],{},"Only network failures are retried",", never an HTTP status. A 500 is surfaced because it may have committed.",[1548,1648,1649,1658,1659,1662,1663,1666],{},[278,1650,1651,1654,1655],{},[283,1652,1653],{},"ErrServiceUnavailable"," is now only a genuine ",[283,1656,1657],{},"503"," — the API answering that nothing was created, safe to retry. Exhausted transport retries wrap ",[283,1660,1661],{},"ErrDeliveryUnknown"," instead, because ",[283,1664,1665],{},"Do"," returns once headers arrive, so a failure after that can still mean the request was processed.",[1548,1668,1669,1675],{},[278,1670,1671,1674],{},[283,1672,1673],{},"ErrAuthentication"," is narrower than it sounds."," A revoked or unknown credential arrives as HTTP 403 and therefore as the permission error.",[1548,1677,1678,1684,1685,1688,1689,1692],{},[278,1679,1680,1683],{},[283,1681,1682],{},"ReadLink"," always fails"," — by design, since the recipient path is guarded by proof-of-work and captcha checks bearer auth would skip. It wraps ",[283,1686,1687],{},"credenshare.ErrNotSupported",", so ",[283,1690,1691],{},"errors.Is"," matches it.",[1548,1694,1695,1698],{},[278,1696,1697],{},"A webhook secret with a trailing newline fails."," The blank check trims, but the HMAC is keyed with the untrimmed string. Go, Python and Rust behave this way — trim it yourself. Node now refuses such a secret by name.",[288,1700,1702],{"id":1701},"checking-your-build","Checking your build",[265,1704,1705],{},"From your own module, with nothing cloned:",[293,1707,1709],{"className":295,"code":1708,"language":297,"meta":298,"style":298},"go run github.com/CredenShare/credenshare-sdk-go/cmd/credenshare-conformance@latest\n# 24 passed. This installation conforms to the wire specification.\n",[283,1710,1711,1721],{"__ignoreMap":298},[302,1712,1713,1715,1718],{"class":304,"line":305},[302,1714,309],{"class":308},[302,1716,1717],{"class":312}," run",[302,1719,1720],{"class":312}," github.com/CredenShare/credenshare-sdk-go/cmd/credenshare-conformance@latest\n",[302,1722,1723],{"class":304,"line":369},[302,1724,1725],{"class":696},"# 24 passed. This installation conforms to the wire specification.\n",[265,1727,1728,1729,1732,1733,1736,1737,1740,1741,559],{},"Inside a clone of the repository, ",[283,1730,1731],{},"go run ./cmd/credenshare-conformance"," does the same thing. Add ",[283,1734,1735],{},"-v"," for one line per vector. The fixture is embedded with ",[283,1738,1739],{},"//go:embed",", so it travels with the compiled binary; the command exits non-zero on failure and works as a deployment gate. See ",[268,1742,242],{"href":243},[1744,1745,1746],"style",{},"html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}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);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"title":298,"searchDepth":305,"depth":369,"links":1748},[1749,1750,1751,1752,1753,1754,1755,1756,1757],{"id":290,"depth":369,"text":291},{"id":349,"depth":369,"text":350},{"id":735,"depth":369,"text":736},{"id":841,"depth":369,"text":842},{"id":950,"depth":369,"text":951},{"id":1137,"depth":369,"text":1138},{"id":1419,"depth":369,"text":1420},{"id":1539,"depth":369,"text":1540},{"id":1701,"depth":369,"text":1702},"The official Go client — encrypts locally, assembles the link, verifies webhooks. Standard library only.","md",{},{"title":234,"description":1758},"2FIz3k3TYzYJcej7KoSzJOg5-BKTSZNaBxZf19ykeU0",[1764,1766],{"title":230,"path":231,"stem":232,"description":1765,"children":-1},"The official Python client — encrypts locally, assembles the link, verifies webhooks. Python 3.9+, two dependencies.",{"title":238,"path":239,"stem":240,"description":1767,"children":-1},"The official Rust client — encrypts locally, assembles the link, verifies webhooks. Crypto usable without the HTTP stack.",1788908851307]