{"components":{"headers":{"RateLimitLimit":{"description":"The request cap for the tighter of the per-organization / per-endpoint windows that applied to this request.","schema":{"examples":[50],"type":"integer"}},"RateLimitRemaining":{"description":"Requests remaining in the current window.","schema":{"examples":[49],"type":"integer"}},"RateLimitReset":{"description":"Unix timestamp (seconds) when the current window resets.","schema":{"examples":[1713601200],"type":"integer"}},"RetryAfter":{"description":"Seconds the client should wait before retrying.","schema":{"examples":[30],"type":"integer"}}},"responses":{"Conflict":{"content":{"application/json":{"examples":{"default":{"value":{"error":{"code":"conflict","message":"client is already deleted"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request conflicts with the current state of the resource."},"Forbidden":{"content":{"application/json":{"examples":{"default":{"value":{"error":{"code":"forbidden","message":"activity is immutable; only manual activities can be edited"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource exists and belongs to your organization, but the requested\noperation is not permitted on it — e.g. editing an external-source\n(immutable) activity. Distinct from 404, which hides cross-tenant\nexistence.\n"},"InvalidArgument":{"content":{"application/json":{"examples":{"default":{"value":{"error":{"code":"invalid_argument","message":"limit must be an integer between 1 and 100"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request body / query parameters failed validation."},"NotFound":{"content":{"application/json":{"examples":{"default":{"value":{"error":{"code":"not_found","message":"client not found"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The referenced resource does not exist, or belongs to a different\norganization than the one owning the API key. The public API does not\ndistinguish between these cases — both return 404 to avoid leaking\ncross-tenant existence.\n"},"RateLimited":{"content":{"application/json":{"examples":{"default":{"value":{"error":{"code":"rate_limited","details":{"retry_after_seconds":30},"message":"Rate limit exceeded"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Per-organization or per-endpoint rate limit exceeded.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}}},"Unauthorized":{"content":{"application/json":{"examples":{"default":{"value":{"error":{"code":"unauthorized","message":"Authentication required"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Missing or invalid bearer token. The message is intentionally opaque — do not rely on it to distinguish \"missing\" from \"invalid\"."}},"schemas":{"Activity":{"description":"A communication event linked to a client. Projected from Salfio's\nConversation + messages + conversation_clients model family.\n\nThe `clientId` is the \"primary\" client derived from the junction\ntable — a conversation linked to multiple clients is surfaced once\nper linked client (from the list endpoints of each).\n\n`content` is the full concatenated body of all messages on the\nconversation, joined by `\\n\\n---\\n\\n` — single-resource GETs never\ntruncate it. It is returned only on single-resource GETs; list\nendpoints omit it for response-size reasons. Webhook delivery\npayloads cap `content` at 10 KiB (with a\n`[content truncated at 10 KiB]` marker) — fetch the activity by ID\nwhen you need the full text.\n\n`immutable` is derived server-side: non-`manual` sources are always\nimmutable on the v1 surface (per the spec source/operation matrix).\n","properties":{"archivedAt":{"format":"date-time","type":["null","string"]},"clientId":{"format":"uuid","type":"string"},"content":{"description":"Full concatenated message bodies (single-resource GETs only; capped at 10 KiB in webhook deliveries).","type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"immutable":{"description":"True when the activity's source prevents it from being edited or hard-deleted via the API.","type":"boolean"},"occurredAt":{"format":"date-time","type":"string"},"participants":{"items":{"format":"email","type":"string"},"type":"array"},"source":{"enum":["manual","gmail","outlook","fireflies"],"type":"string"},"subject":{"type":["null","string"]},"type":{"enum":["email","meeting","note","chat"],"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["clientId","content","createdAt","id","immutable","occurredAt","participants","source","type","updatedAt"],"type":"object"},"ActivityCreate":{"description":"Request body for creating a manual activity. The server forces `source`\nto `manual`; when present it must equal `manual`.\n","properties":{"content":{"description":"Free-text body, stored as the activity's single message. Optional.","type":"string"},"occurredAt":{"description":"When the activity occurred. Defaults to now when omitted.","format":"date-time","type":"string"},"participants":{"description":"Email-only participant list (no display names, no contact linking).","items":{"format":"email","type":"string"},"type":"array"},"source":{"description":"Optional; must be `manual` if provided. The server forces `manual` regardless.","enum":["manual"],"type":"string"},"subject":{"type":["null","string"]},"type":{"enum":["email","meeting","note","chat"],"type":"string"}},"required":["type"],"type":"object"},"ActivityUpdate":{"description":"Request body for editing a manual activity. All fields optional; omitted\nfields are left unchanged. `participants`, when present, fully replaces\nthe existing list.\n","properties":{"content":{"type":"string"},"participants":{"items":{"format":"email","type":"string"},"type":"array"},"subject":{"type":["null","string"]},"type":{"enum":["email","meeting","note","chat"],"type":"string"}},"type":"object"},"AssignmentRule":{"description":"A client's assignment rule for a single integration. One is returned per\nactive integration; `ruleId` and the other rule fields are `null` when no\nrule is configured for the client on that integration yet.\n","properties":{"chatLabels":{"additionalProperties":{"type":"string"},"description":"Only on read-only WhatsApp entries — maps the chat JIDs referenced\nby `filterCriteria` to display names taken from synced\nconversations. A ruled chat that never synced a message has no\nentry.\n","type":"object"},"createdAt":{"description":"UTC timestamp when the rule was created (`null` when none is set).","format":"date-time","type":["null","string"]},"enabled":{"description":"Whether the rule is active.","type":"boolean"},"filterCriteria":{"anyOf":[{"description":"The rich querybuilder criteria deciding which of the integration's\ncommunications are assigned to the client; `null` when no rule is\nset. For Slack, a channel binding looks like\n`{\"condition\":\"or\",\"rules\":[{\"field\":\"channel\",\"operator\":\"equals\",\"value\":\"general\"}]}`.\n"},{"type":"null"}]},"integrationId":{"description":"The integration this rule binds to the client. Pass it back in a PUT to configure the rule.","format":"uuid","type":"string"},"integrationType":{"description":"Provider of the bound integration (e.g. `slack`, `gmail`).","examples":["slack"],"type":"string"},"priority":{"description":"Rule ordering (lower number = higher priority).","type":"integer"},"providerEmail":{"description":"The account/email the integration authenticates as.","type":"string"},"readOnly":{"description":"The caller may not write this rule — the integration is\nconfigurable only by the user who connected it (WhatsApp). Never\ninclude a read-only entry in a PUT replacement set; writing one is\nrejected. User-authenticated callers still see the rule's real\nvalues; callers with no user identity additionally get\n`rulesHidden: true` with the rule fields withheld.\n","type":"boolean"},"ruleId":{"description":"Stable UUID of the rule, or `null` when none is configured yet.","format":"uuid","type":["null","string"]},"rulesHidden":{"deprecated":true,"description":"The rule was withheld entirely because the caller carries no user\nidentity (org-scoped service keys): `ruleId` and `filterCriteria`\nare `null` and `enabled` is `false` regardless of what is\nconfigured — do not read such an entry as \"no rule yet\".\nDeprecated as the do-not-write signal in favor of `readOnly`,\nwhich also covers user-authenticated callers.\n","type":"boolean"},"updatedAt":{"description":"UTC timestamp of the most recent rule update (`null` when none is set).","format":"date-time","type":["null","string"]}},"required":["createdAt","enabled","filterCriteria","integrationId","integrationType","priority","providerEmail","ruleId","updatedAt"],"type":"object"},"CardFeedback":{"description":"Acknowledgement that a report was stored. There is no endpoint to\nread reports back; keep the `id` if you want to reference the\nreport when following up.\n","properties":{"createdAt":{"description":"Time the report was recorded.","format":"date-time","type":"string"},"id":{"description":"ID of the stored report.","format":"uuid","type":"string"}},"required":["createdAt","id"],"type":"object"},"CardFeedbackCreate":{"description":"A report that a card is wrong. `category` is required; everything\nelse is optional context.\n","properties":{"category":{"description":"What kind of problem this is.\n\n- `wrong_facts` — names, numbers or dates that don't match reality.\n- `speculative_deduction` — the facts are right, the conclusion isn't.\n- `wrong_language_or_format` — wrong language, currency, dates or layout.\n- `other` — anything else; pair it with `details`.\n","enum":["wrong_facts","speculative_deduction","wrong_language_or_format","other"],"examples":["wrong_facts"],"type":"string"},"details":{"description":"Optional free-text explanation of what is wrong. Anything longer than 5000 characters is rejected.","examples":["The renewal date is off by a month — the contract runs to March, not February."],"maxLength":5000,"type":"string"}},"required":["category"],"type":"object"},"Channel":{"description":"A Slack channel the workspace bot is a member of. The `name` is what you pass in `slackChannels`.","properties":{"id":{"description":"Slack's channel ID (e.g. `C0123ABCD`).","examples":["C0123ABCD"],"type":"string"},"isExtShared":{"description":"Whether the channel is shared with an external organization (Slack Connect).","type":"boolean"},"isPrivate":{"description":"Whether the channel is private.","type":"boolean"},"memberCount":{"description":"Number of members in the channel.","type":"integer"},"name":{"description":"Channel name without the leading `#` (e.g. `general`).","examples":["general"],"type":"string"}},"required":["id","isExtShared","isPrivate","memberCount","name"],"type":"object"},"Client":{"description":"A client record (partner's CRM account / customer). The fields\n`email`, `phone`, `company`, and `notes` from the v1.0 spec document\nare not yet populated — tracked as a follow-up.\n","properties":{"accountManagers":{"description":"Users assigned as account managers for this client. Peers — no\nprimary/secondary distinction. Always present; an empty array\nsignals no managers are assigned.\n","items":{"$ref":"#/components/schemas/UserSummary"},"type":"array"},"clientType":{"description":"Lifecycle stage of the client (status, not legal entity type).\n`prospect` → `active` → `churned` is the canonical progression.\nUse this to answer pipeline/status questions (\"who are my\nprospects?\", \"who has churned?\"). Defaults to `active` on\ncreation when the caller omits the field.\n","enum":["prospect","active","churned"],"examples":["active"],"type":"string"},"createdAt":{"description":"UTC timestamp when the client was created.","format":"date-time","type":"string"},"domain":{"description":"Primary email domain used to auto-assign communications (e.g. `acme.com`).","examples":["acme.com"],"type":["null","string"]},"id":{"description":"Stable UUID for this client.","examples":["8b2d1c4e-3f5a-4e2b-9c8f-1e2d3c4b5a6f"],"format":"uuid","type":"string"},"name":{"description":"Display name of the client.","examples":["Acme Corp"],"type":"string"},"updatedAt":{"description":"UTC timestamp of the most recent update.","format":"date-time","type":"string"}},"required":["accountManagers","clientType","createdAt","id","name","updatedAt"],"type":"object"},"ClientCard":{"description":"One AI-generated card for a client. Each card is the result of\nrunning an organization-level prompt against the client's\nrecent activities — the prompt and display position are\nconfigured by the organization's admins, the value is computed\nand refreshed by the Salfio worker.\n\n`value` is `null` until the worker has produced the first\nrendered output (the dashboard renders this as a \"generating…\"\nstate).\n\n`is_stale=true` means the underlying activities have changed\nsince the value was last computed — the value shown is the\nprevious one and a refresh is in flight. Polling will pick up\nthe new value once the worker finishes; reading this endpoint\nalso nudges the worker to prioritise the refresh.\n\n`last_update` is the wall-clock time the value was last\nwritten by the worker; `null` when no value has been produced\nyet.\n","properties":{"card_config_id":{"description":"ID of the parent card configuration this value was computed for. Shared across every client in the organization.","format":"uuid","type":"string"},"card_value_id":{"description":"ID of this client's instance of the card — the thing that\nholds `value`. Unlike `card_config_id`, which is shared by\nevery client using the same card definition, this is unique\nper client and per card. Pass it to\n`POST /cards/{cardValueId}/feedback` to report an issue with\nwhat you read here.\n","format":"uuid","type":"string"},"display_order":{"description":"Position the card occupies in the ordered list (lower values first). The base value is implementation-defined; rely on the relative ordering, not the absolute number.","examples":[1],"type":"integer"},"identifier":{"description":"Stable, machine-readable identifier of the card (e.g. `briefing`, `wins_traction`).","examples":["briefing"],"type":"string"},"is_stale":{"description":"True when the underlying activities have changed since `value` was last written. A refresh is enqueued automatically on read.","type":"boolean"},"last_update":{"description":"Time the worker last wrote `value`. `null` when no value has been produced yet.","format":"date-time","type":["null","string"]},"title":{"description":"Human-readable title configured for this card.","examples":["Briefing"],"type":"string"},"value":{"description":"Rendered Markdown value of the card. `null` until the worker has produced output.","type":["null","string"]}},"required":["card_config_id","card_value_id","display_order","identifier","is_stale","title"],"type":"object"},"CreateClientRequest":{"properties":{"accountManagerIds":{"description":"Optional initial set of account-manager user IDs. Each ID must\nreference a user in the caller's organization; cross-tenant\nassignment returns `400 invalid_argument` naming the offending ID.\n","items":{"format":"uuid","type":"string"},"type":"array"},"clientType":{"description":"Optional lifecycle stage at create-time. Omitted → defaults to\n`active`. Invalid values return `400 invalid_argument` naming\nthe offending value.\n","enum":["prospect","active","churned"],"examples":["prospect"],"type":"string"},"domain":{"description":"Primary email domain — used by the integration assignment-rule\nengine to auto-attach inbound communications to this client. When\nomitted, the rule engine does not auto-assign based on domain.\n","examples":["globex.com"],"type":"string"},"name":{"description":"Display name of the new client.","examples":["Globex"],"type":"string"}},"required":["name"],"type":"object"},"Envelope":{"properties":{"data":{"description":"The response payload — shape depends on the endpoint."},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"],"type":"object"},"ErrorEnvelope":{"properties":{"error":{"properties":{"code":{"description":"Machine-readable error category.","enum":["unauthorized","forbidden","not_found","invalid_argument","conflict","rate_limited","internal_error","not_implemented"],"type":"string"},"details":{"additionalProperties":true,"description":"Optional per-code context (field names, retry windows, …).","type":"object"},"message":{"description":"Human-readable description — intended for operator logs, not end-user display.","type":"string"}},"required":["code","message"],"type":"object"}},"required":["error"],"type":"object"},"Integration":{"description":"A connected integration in the organization.","properties":{"connectedAt":{"description":"UTC timestamp when the integration was connected.","format":"date-time","type":"string"},"connectionStatus":{"description":"Current connection state. Only `active` integrations can serve channel listings or sync.","enum":["active","disconnected","expired","error"],"type":"string"},"enabled":{"description":"Whether syncing is enabled for the integration.","type":"boolean"},"integrationId":{"description":"Stable UUID of the integration. Pass it when creating assignment rules or listing channels.","format":"uuid","type":"string"},"lastSyncedAt":{"description":"UTC timestamp of the last successful sync, or `null` if it has never synced.","format":"date-time","type":["null","string"]},"providerEmail":{"description":"The account/email the integration authenticates as.","type":"string"},"type":{"description":"Provider of the integration.","enum":["slack","gmail","fireflies","outlook","recallai","readai"],"examples":["slack"],"type":"string"}},"required":["connectedAt","connectionStatus","enabled","integrationId","lastSyncedAt","providerEmail","type"],"type":"object"},"Meta":{"description":"Pagination metadata — populated on list endpoints, empty on single-resource endpoints.","properties":{"cursor":{"description":"Opaque cursor to pass to the next request.","type":["null","string"]},"hasMore":{"description":"True when further pages of results are available.","type":["boolean","null"]}},"type":"object"},"NoteCreate":{"description":"Request body for creating a note (`POST /clients/{clientId}/notes`). The\nnote is stored as an activity of type \"note\". Only `content` is required.\n`content` is capped at 50,000 characters and `subject` at 500; exceeding\neither is rejected with `400 invalid_argument` (never a 500).\n","properties":{"authorUserId":{"description":"User to attribute the note to. Required for service-scoped keys\n(which carry no user); optional for user-scoped keys, where it\ndefaults to the authenticated user. Must be a member of your\norganization.\n","format":"uuid","type":"string"},"content":{"description":"The note body (plain text), stored as the note's single message. Up to 50,000 characters; a longer body is rejected with `400 invalid_argument`.","maxlength":50000,"type":"string"},"occurredAt":{"description":"The instant the note refers to. Defaults to now when omitted.","format":"date-time","type":"string"},"participants":{"description":"People present on the note besides the author; each is linked to (or created as) an org contact by email.","items":{"$ref":"#/components/schemas/NoteParticipant"},"type":"array"},"subject":{"description":"Optional short subject/title for the note. Up to 500 characters; a longer subject is rejected with `400 invalid_argument`.","maxLength":500,"type":["null","string"]}},"required":["content"],"type":"object"},"NoteParticipant":{"properties":{"email":{"format":"email","type":"string"},"name":{"description":"Optional display name for the participant.","type":"string"}},"required":["email"],"type":"object"},"Organization":{"description":"The caller's organization. `plan` and `rateLimits` currently return\nstubbed defaults (`\"free\"` and the system-wide caps); see the\ndescription on `GET /organization` for the gap.\n","properties":{"createdAt":{"format":"date-time","type":"string"},"defaultCurrency":{"description":"Three-letter ISO-4217 currency used for revenue displays.","examples":["EUR"],"type":"string"},"defaultTimezone":{"description":"IANA timezone used for report aggregation.","examples":["Europe/Amsterdam"],"type":"string"},"id":{"format":"uuid","type":"string"},"name":{"examples":["Acme Inc."],"type":"string"},"plan":{"description":"Billing plan. Read-only on the public API.","examples":["free"],"type":"string"},"rateLimits":{"$ref":"#/components/schemas/RateLimits"},"slug":{"description":"URL-friendly short identifier. Read-only on the public API.","examples":["acme"],"type":["null","string"]},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","defaultCurrency","defaultTimezone","id","name","plan","rateLimits","updatedAt"],"type":"object"},"RateLimits":{"description":"Rate-limit caps applying to the organization. Currently reflects the\nsystem defaults; per-organization overrides are a tracked follow-up.\n","properties":{"endpointPerMinute":{"description":"Requests per minute for any single endpoint.","examples":[50],"type":"integer"},"organizationPerMinute":{"description":"Requests per minute across the entire organization.","examples":[100],"type":"integer"}},"required":["endpointPerMinute","organizationPerMinute"],"type":"object"},"ReapplyAssignmentRulesStats":{"description":"How a save re-evaluated the client's existing conversations against the new rule set.","properties":{"assignmentsCreated":{"type":"integer"},"assignmentsRemoved":{"type":"integer"},"conversationsEvaluated":{"type":"integer"},"conversationsMatched":{"type":"integer"}},"type":"object"},"SaveAssignmentRuleInput":{"description":"A single rule to upsert. Provide at most one of `filterCriteria` or\n`slackChannels`.\n","properties":{"enabled":{"default":true,"description":"Whether the rule is active. Defaults to `true` when omitted — so when\nupdating via GET-then-PUT, echo the rule's current `enabled` to\npreserve it; omitting it re-enables a currently-disabled rule.\n","type":"boolean"},"filterCriteria":{"description":"Raw rich querybuilder criteria (`{condition, rules}`). Use instead of\n`slackChannels` for full control or for non-Slack integrations.\n"},"integrationId":{"description":"The integration to bind to the client.","format":"uuid","type":"string"},"slackChannels":{"description":"Convenience shorthand — Slack channel names (with or without a\nleading `#`) to bind to the client. The server expands these into the\nmatching criteria. Only valid on a Slack integration; mutually\nexclusive with `filterCriteria`.\n","examples":[["general","acme-project"]],"items":{"type":"string"},"type":"array"}},"required":["integrationId"],"type":"object"},"SaveAssignmentRulesRequest":{"description":"Full replacement set of a client's assignment rules.","properties":{"rules":{"description":"The complete rule set. Integrations omitted here have their rule removed; an empty array clears all rules.","items":{"$ref":"#/components/schemas/SaveAssignmentRuleInput"},"type":"array"}},"required":["rules"],"type":"object"},"SaveAssignmentRulesResponse":{"properties":{"reapplyStats":{"anyOf":[{"allOf":[{"$ref":"#/components/schemas/ReapplyAssignmentRulesStats"}],"description":"Summary of how the save re-evaluated the client's conversations. May be `null` if the re-apply could not run."},{"type":"null"}]},"rules":{"items":{"$ref":"#/components/schemas/AssignmentRule"},"type":"array"}},"required":["rules"],"type":"object"},"UpdateClientRequest":{"description":"PATCH-style update — only the fields present in the body are touched.\nAny unknown fields are ignored.\n","properties":{"accountManagerIds":{"description":"Full-replacement set of account-manager user IDs. Omit to leave\nthe existing assignments untouched. Pass an empty array to clear\nall assignments. Pass a populated array to replace the entire\nassignment set. Each ID is validated for org membership;\ncross-tenant assignment returns `400 invalid_argument` with the\noffending ID in the message.\n","items":{"format":"uuid","type":"string"},"type":"array"},"clientType":{"description":"Optional new lifecycle stage. Omit to leave the stored value\nuntouched (no silent default on update). Invalid values return\n`400 invalid_argument` naming the offending value.\n","enum":["prospect","active","churned"],"examples":["churned"],"type":"string"},"domain":{"description":"New email domain. Passing an empty string clears the domain.","type":"string"},"name":{"description":"New display name.","type":"string"}},"type":"object"},"UpdateOrganizationRequest":{"description":"PATCH-style update. Only `name`, `defaultTimezone`, and\n`defaultCurrency` are writable. `plan` and `slug` in the body are\nexplicitly rejected with `400 invalid_argument`.\n","properties":{"defaultCurrency":{"type":"string"},"defaultTimezone":{"type":"string"},"name":{"type":"string"}},"type":"object"},"UpdateUserRequest":{"description":"PATCH-style update. Only the listed whitelisted fields are applied;\nany other field (including `email`, `clerkUserId`, `id`, etc.) is\nsilently ignored.\n","properties":{"firstName":{"type":"string"},"imageUrl":{"format":"uri","type":"string"},"lastName":{"type":"string"}},"type":"object"},"User":{"description":"Organization user. Identity-bound fields (`email`) are readable but\nnot writable via this API — identity is owned upstream. The spec\nmentions `phone`, but the current user model does not carry one —\ntracked as a follow-up.\n","properties":{"createdAt":{"format":"date-time","type":"string"},"email":{"description":"Read-only on this API surface.","examples":["alice@acme.com"],"format":"email","type":"string"},"firstName":{"examples":["Alice"],"type":"string"},"id":{"format":"uuid","type":"string"},"imageUrl":{"format":"uri","type":["null","string"]},"lastName":{"examples":["Morgan"],"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","email","firstName","id","lastName","updatedAt"],"type":"object"},"UserSummary":{"description":"Minimal user identity surfaced on client records.","properties":{"email":{"format":"email","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"userId":{"description":"Stable UUID for this user.","format":"uuid","type":"string"}},"required":["email","firstName","lastName","userId"],"type":"object"}},"securitySchemes":{"bearerAuth":{"description":"Salfio API token using the documented sk_live_ format.","scheme":"bearer","type":"http"}}},"info":{"title":"Salfio Public API","version":"v1"},"openapi":"3.1.0","paths":{"/cards/{cardValueId}/feedback":{"post":{"description":"$26","operationId":"createCardFeedback","parameters":[{"description":"Card value UUID.","in":"path","name":"cardValueId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardFeedbackCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/CardFeedback"}},"type":"object"}]}}},"description":"The report was stored.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Report an issue with a card","tags":["cards"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Post, \"https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback\");\nrequest.Content = new StringContent(\"{\\\"category\\\":\\\"wrong_facts\\\",\\\"details\\\":\\\"The renewal date is off by a month — the contract runs to March, not February.\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X POST 'https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"category\":\"wrong_facts\",\"details\":\"The renewal date is off by a month — the contract runs to March, not February.\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"category\":\"wrong_facts\",\"details\":\"The renewal date is off by a month — the contract runs to March, not February.\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"POST\", \"https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback\"))\n    .method(\"POST\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"POST\", HttpRequest.BodyPublishers.ofString(\"{\\\"category\\\":\\\"wrong_facts\\\",\\\"details\\\":\\\"The renewal date is off by a month — the contract runs to March, not February.\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"category\":\"wrong_facts\",\"details\":\"The renewal date is off by a month — the contract runs to March, not February.\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"category\\\":\\\"wrong_facts\\\",\\\"details\\\":\\\"The renewal date is off by a month — the contract runs to March, not February.\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"POST\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"category\\\":\\\"wrong_facts\\\",\\\"details\\\":\\\"The renewal date is off by a month — the contract runs to March, not February.\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"POST\",\n    \"https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"category\":\"wrong_facts\",\"details\":\"The renewal date is off by a month — the contract runs to March, not February.\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/cards/00000000-0000-0000-0000-000000000000/feedback\")\nrequest = Net::HTTPGenericRequest.new(\"POST\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"category\\\":\\\"wrong_facts\\\",\\\"details\\\":\\\"The renewal date is off by a month — the contract runs to March, not February.\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients":{"get":{"description":"Returns the authenticated organization's non-deleted clients, ordered\nby opaque internal ID for a stable cursor anchor. Use the `cursor`\nreturned in `meta.cursor` (if `meta.hasMore` is true) to fetch the\nnext page.\n\nToday's response includes `id`, `name`, `domain`, `createdAt`,\n`updatedAt`. Additional fields (`email`, `phone`, `company`, `notes`)\nlisted in the v1.0 spec are not yet populated.\n","operationId":"listClients","parameters":[{"description":"Page size (default 20, max 100).","in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from a previous response's `meta.cursor`.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Client"},"type":"array"}},"type":"object"}]}}},"description":"Page of clients.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List clients","tags":["clients"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/clients?cursor=string&limit=20\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/clients?cursor=string&limit=20'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/clients?cursor=string&limit=20\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients?cursor=string&limit=20\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients?cursor=string&limit=20', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients?cursor=string&limit=20', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients?cursor=string&limit=20\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/clients?cursor=string&limit=20\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients?cursor=string&limit=20\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"post":{"description":"Creates a new client in the authenticated organization. The server\nauto-wires any matching integration assignment rules based on the\nsupplied `domain` (same behaviour as the dashboard create flow).\n\n**`organizationId` must not be included in the body.** The organization\nis resolved from the bearer token; a body-borne `organizationId` is\nrejected with `400 invalid_argument` rather than silently overridden.\n","operationId":"createClient","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Client"}},"type":"object"}]}}},"description":"Client created.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Create a client","tags":["clients"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Post, \"https://api.salfio.com/v1/clients\");\nrequest.Content = new StringContent(\"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"prospect\\\",\\\"domain\\\":\\\"globex.com\\\",\\\"name\\\":\\\"Globex\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X POST 'https://api.salfio.com/v1/clients' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"prospect\",\"domain\":\"globex.com\",\"name\":\"Globex\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"prospect\",\"domain\":\"globex.com\",\"name\":\"Globex\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"POST\", \"https://api.salfio.com/v1/clients\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients\"))\n    .method(\"POST\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"POST\", HttpRequest.BodyPublishers.ofString(\"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"prospect\\\",\\\"domain\\\":\\\"globex.com\\\",\\\"name\\\":\\\"Globex\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"prospect\",\"domain\":\"globex.com\",\"name\":\"Globex\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"prospect\\\",\\\"domain\\\":\\\"globex.com\\\",\\\"name\\\":\\\"Globex\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"POST\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"prospect\\\",\\\"domain\\\":\\\"globex.com\\\",\\\"name\\\":\\\"Globex\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"POST\",\n    \"https://api.salfio.com/v1/clients\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"prospect\",\"domain\":\"globex.com\",\"name\":\"Globex\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients\")\nrequest = Net::HTTPGenericRequest.new(\"POST\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"prospect\\\",\\\"domain\\\":\\\"globex.com\\\",\\\"name\\\":\\\"Globex\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients/{clientId}":{"delete":{"description":"Soft-deletes the client. Subsequent reads return `404 not_found`. The\nstored row is retained for audit / recovery but no longer returned by\nany endpoint. Cross-tenant deletes return `404 not_found`.\n","operationId":"deleteClient","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Client deleted.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Delete a client","tags":["clients"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Delete, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X DELETE 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"DELETE\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\"))\n    .method(\"DELETE\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000', { method: 'DELETE' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000', { method: 'DELETE' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"DELETE\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"DELETE\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"DELETE\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"get":{"description":"Fetch a single client by its UUID. Returns `404 not_found` both for\nunknown IDs *and* for clients belonging to a different organization —\nthe public API never leaks the existence of cross-tenant resources.\n","operationId":"getClient","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Client"}},"type":"object"}]}}},"description":"Client record.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Get a client","tags":["clients"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"put":{"description":"Updates the provided fields; omitted fields are left unchanged. Cross-\ntenant updates return `404 not_found` (no existence leak).\n","operationId":"updateClient","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClientRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Client"}},"type":"object"}]}}},"description":"Updated client.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Update a client","tags":["clients"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Put, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\");\nrequest.Content = new StringContent(\"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"churned\\\",\\\"domain\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X PUT 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"churned\",\"domain\":\"string\",\"name\":\"string\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"churned\",\"domain\":\"string\",\"name\":\"string\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"PUT\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\"))\n    .method(\"PUT\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"PUT\", HttpRequest.BodyPublishers.ofString(\"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"churned\\\",\\\"domain\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000', {\n  method: 'PUT',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"churned\",\"domain\":\"string\",\"name\":\"string\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"churned\\\",\\\"domain\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"PUT\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"churned\\\",\\\"domain\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"PUT\",\n    \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"accountManagerIds\":[\"00000000-0000-0000-0000-000000000000\"],\"clientType\":\"churned\",\"domain\":\"string\",\"name\":\"string\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"PUT\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"accountManagerIds\\\":[\\\"00000000-0000-0000-0000-000000000000\\\"],\\\"clientType\\\":\\\"churned\\\",\\\"domain\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients/{clientId}/activities":{"get":{"description":"Returns the client's activities (emails, meetings, notes, chats)\nordered by most-recent first.\n\n**Pagination.** Offset-based: `cursor` is the integer offset of the\nnext page encoded as a decimal string (e.g. `\"20\"`). This differs from\n`/clients`, whose cursor is a base64-encoded UUID — the two endpoints\npaginate differently and their cursors are not interchangeable.\n\n**Filters.** `type`, `source`, `from`, `to`, and `includeArchived` are\nall applied server-side. `from`/`to` bound the activity's `occurredAt`\n(inclusive) and accept an ISO-8601 date (`2026-01-01`) or an RFC 3339\ndatetime. Archived activities are hidden unless `includeArchived=true`.\nUnknown enum values, unparseable dates, or a non-boolean\n`includeArchived` return `400 invalid_argument`.\n\nList responses omit `content` for cost reasons — fetch the\nsingle-resource endpoint to get message bodies.\n","operationId":"listActivities","parameters":[{"in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Decimal-string offset of the next page (from a prior response's `meta.cursor`).","in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"in":"query","name":"type","required":false,"schema":{"enum":["email","meeting","note","chat"],"type":"string"}},{"in":"query","name":"source","required":false,"schema":{"enum":["manual","gmail","outlook","fireflies"],"type":"string"}},{"description":"Only activities whose `occurredAt` is on/after this instant. ISO-8601 date or RFC 3339 datetime.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Only activities whose `occurredAt` is on/before this instant. ISO-8601 date or RFC 3339 datetime.","in":"query","name":"to","required":false,"schema":{"type":"string"}},{"description":"When true, archived activities are included. Defaults to false.","in":"query","name":"includeArchived","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Activity"},"type":"array"}},"type":"object"}]}}},"description":"Page of activities.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List activities for a client","tags":["activities"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities?cursor=string&from=string&includeArchived=false&limit=20&source=fireflies&to=string&type=chat\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"post":{"description":"Creates a manual activity for the client. The server always forces\n`source` to `manual` — activities created through the API are manual by\ndefinition (the source/operation matrix only permits creating manual\nactivities). A request body that sets `source` to anything other than\n`manual` is rejected with `400 invalid_argument` rather than silently\noverridden.\n\n`participants` is a flat list of email addresses, stored email-only (no\ndisplay name, no automatic linking to existing contacts). `occurredAt`\ndefaults to the current time when omitted.\n","operationId":"createActivity","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Activity"}},"type":"object"}]}}},"description":"The created activity (content included).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Create a manual activity","tags":["activities"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Post, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities\");\nrequest.Content = new StringContent(\"{\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"source\\\":\\\"manual\\\",\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X POST 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[\"user@example.com\"],\"source\":\"manual\",\"subject\":\"string\",\"type\":\"chat\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[\"user@example.com\"],\"source\":\"manual\",\"subject\":\"string\",\"type\":\"chat\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"POST\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities\"))\n    .method(\"POST\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"POST\", HttpRequest.BodyPublishers.ofString(\"{\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"source\\\":\\\"manual\\\",\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[\"user@example.com\"],\"source\":\"manual\",\"subject\":\"string\",\"type\":\"chat\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"source\\\":\\\"manual\\\",\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"POST\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"source\\\":\\\"manual\\\",\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"POST\",\n    \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[\"user@example.com\"],\"source\":\"manual\",\"subject\":\"string\",\"type\":\"chat\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities\")\nrequest = Net::HTTPGenericRequest.new(\"POST\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"source\\\":\\\"manual\\\",\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients/{clientId}/activities/{activityId}":{"delete":{"description":"Removes an activity, with semantics that depend on its source\n(the source/operation matrix):\n\n- **Manual** activities are **hard-deleted** — the row and its messages\n  are removed permanently; a subsequent GET returns `404 not_found`.\n- **External-source** activities (`gmail`, `outlook`, `fireflies`) are\n  **archived** — `archivedAt` is stamped and the row is retained but\n  hidden from list responses unless `includeArchived=true`.\n\nBoth outcomes return `204 No Content`.\n","operationId":"deleteOrArchiveActivity","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Activity UUID.","in":"path","name":"activityId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Activity deleted (manual) or archived (external source).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Delete or archive an activity","tags":["activities"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Delete, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X DELETE 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"DELETE\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\"))\n    .method(\"DELETE\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000', { method: 'DELETE' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000', { method: 'DELETE' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"DELETE\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"DELETE\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"DELETE\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"get":{"description":"Fetch a single activity by UUID. The response includes the full\nconcatenated message content — long call transcripts are returned\nwhole, without truncation. Cross-tenant lookups and activities that\ndon't belong to the path's client return `404 not_found`.\n","operationId":"getActivity","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Activity UUID.","in":"path","name":"activityId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Activity"}},"type":"object"}]}}},"description":"Activity record with content.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Get an activity","tags":["activities"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"put":{"description":"Edits a manual activity. Only manual activities are editable: a PUT on\nan activity from an external source (`gmail`, `outlook`, `fireflies`)\nreturns `403 forbidden` — the activity exists and belongs to you, but\nits source makes it immutable on the v1 surface (`immutable: true`).\n\nAll body fields are optional; omitted fields are left unchanged.\n`participants`, when provided, fully replaces the existing list.\n","operationId":"updateActivity","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Activity UUID.","in":"path","name":"activityId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Activity"}},"type":"object"}]}}},"description":"The updated activity.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Update a manual activity","tags":["activities"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Put, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\");\nrequest.Content = new StringContent(\"{\\\"content\\\":\\\"string\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X PUT 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"content\":\"string\",\"participants\":[\"user@example.com\"],\"subject\":\"string\",\"type\":\"chat\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"content\":\"string\",\"participants\":[\"user@example.com\"],\"subject\":\"string\",\"type\":\"chat\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"PUT\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\"))\n    .method(\"PUT\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"PUT\", HttpRequest.BodyPublishers.ofString(\"{\\\"content\\\":\\\"string\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000', {\n  method: 'PUT',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"content\":\"string\",\"participants\":[\"user@example.com\"],\"subject\":\"string\",\"type\":\"chat\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"content\\\":\\\"string\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"PUT\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"content\\\":\\\"string\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"PUT\",\n    \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"content\":\"string\",\"participants\":[\"user@example.com\"],\"subject\":\"string\",\"type\":\"chat\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/activities/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"PUT\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"content\\\":\\\"string\\\",\\\"participants\\\":[\\\"user@example.com\\\"],\\\"subject\\\":\\\"string\\\",\\\"type\\\":\\\"chat\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients/{clientId}/assignment-rules":{"get":{"description":"Returns one entry per active integration in the organization, each\ncarrying that integration's current rule for this client. When an\nintegration has no rule configured for the client yet, the entry is\nstill returned with `ruleId: null` — so this doubles as a way to\ndiscover the `integrationId`s you can bind.\n\nCross-tenant lookups and missing clients both return `404 not_found`\nso existence is never leaked.\n","operationId":"getAssignmentRules","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/AssignmentRule"},"type":"array"}},"type":"object"}]}}},"description":"The client's assignment rules.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List a client's assignment rules","tags":["assignment-rules"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"put":{"description":"Replace-all upsert of the client's assignment rules. Each rule binds an\nintegration to the client via **either** a raw `filterCriteria` object\n**or**, for Slack, the `slackChannels` shorthand — a list of channel\nnames the server expands into the equivalent criteria, so you never have\nto hand-build the query structure. The two are mutually exclusive, and\n`slackChannels` is only valid on a Slack integration.\n\nReplace semantics: any integration **omitted** from `rules` has its\nexisting rule removed. Send an empty `rules` array to clear every rule.\nA save re-applies the rules to the client's existing conversations (see\n`reapplyStats`) and can start a Slack history backfill.\n\nUse a GET-then-PUT flow to avoid unintentionally wiping rules you didn't\nmean to touch. Cross-tenant clients and integrations return `404\nnot_found` / `400 invalid_argument` with no existence leak.\n","operationId":"setAssignmentRules","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAssignmentRulesRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/SaveAssignmentRulesResponse"}},"type":"object"}]}}},"description":"The saved rules plus the re-apply summary.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Replace a client's assignment rules","tags":["assignment-rules"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Put, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\");\nrequest.Content = new StringContent(\"{\\\"rules\\\":[{\\\"enabled\\\":true,\\\"filterCriteria\\\":null,\\\"integrationId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"slackChannels\\\":[\\\"general\\\",\\\"acme-project\\\"]}]}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X PUT 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"rules\":[{\"enabled\":true,\"filterCriteria\":null,\"integrationId\":\"00000000-0000-0000-0000-000000000000\",\"slackChannels\":[\"general\",\"acme-project\"]}]}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"rules\":[{\"enabled\":true,\"filterCriteria\":null,\"integrationId\":\"00000000-0000-0000-0000-000000000000\",\"slackChannels\":[\"general\",\"acme-project\"]}]}`)\n\treq, err := http.NewRequestWithContext(ctx, \"PUT\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\"))\n    .method(\"PUT\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"PUT\", HttpRequest.BodyPublishers.ofString(\"{\\\"rules\\\":[{\\\"enabled\\\":true,\\\"filterCriteria\\\":null,\\\"integrationId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"slackChannels\\\":[\\\"general\\\",\\\"acme-project\\\"]}]}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules', {\n  method: 'PUT',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"rules\":[{\"enabled\":true,\"filterCriteria\":null,\"integrationId\":\"00000000-0000-0000-0000-000000000000\",\"slackChannels\":[\"general\",\"acme-project\"]}]}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"rules\\\":[{\\\"enabled\\\":true,\\\"filterCriteria\\\":null,\\\"integrationId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"slackChannels\\\":[\\\"general\\\",\\\"acme-project\\\"]}]}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"PUT\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"rules\\\":[{\\\"enabled\\\":true,\\\"filterCriteria\\\":null,\\\"integrationId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"slackChannels\\\":[\\\"general\\\",\\\"acme-project\\\"]}]}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"PUT\",\n    \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"rules\":[{\"enabled\":true,\"filterCriteria\":null,\"integrationId\":\"00000000-0000-0000-0000-000000000000\",\"slackChannels\":[\"general\",\"acme-project\"]}]}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/assignment-rules\")\nrequest = Net::HTTPGenericRequest.new(\"PUT\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"rules\\\":[{\\\"enabled\\\":true,\\\"filterCriteria\\\":null,\\\"integrationId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"slackChannels\\\":[\\\"general\\\",\\\"acme-project\\\"]}]}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients/{clientId}/cards":{"get":{"description":"Returns the AI-generated cards (briefing, wins/traction,\nrisks/frictions, topics) for the client, in the display order\nconfigured in the organization's card settings. Filtered to\nconfigs where both `is_active` and `is_displayed` are true; the\ncolumn-only configs that surface on the clients-overview list\nare intentionally excluded here.\n\n**Stale handling.** When at least one card is stale, that card\nis returned with `is_stale=true` AND a regeneration is\nenqueued for the worker to pick up on its next tick. The read\npath is purely lazy — no synchronous LLM call is ever made on\na partner request. Re-call the endpoint after a short delay to\nobserve the refreshed value (`is_stale=false`, new\n`last_update`).\n\nCross-tenant lookups and missing clients both return `404\nnot_found` so existence is never leaked.\n","operationId":"listClientCards","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/ClientCard"},"type":"array"}},"type":"object"}]}}},"description":"Ordered list of the client's cards.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List a client's cards","tags":["cards"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/cards\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/clients/{clientId}/notes":{"post":{"description":"Records a note against the client and returns it as an activity of\n`type: \"note\"`. Unlike the generic activity create, the note path\nattributes the note to a user author (added as a participant contact)\nand marks the client's AI cards stale so they regenerate.\n\n**Author attribution.** With a **user-scoped** key the note is authored\nby the authenticated user automatically. With a **service-scoped** key\n(which carries no user) you MUST supply `authorUserId` referencing a\nmember of your organization — otherwise the request is rejected with\n`400 invalid_argument`. A cross-organization or unknown `authorUserId`\nis likewise `400 invalid_argument`.\n\n`content` is required. `participants` are people present on the note\nbesides the author; each is linked to (or created as) an org contact by\nemail. `occurredAt` defaults to now when omitted.\n","operationId":"createNote","parameters":[{"description":"Client UUID.","in":"path","name":"clientId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Activity"}},"type":"object"}]}}},"description":"The created note, as an activity of type \"note\" (content included).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Create a note on a client","tags":["notes"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Post, \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes\");\nrequest.Content = new StringContent(\"{\\\"authorUserId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[{\\\"email\\\":\\\"user@example.com\\\",\\\"name\\\":\\\"string\\\"}],\\\"subject\\\":\\\"string\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X POST 'https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"authorUserId\":\"00000000-0000-0000-0000-000000000000\",\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[{\"email\":\"user@example.com\",\"name\":\"string\"}],\"subject\":\"string\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"authorUserId\":\"00000000-0000-0000-0000-000000000000\",\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[{\"email\":\"user@example.com\",\"name\":\"string\"}],\"subject\":\"string\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"POST\", \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes\"))\n    .method(\"POST\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"POST\", HttpRequest.BodyPublishers.ofString(\"{\\\"authorUserId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[{\\\"email\\\":\\\"user@example.com\\\",\\\"name\\\":\\\"string\\\"}],\\\"subject\\\":\\\"string\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"authorUserId\":\"00000000-0000-0000-0000-000000000000\",\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[{\"email\":\"user@example.com\",\"name\":\"string\"}],\"subject\":\"string\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"authorUserId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[{\\\"email\\\":\\\"user@example.com\\\",\\\"name\\\":\\\"string\\\"}],\\\"subject\\\":\\\"string\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"POST\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"authorUserId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[{\\\"email\\\":\\\"user@example.com\\\",\\\"name\\\":\\\"string\\\"}],\\\"subject\\\":\\\"string\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"POST\",\n    \"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"authorUserId\":\"00000000-0000-0000-0000-000000000000\",\"content\":\"string\",\"occurredAt\":\"2026-06-09T00:00:00Z\",\"participants\":[{\"email\":\"user@example.com\",\"name\":\"string\"}],\"subject\":\"string\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/clients/00000000-0000-0000-0000-000000000000/notes\")\nrequest = Net::HTTPGenericRequest.new(\"POST\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"authorUserId\\\":\\\"00000000-0000-0000-0000-000000000000\\\",\\\"content\\\":\\\"string\\\",\\\"occurredAt\\\":\\\"2026-06-09T00:00:00Z\\\",\\\"participants\\\":[{\\\"email\\\":\\\"user@example.com\\\",\\\"name\\\":\\\"string\\\"}],\\\"subject\\\":\\\"string\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/docs":{"get":{"description":"Renders an interactive API reference (Scalar) that points at\n`/v1/openapi.yaml`. Unauthenticated — intended for prospective\npartners to preview the API surface before minting a key. Rate-\nlimited per caller IP (60 req/min).\n","operationId":"getDocsPage","parameters":[],"responses":{"200":{"content":{"text/html":{"schema":{"description":"Static HTML shell that loads Scalar from a CDN.","type":"string"}}},"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[],"summary":"Render the Public API v1 documentation (Scalar)","tags":["docs"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/docs\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/docs'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/docs\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/docs\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/docs', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/docs', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/docs\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/docs\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/docs\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/health":{"get":{"description":"Returns `{\"status\":\"ok\"}` when the presented bearer token is valid.\nUsed by callers to verify their token and the end-to-end routing\nfrom `api.salfio.com` to the Salfio API service.\n","operationId":"getHealth","parameters":[],"responses":{"200":{"content":{"application/json":{"examples":{"ok":{"summary":"Healthy","value":{"data":{"status":"ok"},"meta":{}}}},"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"properties":{"status":{"enum":["ok"],"examples":["ok"],"type":"string"}},"required":["status"],"type":"object"}},"type":"object"}]}}},"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Authenticated health check","tags":["health"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/health\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/health'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/health\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/health\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/health', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/health', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/health\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/health\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/health\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/integrations":{"get":{"description":"Returns every integration connected in your organization, regardless of\nconnection status. Use it to discover the `integrationId` and `type` you\npass when creating assignment rules: the `type` tells you whether to\nbind via the `slackChannels` shorthand (Slack) or a raw `filterCriteria`\nobject (everything else).\n\nDisconnected or expired integrations are included so you can detect and\nreconnect them — check `connectionStatus` and `enabled`.\n","operationId":"listIntegrations","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Integration"},"type":"array"}},"type":"object"}]}}},"description":"The organization's integrations.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List the organization's integrations","tags":["integrations"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/integrations\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/integrations'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/integrations\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/integrations\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/integrations', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/integrations', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/integrations\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/integrations\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/integrations\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/integrations/{integrationId}/channels":{"get":{"description":"Returns the channels the workspace bot is a member of for a Slack\nintegration — the valid set of channel names to pass in the\n`slackChannels` shorthand when creating an assignment rule.\n\nOnly Slack integrations have channels: any other integration type\nreturns `400 invalid_argument`. The integration must be active —\na disconnected, expired, or disabled one returns `409 conflict`.\nCross-tenant or unknown integration IDs return `404 not_found` with no\nexistence leak.\n","operationId":"listIntegrationChannels","parameters":[{"description":"Integration UUID.","in":"path","name":"integrationId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Channel"},"type":"array"}},"type":"object"}]}}},"description":"The channels the bot is a member of.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List a Slack integration's channels","tags":["integrations"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/integrations/00000000-0000-0000-0000-000000000000/channels\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/openapi.yaml":{"get":{"description":"Returns this very document as `application/yaml`. Unauthenticated —\nthe spec is public. Rate-limited per caller IP (60 req/min) and\ncacheable for 5 minutes at the edge.\n","operationId":"getOpenAPISpec","parameters":[],"responses":{"200":{"content":{"application/yaml":{"schema":{"description":"This OpenAPI document, served verbatim.","type":"string"}}},"description":"OK","headers":{"Cache-Control":{"description":"Edge cache hint (5 minutes) so a busy docs page doesn't thrash the origin.","schema":{"examples":["public, max-age=300"],"type":"string"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[],"summary":"Fetch the Public API v1 OpenAPI specification","tags":["docs"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/openapi.yaml\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/openapi.yaml'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/openapi.yaml\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/openapi.yaml\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/openapi.yaml', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/openapi.yaml', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/openapi.yaml\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/openapi.yaml\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/openapi.yaml\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/organization":{"get":{"description":"Returns the organization associated with the bearer token. Singleton\nendpoint — there is no `{organizationId}` in the path and there is no\nway for a caller to read a different organization's record.\n\nToday the organization model does not carry per-org plan or\nrate-limit overrides. The response stubs `plan` to `\"free\"` and\npopulates `rateLimits` with the system-wide defaults (100\nrequests/min per org, 50 requests/min per endpoint). When per-org\noverrides land the same wire fields will start reflecting per-org\nvalues — the response shape is forwards-compatible.\n","operationId":"getOrganization","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Organization"}},"type":"object"}]}}},"description":"Organization record.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Get the caller's organization","tags":["organization"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/organization\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/organization'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/organization\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/organization\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/organization', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/organization', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/organization\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/organization\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/organization\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"put":{"description":"Updates the whitelisted fields on the caller's organization. Only\n`name`, `defaultTimezone`, and `defaultCurrency` are writable.\n\n**`plan` is billing-bound** — an attempt to update it is rejected\nwith `400 invalid_argument` rather than silently ignored, so a\npartner misreading the spec gets a clear error rather than a false\nsense of success. **`slug` is stable** for the same reason —\nchanging it breaks dashboard deep links and other external\nreferences. Both return 400 when present in the body.\n\nOther unknown fields are silently ignored.\n","operationId":"updateOrganization","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Organization"}},"type":"object"}]}}},"description":"Updated organization.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Update the caller's organization","tags":["organization"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Put, \"https://api.salfio.com/v1/organization\");\nrequest.Content = new StringContent(\"{\\\"defaultCurrency\\\":\\\"string\\\",\\\"defaultTimezone\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X PUT 'https://api.salfio.com/v1/organization' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"defaultCurrency\":\"string\",\"defaultTimezone\":\"string\",\"name\":\"string\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"defaultCurrency\":\"string\",\"defaultTimezone\":\"string\",\"name\":\"string\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"PUT\", \"https://api.salfio.com/v1/organization\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/organization\"))\n    .method(\"PUT\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"PUT\", HttpRequest.BodyPublishers.ofString(\"{\\\"defaultCurrency\\\":\\\"string\\\",\\\"defaultTimezone\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/organization', {\n  method: 'PUT',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"defaultCurrency\":\"string\",\"defaultTimezone\":\"string\",\"name\":\"string\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/organization', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"defaultCurrency\\\":\\\"string\\\",\\\"defaultTimezone\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/organization\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"PUT\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"defaultCurrency\\\":\\\"string\\\",\\\"defaultTimezone\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"PUT\",\n    \"https://api.salfio.com/v1/organization\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"defaultCurrency\":\"string\",\"defaultTimezone\":\"string\",\"name\":\"string\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/organization\")\nrequest = Net::HTTPGenericRequest.new(\"PUT\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"defaultCurrency\\\":\\\"string\\\",\\\"defaultTimezone\\\":\\\"string\\\",\\\"name\\\":\\\"string\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/users":{"get":{"description":"Returns the authenticated organization's members. Creation and\ndeletion of users are managed through the Salfio dashboard's\ninvitation flow and are intentionally not exposed via the API.\n","operationId":"listUsers","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/User"},"type":"array"}},"type":"object"}]}}},"description":"Users belonging to the caller's organization.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"List organization users","tags":["users"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/users\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/users'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/users\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/users\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/users', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/users', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/users\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/users\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/users\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}},"/users/{userId}":{"get":{"description":"Fetch a single user by UUID. Users that don't belong to the caller's\norganization return `404 not_found` — existence is never leaked\nacross tenants.\n","operationId":"getUser","parameters":[{"description":"User UUID.","in":"path","name":"userId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/User"}},"type":"object"}]}}},"description":"User record.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Get a user","tags":["users"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Get, \"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X GET 'https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\"))\n    .method(\"GET\", HttpRequest.BodyPublishers.noBody())\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000', { method: 'GET' });\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000', { method: 'GET' });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"GET\");\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\"GET\", \"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\")\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"GET\", false, true, uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]},"put":{"description":"Updates whitelisted profile fields. The endpoint intentionally does\nnot accept identity-bound fields — `email`, `clerkUserID`, and the\ncanonical `id` are owned by Clerk and cannot be changed through the\nAPI. Unknown fields in the body are silently ignored.\n","operationId":"updateUser","parameters":[{"description":"User UUID.","in":"path","name":"userId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/User"}},"type":"object"}]}}},"description":"Updated user.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"$ref":"#/components/responses/InvalidArgument"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}],"summary":"Update a user's profile","tags":["users"],"x-codeSamples":[{"lang":"csharp","source":"using var client = new HttpClient();\nusing var request = new HttpRequestMessage(HttpMethod.Put, \"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\");\nrequest.Content = new StringContent(\"{\\\"firstName\\\":\\\"string\\\",\\\"imageUrl\\\":\\\"https://example.com\\\",\\\"lastName\\\":\\\"string\\\"}\", Encoding.UTF8, \"application/json\");\nusing var response = await client.SendAsync(request);"},{"lang":"curl","source":"curl -X PUT 'https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"firstName\":\"string\",\"imageUrl\":\"https://example.com\",\"lastName\":\"string\"}'"},{"lang":"go","source":"package main\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tbody := strings.NewReader(`{\"firstName\":\"string\",\"imageUrl\":\"https://example.com\",\"lastName\":\"string\"}`)\n\treq, err := http.NewRequestWithContext(ctx, \"PUT\", \"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\", body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n}"},{"lang":"java","source":"var request = HttpRequest.newBuilder(URI.create(\"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\"))\n    .method(\"PUT\", HttpRequest.BodyPublishers.noBody())\n    .header(\"Content-Type\", \"application/json\")\n    .method(\"PUT\", HttpRequest.BodyPublishers.ofString(\"{\\\"firstName\\\":\\\"string\\\",\\\"imageUrl\\\":\\\"https://example.com\\\",\\\"lastName\\\":\\\"string\\\"}\"))\n    .build();\nvar response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());"},{"lang":"javascript-fetch","source":"const response = await fetch('https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000', {\n  method: 'PUT',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"firstName\":\"string\",\"imageUrl\":\"https://example.com\",\"lastName\":\"string\"}),\n});\nconst data = await response.json();"},{"lang":"node","source":"const response = await fetch('https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: \"{\\\"firstName\\\":\\\"string\\\",\\\"imageUrl\\\":\\\"https://example.com\\\",\\\"lastName\\\":\\\"string\\\"}\" });\nconsole.log(await response.json());"},{"lang":"php","source":"<?php\n$request = curl_init(\"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\");\ncurl_setopt($request, CURLOPT_CUSTOMREQUEST, \"PUT\");\ncurl_setopt($request, CURLOPT_POSTFIELDS, \"{\\\"firstName\\\":\\\"string\\\",\\\"imageUrl\\\":\\\"https://example.com\\\",\\\"lastName\\\":\\\"string\\\"}\");\ncurl_setopt($request, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\n$response = curl_exec($request);\ncurl_close($request);"},{"lang":"python","source":"import requests\n\nresponse = requests.request(\n    \"PUT\",\n    \"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\",\n    headers={\"Content-Type\": \"application/json\"},\n    data='{\"firstName\":\"string\",\"imageUrl\":\"https://example.com\",\"lastName\":\"string\"}',\n)\nprint(response.json())"},{"lang":"ruby","source":"require 'net/http'\n\nuri = URI(\"https://api.salfio.com/v1/users/00000000-0000-0000-0000-000000000000\")\nrequest = Net::HTTPGenericRequest.new(\"PUT\", true, true, uri)\nrequest['Content-Type'] = 'application/json'\nrequest.body = \"{\\\"firstName\\\":\\\"string\\\",\\\"imageUrl\\\":\\\"https://example.com\\\",\\\"lastName\\\":\\\"string\\\"}\"\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }"}]}}},"servers":[{"url":"https://api.salfio.com/v1"}]}