Skip to content

docs: clarify Idempotency-Key is only honored on audit log event creation#128

Open
workos-tars[bot] wants to merge 2 commits into
mainfrom
docs/scope-idempotency-key-to-audit-logs
Open

docs: clarify Idempotency-Key is only honored on audit log event creation#128
workos-tars[bot] wants to merge 2 commits into
mainfrom
docs/scope-idempotency-key-to-audit-logs

Conversation

@workos-tars

@workos-tars workos-tars Bot commented Jul 20, 2026

Copy link
Copy Markdown

Summary

The WorkOS API only deduplicates requests carrying an Idempotency-Key header on POST /audit_logs/events (Create Audit Log Event). The README previously presented idempotency keys as a general capability on arbitrary mutations (e.g. organization creation), so a client that retried a mutation with the same key could still create a duplicate — as reported publicly by a user who retried POST /organizations and got two organizations.

Rewrites the Per-Request Options example to use audit_logs().create_event_with_options (the one endpoint where the key is honored), updates the Request Strategies and Retries sections to note the server-side scoping, and adds an explicit callout.

This README is synced to workos.com/docs SDK pages by the sync-sdk-readmes workflow, so the fix propagates to the public docs on the next sync.

Part of a coordinated docs fix across workos-rust, workos-ruby, workos-python, workos-kotlin, workos-go, and workos-dotnet.

Test plan

Docs-only change; rendered the Markdown and verified the referenced SDK methods exist in this repo.

…tion

The WorkOS API only deduplicates requests carrying an Idempotency-Key on
POST /audit_logs/events. The README previously implied the key was honored
on arbitrary mutations (e.g. organization creation), which could lead
callers to retry mutations expecting server-side deduplication that does
not happen. Scope the examples and prose to the Audit Logs endpoint and
call out the limitation explicitly.
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR is a coordinated documentation-only fix clarifying that the WorkOS API only deduplicates requests on the POST /audit_logs/events endpoint — not on arbitrary mutations — to prevent users from believing a retried POST /organizations (or similar) with the same idempotency key is safe.

  • README.md: Per-Request Options example replaced with audit_logs().create_event_with_options, idempotency-key scope callout added, Retries section updated, feature table corrected (removes phantom reqwest feature row), version specifier updated from \"1\" to \"2\".
  • src/client.rs: Doc comments for RequestStrategy::Idempotent, RequestOptions::idempotency_key, and ClientBuilder::build updated to reflect actual behavior (panic on invalid header bytes; server-side deduplication scope narrowed to audit log events).
  • src/lib.rs / src/transport.rs: Module-level doc comments aligned with the current feature flag layout.

Confidence Score: 5/5

Safe to merge — all changes are documentation and doc comment corrections with no logic changes.

Every changed line is a comment, doc string, or README update. The technical claims were verified against the source: connection_type field name is correct, build() does panic on invalid header bytes, the crate is on version 2.x, and the reqwest feature is now implicit behind rustls-tls/native-tls. No runtime behavior is affected.

README.md — the new Per-Request Options code snippet references an undeclared event variable (flagged in an earlier review thread).

Important Files Changed

Filename Overview
README.md Documentation-only updates clarifying idempotency-key scope, fixing the Per-Request Options example to use audit_logs, updating feature table, and correcting field references; the code example still references an undeclared event variable (flagged in a previous review thread).
src/client.rs Doc comment updates only: narrows the idempotency-key guarantee in RequestStrategy::Idempotent and RequestOptions::idempotency_key, and replaces the misleading 'silently dropped' wording in ClientBuilder::build with an accurate # Panics section that matches the actual unwrap implementation.
src/lib.rs Module-level doc comment updated to correctly describe the transport feature flags (rustls-tls/native-tls) and bumps the example version specifier from "1" to "2", matching the crate's current 2.5.0 version.
src/transport.rs Minor doc comment correction aligning the feature gate description with the actual Cargo.toml feature layout (rustls-tls and native-tls instead of the old reqwest feature name).

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant App
    participant SDK
    participant WorkOS API

    Note over App,WorkOS API: Audit Log Event (idempotency honored)
    App->>SDK: create_event_with_options(..., idempotency_key)
    SDK->>WorkOS API: POST /audit_logs/events + Idempotency-Key header
    WorkOS API-->>SDK: 200 OK (deduplicated on retry)
    SDK-->>App: Ok(response)

    Note over App,WorkOS API: Other mutations (idempotency NOT honored)
    App->>SDK: create_organization_with_options(..., idempotency_key)
    SDK->>WorkOS API: POST /organizations + Idempotency-Key header
    WorkOS API-->>SDK: 201 Created (duplicate on retry!)
    SDK-->>App: Ok(response)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant App
    participant SDK
    participant WorkOS API

    Note over App,WorkOS API: Audit Log Event (idempotency honored)
    App->>SDK: create_event_with_options(..., idempotency_key)
    SDK->>WorkOS API: POST /audit_logs/events + Idempotency-Key header
    WorkOS API-->>SDK: 200 OK (deduplicated on retry)
    SDK-->>App: Ok(response)

    Note over App,WorkOS API: Other mutations (idempotency NOT honored)
    App->>SDK: create_organization_with_options(..., idempotency_key)
    SDK->>WorkOS API: POST /organizations + Idempotency-Key header
    WorkOS API-->>SDK: 201 Created (duplicate on retry!)
    SDK-->>App: Ok(response)
Loading

Reviews (2): Last reviewed commit: "docs: fix README inaccuracies found in a..." | Re-trigger Greptile

Comment thread README.md
Comment on lines +113 to 126
let opts = RequestOptions::new().idempotency_key("51343ada-3f0f-4372-9d24-4d0b0dfba384");

let org = client
.organizations()
.create_organization_with_options(
CreateOrganizationParams::new(workos::OrganizationInput {
name: "Acme".into(),
..Default::default()
let response = client
.audit_logs()
.create_event_with_options(
CreateEventParams::new(workos::AuditLogEventIngestion {
organization_id: "org_01EHZNVPK3SFK441A1RGBFSHRT".into(),
event,
}),
Some(&opts),
)
.await?;
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Undefined event variable in code snippet

The new example references event inside the AuditLogEventIngestion struct literal, but event is never declared or initialized in the snippet. The original example was fully self-contained (using ..Default::default() to fill optional fields); this replacement leaves event dangling. A reader who copies the snippet as-is will get a compile error. Consider either initializing event inline (e.g. with a minimal AuditLogEvent { .. } struct literal) or adding a // let event = …; comment stub before the let opts = … line to make the intent clear.

Prompt To Fix With AI
This is a comment left during a code review.
Path: README.md
Line: 113-126

Comment:
**Undefined `event` variable in code snippet**

The new example references `event` inside the `AuditLogEventIngestion` struct literal, but `event` is never declared or initialized in the snippet. The original example was fully self-contained (using `..Default::default()` to fill optional fields); this replacement leaves `event` dangling. A reader who copies the snippet as-is will get a compile error. Consider either initializing `event` inline (e.g. with a minimal `AuditLogEvent { .. }` struct literal) or adding a `// let event = …;` comment stub before the `let opts = …` line to make the intent clear.

How can I resolve this? If you propose a fix, please make it concise.

@workos-tars

workos-tars Bot commented Jul 20, 2026

Copy link
Copy Markdown
Author

Assessed the rest of the README against the codebase per the Slack thread. Fixes pushed in the follow-up commit:

  • Non-existent reqwest Cargo feature referenced in three places — Cargo.toml only defines rustls-tls (default) and native-tls, both of which pull in the bundled reqwest transport. Fixed the prose and feature table (also fixed the same stale phrasing in src/lib.rs and src/transport.rs rustdoc).
  • Stale dependency snippet workos = { version = "1", ... } — crate is at 2.5.0; bumped to "2" (also in src/lib.rs).
  • Example didn't compile: connection.r#typeconnection.connection_type.
  • "List endpoints return Page<T>" — most return generated *List types; only a handful return Page<T>. Reworded.
  • "enums include Unknown(String)" — three enums use Unrecognized(String) because the API defines a literal unknown value. Reworded.
  • "Every list endpoint generates a *_auto_paging companion" — 8 non-cursor-paginated list methods have none. Scoped to cursor-paginated endpoints.
  • Rustdoc contradicted this PR: RequestStrategy::Idempotent and RequestOptions::idempotency_key docs in src/client.rs still claimed general server-side dedup; scoped them to audit log event creation. Also fixed the build() rustdoc that said invalid header bytes are "silently dropped" when the code panics.
  • Minor: Changelog link now points to GitHub (CHANGELOG.md is excluded from the published package); Debug prints SecretString("<redacted>"), not bare "<redacted>".

All source changes are doc-comment-only (verified no code lines touched).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

0 participants