{"openapi":"3.1.0","info":{"title":"Paydirt API","version":"2.3.0","description":"API for Paydirt apps, voice-first feedback and Suggest a Feature forms, RevenueCat-enriched trial and subscription cancellation conversations, read-only churn analysis, Slack delivery, and agent-assisted setup. Paydirt does not replace RevenueCat billing or entitlement management.","contact":{"name":"Paydirt support","email":"hello@paydirt.ai","url":"https://www.paydirt.ai/contact"},"license":{"name":"Proprietary API; public SDK and MCP licenses are documented in their repositories."}},"jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","servers":[{"url":"https://api.paydirt.ai","description":"Production API"}],"externalDocs":{"description":"Paydirt developer documentation","url":"https://www.paydirt.ai/docs"},"tags":[{"name":"System","description":"Availability and machine discovery."},{"name":"Authentication","description":"Dashboard account authentication."},{"name":"Apps","description":"App identity, SDK keys, and retention policy."},{"name":"Forms","description":"Remote feedback conversation configuration."},{"name":"SDK conversations","description":"Public-SDK operations protected by app and bundle credentials."},{"name":"Responses","description":"Durable raw feedback and delivery receipts."},{"name":"Analytics","description":"Read-only summaries, questions, and privacy-limited site events."},{"name":"Slack","description":"Workspace authorization and typed feedback routing."},{"name":"Agent setup","description":"Browser-authorized coding-agent setup."},{"name":"Webhooks","description":"Third-party callbacks."}],"paths":{"/health":{"get":{"operationId":"getApiHealth","tags":["System"],"summary":"Check API health","description":"Returns the deployed API version and current server time without requiring authentication.","security":[],"parameters":[],"responses":{"200":{"description":"The API is available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/google":{"post":{"operationId":"exchangeGoogleAuthorization","tags":["Authentication"],"summary":"Exchange Google authorization for a Paydirt token","description":"Exchanges a Google OAuth authorization code and returns a Paydirt Bearer token used by dashboard and agent-control endpoints.","security":[],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleAuthRequest"}}}},"responses":{"200":{"description":"Authentication completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps":{"get":{"operationId":"listPaydirtApps","tags":["Apps"],"summary":"List Paydirt apps","description":"Lists every Paydirt app owned by the authenticated account.","security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Owned apps.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/App"}}},"required":["apps"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"createPaydirtApp","tags":["Apps"],"summary":"Create a Paydirt app","description":"Creates an app, public SDK key, bundle policy, and feedback-retention policy.","security":[{"bearerAuth":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppCreateRequest"}}}},"responses":{"201":{"description":"App created.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{id}":{"get":{"operationId":"getPaydirtApp","tags":["Apps"],"summary":"Get a Paydirt app","description":"Returns one app owned by the authenticated account.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"App details.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"updatePaydirtApp","tags":["Apps"],"summary":"Update a Paydirt app","description":"Updates supported app settings without replacing unspecified fields.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppUpdateRequest"}}}},"responses":{"200":{"description":"Updated app.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"deletePaydirtApp","tags":["Apps"],"summary":"Delete a Paydirt app","description":"Permanently removes an app owned by the authenticated account.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deletion result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{id}/rotate-key":{"post":{"operationId":"rotatePaydirtSdkKey","tags":["Apps"],"summary":"Rotate the public SDK key","description":"Creates a new SDK key immediately; existing app builds using the previous key stop authenticating.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}}}}},"responses":{"200":{"description":"App with its new key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/forms":{"get":{"operationId":"listFeedbackForms","tags":["Forms"],"summary":"List feedback forms","description":"Lists feature, trial-cancellation, subscription-cancellation, and custom forms for one app.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Forms for the app.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"forms":{"type":"array","items":{"$ref":"#/components/schemas/Form"}}},"required":["forms"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"createFeedbackForm","tags":["Forms"],"summary":"Create a feedback form","description":"Creates a remotely configurable feedback conversation and optionally assigns its Slack channel.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormCreateRequest"}}}},"responses":{"201":{"description":"Form created.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"form":{"$ref":"#/components/schemas/Form"}},"required":["form"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/forms/{id}":{"get":{"operationId":"getFeedbackForm","tags":["Forms"],"summary":"Get a feedback form","description":"Returns one form after verifying account ownership.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Feedback form identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Form details.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"form":{"$ref":"#/components/schemas/Form"}},"required":["form"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"updateFeedbackForm","tags":["Forms"],"summary":"Update a feedback form","description":"Updates the supplied form fields, including enablement and Slack routing.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Feedback form identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormUpdateRequest"}}}},"responses":{"200":{"description":"Updated form.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"form":{"$ref":"#/components/schemas/Form"}},"required":["form"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"deleteFeedbackForm","tags":["Forms"],"summary":"Delete a feedback form","description":"Deletes one form owned by the authenticated account.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Feedback form identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deletion result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/conversation/forms":{"get":{"operationId":"getSdkForm","tags":["SDK conversations"],"summary":"Load an enabled SDK form","description":"Returns the enabled form requested by an installed SDK using its public app key.","security":[{"sdkKeyAuth":[],"bundleId":[]}],"parameters":[{"name":"form_id","in":"query","required":false,"description":"Feedback form identifier.","schema":{"type":"string","format":"uuid"}},{"name":"type","in":"query","required":false,"description":"Fallback form-type selector when form_id is omitted.","schema":{"type":"string","enum":["cancellation","trial_expiration","feature_request","custom"]}}],"responses":{"200":{"description":"SDK form configuration.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"form":{"$ref":"#/components/schemas/Form"}},"required":["form"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/conversation/message":{"post":{"operationId":"continueFeedbackConversation","tags":["SDK conversations"],"summary":"Generate a feedback follow-up","description":"Uses the configured form and prior conversation to generate the next read-only research question.","security":[{"sdkKeyAuth":[],"bundleId":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationMessageRequest"}}}},"responses":{"200":{"description":"Follow-up question.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationMessageResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/responses":{"post":{"operationId":"saveFeedbackSnapshot","tags":["Responses"],"summary":"Save a feedback conversation snapshot","description":"Creates or idempotently updates a durable conversation snapshot. A completed response requires a non-empty user answer and is immutable against later retries. Completion attempts configured Slack delivery unless the app uses agents-only delivery. A saved response can return 503 when Slack delivery fails; retry with the same idempotency key. Delivery is not backed by an independent server outbox in this version.","security":[{"sdkKeyAuth":[],"bundleId":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseSnapshotRequest"}}}},"responses":{"200":{"description":"Saved or replayed response snapshot.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"response":{"$ref":"#/components/schemas/FeedbackResponse"},"replayed":{"type":"boolean"}},"required":["response","replayed"]}}}},"201":{"description":"Saved or replayed response snapshot.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"response":{"$ref":"#/components/schemas/FeedbackResponse"},"replayed":{"type":"boolean"}},"required":["response","replayed"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/responses/{id}/delivery":{"get":{"operationId":"getFeedbackDeliveryReceipt","tags":["Responses"],"summary":"Check SDK delivery","description":"Returns receipt and Slack-delivery state without exposing the feedback content.","security":[{"sdkKeyAuth":[],"bundleId":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Response identifier generated by the SDK.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delivery receipt.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryReceipt"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/responses":{"get":{"operationId":"listAppFeedbackResponses","tags":["Responses"],"summary":"List app feedback responses","description":"Returns filtered feedback conversations for an app owned by the authenticated account.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}},{"name":"form_id","in":"query","required":false,"description":"Filter by form.","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"description":"Conversation status.","schema":{"type":"string","enum":["completed","in_progress","abandoned","all"],"default":"completed"}},{"name":"limit","in":"query","required":false,"description":"Maximum records.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"description":"Zero-based record offset.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"date_from","in":"query","required":false,"description":"Inclusive ISO-8601 lower bound.","schema":{"type":"string","format":"date-time"}},{"name":"date_to","in":"query","required":false,"description":"Inclusive ISO-8601 upper bound.","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Filtered responses.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"responses":{"type":"array","items":{"$ref":"#/components/schemas/FeedbackResponse"}}},"required":["responses"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/responses/app/{app_id}":{"get":{"operationId":"listDashboardFeedbackResponses","tags":["Responses"],"summary":"List dashboard feedback responses","description":"Compatibility route for listing an app’s responses with dashboard authentication.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Responses.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"responses":{"type":"array","items":{"$ref":"#/components/schemas/FeedbackResponse"}}},"required":["responses"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/responses/{id}":{"get":{"operationId":"getFeedbackResponse","tags":["Responses"],"summary":"Get one feedback response","description":"Returns one complete response after verifying account ownership.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Feedback response identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Response details.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"response":{"$ref":"#/components/schemas/FeedbackResponse"}},"required":["response"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"deleteFeedbackResponse","tags":["Responses"],"summary":"Delete one feedback response","description":"Deletes a response owned by the authenticated account.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Feedback response identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deletion result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/responses/app/{app_id}/all":{"delete":{"operationId":"deleteAllAppFeedback","tags":["Responses"],"summary":"Delete all feedback for an app","description":"Deletes every response belonging to one owned app.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deletion result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/summary":{"get":{"operationId":"summarizeAppFeedback","tags":["Analytics"],"summary":"Summarize recent feedback","description":"Produces a read-only AI summary and top reasons from completed Paydirt conversations.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}},{"name":"form_id","in":"query","required":false,"description":"Optional form filter.","schema":{"type":"string","format":"uuid"}},{"name":"period","in":"query","required":false,"description":"Named lookback period.","schema":{"type":"string","enum":["week","month","all"],"default":"week"}},{"name":"days","in":"query","required":false,"description":"Custom positive lookback in days; overrides period.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Aggregate feedback summary.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SummaryResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/ask":{"post":{"operationId":"askAboutAppFeedback","tags":["Analytics"],"summary":"Ask a question about feedback","description":"Answers a read-only question from recent completed feedback; raw responses remain the source of truth.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskFeedbackRequest"}}}},"responses":{"200":{"description":"Answer grounded in feedback.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskFeedbackResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/slack/install":{"get":{"operationId":"startSlackInstallation","tags":["Slack"],"summary":"Start Slack OAuth","description":"Creates the Slack authorization URL for an owned app and requested delivery preference.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"query","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}},{"name":"delivery","in":"query","required":false,"description":"Saved delivery preference.","schema":{"type":"string","enum":["both","slack"]}},{"name":"return_to","in":"query","required":false,"description":"Local /setup path, optionally including a setup session and app identity, to resume after OAuth.","schema":{"type":"string","maxLength":2000}},{"name":"channel_selection","in":"query","required":false,"description":"Use manual for human channel selection after OAuth. Omit for legacy automatic channel provisioning.","schema":{"type":"string","enum":["manual"]}}],"responses":{"200":{"description":"Slack authorization URL.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"auth_url":{"type":"string","format":"uri"}},"required":["auth_url"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/slack/callback":{"get":{"operationId":"completeSlackInstallation","tags":["Slack"],"summary":"Complete Slack OAuth","description":"Slack redirects here after authorization. With channel_selection=manual in the signed state, Paydirt saves the app-scoped workspace connection and returns channel_setup=selection_required without creating channels or posting messages. Legacy automatic setup provisions default channels. Reconnecting the same workspace preserves destinations; switching workspaces clears previous assignments.","security":[],"parameters":[{"name":"code","in":"query","required":false,"description":"Slack OAuth authorization code; omitted when the user cancels.","schema":{"type":"string"}},{"name":"state","in":"query","required":true,"description":"Signed Paydirt OAuth state.","schema":{"type":"string"}}],"responses":{"302":{"description":"Browser redirect to the Paydirt setup result.","content":{"text/html":{"schema":{"type":"string","description":"HTML redirect response."}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/slack/{app_id}/channels":{"get":{"operationId":"listSlackChannels","tags":["Slack"],"summary":"List Slack channels","description":"Lists public and accessible private channels in this app’s connected Slack workspace, together with its team name. Invite Paydirt into a private channel before selecting it.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workspace channels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackChannelsResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"selectSlackDestinations","tags":["Slack"],"summary":"Select feedback destinations","description":"Assigns destinations for all existing forms of the owned app. Provide both fields; a category with no forms may be null. Custom forms share the feature destination; trial and paid cancellation forms share the cancellation destination. Both categories may use the same channel. Channel IDs must be accessible in the app’s connected Slack workspace. This does not send a Slack message or change the app delivery preference. Read app form inventory before asking the human to select channels.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackDestinationsRequest"}}}},"responses":{"200":{"description":"Selected destinations saved and assigned to forms.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"feature_channel_id":{"type":["string","null"]},"cancellation_channel_id":{"type":["string","null"]}},"required":["success","feature_channel_id","cancellation_channel_id"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/slack/{app_id}/status":{"get":{"operationId":"getSlackConnectionStatus","tags":["Slack"],"summary":"Check Slack routing","description":"Reports workspace connection and form-to-channel assignment completeness. all_forms_assigned requires at least one form and a selected destination for every existing form; distinct channels are not required. This is configuration status, not proof of live Slack delivery.","security":[{"bearerAuth":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"description":"Paydirt app identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Slack connection and assignment status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackStatusResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/slack/events":{"post":{"operationId":"receiveSlackEvent","tags":["Webhooks"],"summary":"Receive a Slack event","description":"Receives Slack URL-verification challenges and acknowledges other configured Slack app event callbacks.","security":[],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackEventRequest"}}}},"responses":{"200":{"description":"Slack event accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackEventResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/audio/transcribe":{"post":{"operationId":"transcribeFeedbackAudio","tags":["SDK conversations"],"summary":"Transcribe feedback audio","description":"Transcribes a protected M4A or MP3 feedback recording up to 25 MB.","security":[{"sdkKeyAuth":[],"bundleId":[]}],"parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","additionalProperties":false,"properties":{"audio":{"type":"string","format":"binary"}},"required":["audio"]}}}},"responses":{"200":{"description":"Transcribed text.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/setup/start":{"post":{"operationId":"startAgentSetup","tags":["Agent setup"],"summary":"Start browser-assisted setup","description":"Creates a short-lived setup session used by an agent to hand authorization to the developer.","security":[],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}}}}},"responses":{"200":{"description":"Setup session created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupStartResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/setup/status/{sessionId}":{"get":{"operationId":"getAgentSetupStatus","tags":["Agent setup"],"summary":"Read setup status","description":"Returns pending, expired, or authorized setup state without exposing account credentials.","security":[],"parameters":[{"name":"sessionId","in":"path","required":true,"description":"Short-lived setup session identifier.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Current setup state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupStatusResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/setup/complete/{sessionId}":{"post":{"operationId":"completeAgentSetup","tags":["Agent setup"],"summary":"Complete browser-assisted setup","description":"Associates the authorized account, app, forms, delivery preference, and Slack routing with the setup session.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"description":"Short-lived setup session identifier.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupCompleteRequest"}}}},"responses":{"200":{"description":"Setup completion result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/setup/ensure-ready":{"post":{"operationId":"ensureAgentSetupReady","tags":["Agent setup"],"summary":"Ensure required setup resources exist","description":"Creates or reuses the requested app and forms, validates bundle identity, and returns the installation contract.","security":[{"bearerAuth":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnsureReadyRequest"}}}},"responses":{"200":{"description":"Agent installation contract.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/analytics/events":{"post":{"operationId":"recordPublicProductEvent","tags":["Analytics"],"summary":"Record an anonymous public-site event","description":"Accepts only the documented privacy-limited public event names and no cookies or referrer data.","security":[],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAnalyticsEvent"}}}},"responses":{"202":{"description":"Event accepted.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"accepted":{"type":"boolean","const":true}},"required":["accepted"]}}}},"default":{"description":"Structured error with a stable code and a recovery hint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Paydirt account token returned after Google authorization."},"sdkKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Public app-specific SDK key. It is not an account secret."},"bundleId":{"type":"apiKey","in":"header","name":"X-Paydirt-Bundle-ID","description":"Installed iOS bundle identifier when bundle enforcement is enabled."}},"schemas":{"ErrorResponse":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string","description":"Backward-compatible human-readable error."},"code":{"type":"string","pattern":"^[A-Z0-9_]+$","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"resolution":{"type":"string","description":"Concrete recovery hint safe for an agent to follow."},"request_id":{"type":"string","description":"Identifier for support and log correlation."},"links":{"type":"object","additionalProperties":{"type":"string","format":"uri"}}},"required":["error","code","message","resolution","request_id"]},"SuccessResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean"}},"required":["success"]},"HealthResponse":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","const":"ok"},"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}},"required":["status","version","timestamp"]},"App":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"bundle_id":{"type":["string","null"]},"api_key":{"type":"string","pattern":"^pk_live_"},"app_description":{"type":["string","null"]},"system_prompt":{"type":["string","null"]},"app_context_prompt":{"type":["string","null"]},"enforce_bundle_id":{"type":"boolean"},"response_retention_days":{"type":"integer","minimum":1,"maximum":3650},"feedback_delivery_preference":{"type":"string","enum":["unconfigured","both","slack","agents"]},"created_at":{"type":"string","format":"date-time"}},"required":["id","name","api_key","enforce_bundle_id","response_retention_days","created_at"]},"AppCreateRequest":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1},"bundle_id":{"type":"string"},"app_description":{"type":"string"},"system_prompt":{"type":"string"},"app_context_prompt":{"type":"string"},"enforce_bundle_id":{"type":"boolean"},"response_retention_days":{"type":"integer","minimum":1,"maximum":3650,"default":365}},"required":["name"]},"AppUpdateRequest":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1},"bundle_id":{"type":["string","null"]},"app_description":{"type":["string","null"]},"system_prompt":{"type":["string","null"]},"app_context_prompt":{"type":["string","null"]},"enforce_bundle_id":{"type":"boolean"},"response_retention_days":{"type":"integer","minimum":1,"maximum":3650},"feedback_delivery_preference":{"type":"string","enum":["unconfigured","both","slack","agents"]}},"minProperties":1},"Form":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"app_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["cancellation","trial_expiration","feature_request","custom"]},"prompt":{"type":"string"},"custom_system_prompt":{"type":["string","null"]},"slack_channel_id":{"type":["string","null"]},"enabled":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}},"required":["id","app_id","name","type","prompt","enabled","created_at"]},"FormCreateRequest":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1},"type":{"type":"string","enum":["cancellation","trial_expiration","feature_request","custom"]},"prompt":{"type":"string","minLength":1},"custom_system_prompt":{"type":"string"},"slack_channel_id":{"type":["string","null"]}},"required":["name","type","prompt"]},"FormUpdateRequest":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"type":{"type":"string","enum":["cancellation","trial_expiration","feature_request","custom"]},"prompt":{"type":"string"},"custom_system_prompt":{"type":["string","null"]},"slack_channel_id":{"type":["string","null"]},"enabled":{"type":"boolean"}},"minProperties":1},"ConversationTurn":{"type":"object","additionalProperties":false,"properties":{"role":{"type":"string","enum":["assistant","user"]},"content":{"type":"string","minLength":1,"maxLength":10000},"input_type":{"type":"string","enum":["text","audio"]}},"required":["role","content"]},"ConversationMessageRequest":{"type":"object","additionalProperties":false,"properties":{"form_id":{"type":"string","format":"uuid"},"message":{"type":"string","minLength":1},"conversation_history":{"type":"array","items":{"$ref":"#/components/schemas/ConversationTurn"}},"app_context":{"type":"string"},"previous_response_id":{"type":"string"}},"required":["form_id","message"]},"ConversationMessageResponse":{"type":"object","additionalProperties":false,"properties":{"follow_up_question":{"type":"string"},"is_complete":{"type":"boolean"},"response_id":{"type":["string","null"]}},"required":["follow_up_question","is_complete"]},"ResponseSnapshotRequest":{"type":"object","additionalProperties":false,"properties":{"form_id":{"type":"string","format":"uuid"},"user_id_external":{"type":"string"},"conversation":{"type":"array","items":{"$ref":"#/components/schemas/ConversationTurn"}},"metadata":{"type":"object","additionalProperties":true,"description":"Optional subscription context such as provider, product, price, period, expiration, and cancellation timestamp."},"idempotency_key":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["in_progress","completed","abandoned"],"default":"completed"},"snapshot_version":{"type":"integer","minimum":0,"default":0}},"required":["form_id","conversation"]},"FeedbackResponse":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"form_id":{"type":"string","format":"uuid"},"app_id":{"type":"string","format":"uuid"},"user_id_external":{"type":["string","null"]},"conversation":{"type":"array","items":{"$ref":"#/components/schemas/ConversationTurn"}},"ai_summary":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":true},"status":{"type":"string","enum":["in_progress","completed","abandoned"]},"snapshot_version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"slack_sent_at":{"type":["string","null"],"format":"date-time"}},"required":["id","form_id","app_id","conversation","status","created_at","updated_at"]},"DeliveryReceipt":{"type":"object","additionalProperties":false,"properties":{"response_id":{"type":"string","format":"uuid"},"received":{"type":"boolean"},"completed":{"type":"boolean"},"slack_configured":{"type":"boolean"},"slack_delivered":{"type":"boolean"}},"required":["response_id","received","completed","slack_configured","slack_delivered"]},"SummaryResponse":{"type":"object","additionalProperties":false,"properties":{"summary":{"type":"string"},"top_reasons":{"type":"array","items":{"type":"string"}},"response_count":{"type":"integer","minimum":0},"period":{"type":"string"}},"required":["summary","top_reasons","response_count","period"]},"AskFeedbackRequest":{"type":"object","additionalProperties":false,"properties":{"question":{"type":"string","minLength":1},"form_id":{"type":"string","format":"uuid"},"days":{"type":"integer","minimum":1,"default":30}},"required":["question"]},"AskFeedbackResponse":{"type":"object","additionalProperties":false,"properties":{"answer":{"type":"string"},"response_count":{"type":"integer","minimum":0},"days":{"type":"integer"}},"required":["answer","response_count"]},"SlackDestinationsRequest":{"type":"object","additionalProperties":false,"properties":{"feature_channel_id":{"type":["string","null"],"pattern":"^[CG][A-Z0-9]+$","description":"Destination for feature_request and custom forms, or null when neither exists."},"cancellation_channel_id":{"type":["string","null"],"pattern":"^[CG][A-Z0-9]+$","description":"Destination for cancellation and trial_expiration forms, or null when neither exists."}},"required":["feature_channel_id","cancellation_channel_id"]},"SlackChannelsResponse":{"type":"object","additionalProperties":false,"properties":{"channels":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"team_name":{"type":["string","null"]}},"required":["channels"]},"SlackStatusResponse":{"type":"object","additionalProperties":true,"required":["connected","two_channel_routing","all_forms_assigned"],"properties":{"connected":{"type":"boolean"},"two_channel_routing":{"type":"boolean"},"all_forms_assigned":{"type":"boolean"}}},"GoogleAuthRequest":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"}},"required":["code"]},{"type":"object","additionalProperties":false,"properties":{"googleId":{"type":"string"},"email":{"type":"string","format":"email"}},"required":["googleId","email"]}]},"AuthResponse":{"type":"object","additionalProperties":false,"properties":{"token":{"type":"string"},"user":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"}},"required":["id","email"]}},"required":["token","user"]},"SetupStartResponse":{"type":"object","additionalProperties":false,"properties":{"session_id":{"type":"string","format":"uuid"},"expires_in":{"type":"integer","const":1800}},"required":["session_id","expires_in"]},"SetupStatusResponse":{"type":"object","additionalProperties":false,"required":["status"],"properties":{"status":{"type":"string","enum":["pending","ready","expired"]},"api_key":{"type":"string"},"auth_token":{"type":"string"},"app_id":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["created","reused","repaired"]},"forms":{"type":"array","items":{"$ref":"#/components/schemas/PreparedSetupForm"}},"delivery_preference":{"type":["string","null"],"enum":["both","slack","agents",null]}}},"PreparedSetupForm":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["cancellation","trial_expiration","feature_request","custom"]},"name":{"type":"string"},"created":{"type":"boolean"}},"required":["id","type","name"]},"SetupCompleteRequest":{"type":"object","additionalProperties":false,"properties":{"api_key":{"type":"string","pattern":"^pk_live_"},"app_id":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["created","reused","repaired"]},"forms":{"type":"array","items":{"$ref":"#/components/schemas/PreparedSetupForm"}},"delivery_preference":{"type":"string","enum":["both","slack","agents"]}},"required":["api_key","app_id"]},"EnsureReadyRequest":{"type":"object","additionalProperties":false,"properties":{"app_id":{"type":"string","format":"uuid"},"bundle_id":{"type":"string"},"app_name":{"type":"string"},"app_description":{"type":"string"},"required_forms":{"type":"array","maxItems":4,"items":{"type":"string","enum":["cancellation","trial_expiration","feature_request","custom"]}},"create_if_missing":{"type":"boolean","default":true}}},"SlackEventRequest":{"type":"object","additionalProperties":true,"properties":{"type":{"type":"string"},"challenge":{"type":"string"},"event":{"type":"object","additionalProperties":true}}},"SlackEventResponse":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"challenge":{"type":"string"}},"required":["challenge"]},{"type":"object","additionalProperties":false,"properties":{"ok":{"type":"boolean","const":true}},"required":["ok"]}]},"PublicAnalyticsEvent":{"type":"object","additionalProperties":false,"properties":{"event_name":{"type":"string","enum":["site_view","agent_docs_view"]},"anonymous_session_id":{"type":"string"},"source":{"type":"string"},"path":{"type":"string"}},"required":["event_name"]}}}}