{"openapi":"3.0.0","paths":{"/v1/iam/auth/signin":{"post":{"operationId":"signIn","summary":"Sign in user","description":"Authenticate a user with email and password credentials. Returns JWT tokens (access, refresh, and ID tokens) that can be used to access protected endpoints. The access token expires in 1 hour and should be included in the Authorization header as \"Bearer <token>\". Use the refresh token with /iam/auth/refresh to obtain a new access token without re-authenticating.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInDto"},"examples":{"example1":{"summary":"Basic signin","value":{"email":"developer@example.com","password":"SecurePassword123!"}}}}}},"responses":{"200":{"description":"Successfully authenticated - returns JWT tokens and user information","content":{"application/json":{"schema":{"example":{"success":true,"message":"Successfully signed in","tokens":{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMyIsImVtYWlsIjoiZGV2ZWxvcGVyQGV4YW1wbGUuY29tIiwiaWF0IjoxNjk5MDAwMDAwLCJleHAiOjE2OTkwMDM2MDB9...","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMyIsInR5cGUiOiJyZWZyZXNoIiwiaWF0IjoxNjk5MDAwMDAwLCJleHAiOjE3MDE1OTIwMDB9...","idToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMyIsImVtYWlsIjoiZGV2ZWxvcGVyQGV4YW1wbGUuY29tIiwibmFtZSI6IkpvaG4gRG9lIn0...","expiresIn":3600},"user":{"id":"user-123","email":"developer@example.com","name":"John Doe","createdAt":"2025-10-01T00:00:00.000Z"}}}}}},"400":{"description":"Bad request - missing or invalid fields","content":{"application/json":{"schema":{"example":{"success":false,"message":"Validation failed","errors":["email must be a valid email","password is required"],"statusCode":400}}}}},"401":{"description":"Authentication failed - invalid email or password","content":{"application/json":{"schema":{"example":{"success":false,"message":"Invalid email or password","statusCode":401}}}}}},"tags":["Authentication"]}},"/v1/iam/auth/legal-documents":{"get":{"operationId":"getLegalDocuments","summary":"Get current signup legal documents","description":"Fetch this registry projection at runtime, display every returned document, and echo the exact metadata in the signup request only after explicit acceptance.","parameters":[],"responses":{"200":{"description":"Current legal-document metadata","content":{"application/json":{"schema":{"type":"object","required":["documents"],"properties":{"documents":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"object","required":["document_kind","document_version","document_effective_date"],"properties":{"document_kind":{"type":"string","enum":["terms","privacy","dpa"]},"document_version":{"type":"string"},"document_effective_date":{"type":"string","format":"date"}}}}}}}}},"503":{"description":"Signup is unavailable because the legal-document registry is not configured or contains documents that are not yet effective"}},"tags":["Authentication"]}},"/v1/iam/auth/signup":{"post":{"operationId":"signUp","summary":"Sign up new user","description":"Register a new user account to access the BillerAPI platform. Fetch GET /v1/iam/auth/legal-documents, display the returned documents, and submit their exact metadata after explicit acceptance. Password must be at least 12 characters with uppercase, lowercase, numbers, and special characters.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignUpDto"},"examples":{"example1":{"summary":"New user registration","value":{"email":"newdev@example.com","password":"SecurePass123!","given_name":"Jane","family_name":"Developer","client_name":"Example integration","legal_acceptances":[{"document_kind":"terms","document_version":"<copy terms document_version from registry>","document_effective_date":"<copy terms document_effective_date from registry>","accepted":true},{"document_kind":"privacy","document_version":"<copy privacy document_version from registry>","document_effective_date":"<copy privacy document_effective_date from registry>","accepted":true}],"terms_accepted":true,"terms_version":"<copy terms document_version from registry>","privacy_version":"<copy privacy document_version from registry>","accepted_at":"2026-08-24T12:34:56.000Z","acceptance_source":"billerapi_cli"}}}}}},"responses":{"201":{"description":"User created and signed in successfully","content":{"application/json":{"schema":{"example":{"success":true,"message":"User created successfully","user_id":"user-456","client_id":"client-456"}}}}},"400":{"description":"Bad request - validation failed or email already exists","content":{"application/json":{"schema":{"example":{"success":false,"message":"Email already exists","statusCode":400}}}}}},"tags":["Authentication"]}},"/v1/iam/auth/signout":{"post":{"operationId":"signOut","summary":"Sign out user","description":"Invalidate user access token","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignOutDto"}}}},"responses":{"200":{"description":"Successfully signed out"}},"tags":["Authentication"]}},"/v1/iam/auth/confirm-signup":{"post":{"operationId":"confirmSignUp","summary":"Confirm email signup","description":"Verify email with confirmation code","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmSignUpDto"}}}},"responses":{"200":{"description":"Email confirmed successfully"},"400":{"description":"Invalid or expired code"}},"tags":["Authentication"]}},"/v1/iam/auth/confirm-and-signin":{"post":{"operationId":"confirmAndSignIn","summary":"Confirm email and sign in","description":"Confirm email with verification code and sign in. Returns tokens and user (same shape as signin). Use when the user has just verified their email and should be logged in without a separate sign-in step.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmSignUpAndSignInDto"}}}},"responses":{"200":{"description":"Email confirmed and signed in - returns JWT tokens and user information","content":{"application/json":{"schema":{"example":{"success":true,"message":"Email confirmed and signed in","tokens":{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","idToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","expiresIn":3600},"user":{"id":"user-123","email":"developer@example.com","given_name":"John","family_name":"Doe"}}}}}},"400":{"description":"Invalid or expired code"},"401":{"description":"Invalid password after confirmation"}},"tags":["Authentication"]}},"/v1/iam/auth/forgot-password":{"post":{"operationId":"forgotPassword","summary":"Request password reset","description":"Send password reset code to email","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordDto"}}}},"responses":{"200":{"description":"Reset code sent"}},"tags":["Authentication"]}},"/v1/iam/auth/reset-password":{"post":{"operationId":"resetPassword","summary":"Reset password with code","description":"Set new password using reset code","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"200":{"description":"Password reset successfully"},"400":{"description":"Invalid or expired code"}},"tags":["Authentication"]}},"/v1/iam/auth/refresh":{"post":{"operationId":"refreshToken","summary":"Refresh access token","description":"Get new access token using refresh token","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenDto"}}}},"responses":{"200":{"description":"New access token issued","content":{"application/json":{"schema":{"example":{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","expires_in":3600}}}}},"401":{"description":"Invalid or expired refresh token"}},"tags":["Authentication"]}},"/v1/iam/auth/email/request-verification":{"post":{"operationId":"requestEmailVerification","summary":"Request an email verification code","description":"Sends a 6-digit code to the authenticated user's email address via Resend. Required before transitioning from sandbox to development environment. Returns 429 with cooldown_seconds when called within 5 minutes of a previous request.","parameters":[],"responses":{"200":{"description":"Code generated and sent","content":{"application/json":{"schema":{"example":{"success":true,"message":"Verification code sent. Check your email.","cooldown_seconds":300,"error_code":""}}}}},"401":{"description":"Unauthorized"},"429":{"description":"Still inside the cooldown window — retry after `retry_after` seconds"},"503":{"description":"The verification email could not be sent"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/auth/email/verify":{"post":{"operationId":"verifyEmail","summary":"Verify an email verification code","description":"Submits a 6-digit code received by email. On success, the user's Client.emailVerified flag is set to true and the dashboard banner disappears. After 5 wrong attempts, the user is locked out for 15 minutes.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailCodeDto"}}}},"responses":{"200":{"description":"Verification attempted (check success field)","content":{"application/json":{"schema":{"example":{"success":true,"message":"Email verified.","error_code":""}}}}},"401":{"description":"Unauthorized"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/auth/change-password":{"post":{"operationId":"changePassword","summary":"Change password (authenticated)","description":"Rotate the signed-in user's password. On success the server invokes AdminUserGlobalSignOut to invalidate ALL refresh tokens (including any other devices the user is signed in on), then re-issues a fresh token pair for the current session. The bb_client_auth_token cookie is rotated in place.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordDto"}}}},"responses":{"200":{"description":"Password change attempted (check success field)","content":{"application/json":{"schema":{"example":{"success":true,"message":"Password updated.","error_code":""}}}}},"401":{"description":"Unauthorized"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/auth/me":{"get":{"operationId":"getProfile","summary":"Get user profile","description":"Retrieve the authenticated user's profile information including email, name, and account details. Requires a valid JWT access token in the Authorization header.","parameters":[],"responses":{"200":{"description":"User profile retrieved successfully","content":{"application/json":{"schema":{"example":{"success":true,"user":{"id":"user-123","email":"developer@example.com","name":"John Doe","companyName":"My Company","emailVerified":true,"createdAt":"2025-10-01T00:00:00.000Z","updatedAt":"2025-11-01T00:00:00.000Z"}}}}}},"401":{"description":"Unauthorized - invalid or expired token","content":{"application/json":{"schema":{"example":{"success":false,"message":"Unauthorized","statusCode":401}}}}}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/verification-request":{"post":{"operationId":"submitVerificationRequest","summary":"Submit verification request","description":"Submit business/use-case form to request production access. A team member will review and verify your client.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitVerificationRequestDto"}}}},"responses":{"200":{"description":"Verification request submitted"},"400":{"description":"Already verified or invalid request"},"401":{"description":"Unauthorized"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/request-live-access":{"post":{"operationId":"requestLiveAccess","summary":"Request live (dev + prod) access","description":"#2404 — explicit user-driven request to flip live-access on. Requires email verified, business form submitted, and billing setup completed. In dev, auto-approves. In prod, the handler will queue an operator review (not yet wired).","parameters":[],"responses":{"200":{"description":"Live access granted"},"400":{"description":"Prerequisites not met"},"401":{"description":"Unauthorized"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients":{"get":{"operationId":"listClients","summary":"List clients","description":"Get all API clients for the authenticated user","parameters":[],"responses":{"200":{"description":"List of clients","content":{"application/json":{"schema":{"example":{"clients":[{"id":"client-123","name":"My Application","createdAt":"2025-11-01T00:00:00Z"}]}}}}}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"post":{"operationId":"createClient","summary":"Create client application","description":"Create a new API client to access BillerAPI services. Each client represents an application or integration that will use the BillerAPI API. After creating a client, use the /iam/clients/:id/client-secrets endpoint to generate credentials (client_id and client_secret) for each environment.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientDto"},"examples":{"example1":{"summary":"Production application","value":{"name":"My Bill Pay App","description":"Production bill payment integration","redirectUris":["https://myapp.com/callback"],"allowedOrigins":["https://myapp.com"]}}}}}},"responses":{"201":{"description":"Client created successfully - now generate client secrets for each environment","content":{"application/json":{"schema":{"example":{"success":true,"message":"Client created successfully","client":{"id":"client-abc123","name":"My Bill Pay App","description":"Production bill payment integration","userId":"user-123","redirectUris":["https://myapp.com/callback"],"allowedOrigins":["https://myapp.com"],"createdAt":"2025-11-01T00:00:00.000Z","updatedAt":"2025-11-01T00:00:00.000Z"}}}}}},"400":{"description":"Bad request - invalid client configuration","content":{"application/json":{"schema":{"example":{"success":false,"message":"Validation failed","errors":["name is required","redirectUris must be valid URLs"],"statusCode":400}}}}}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{id}":{"get":{"operationId":"getClient","summary":"Get client by ID","description":"Retrieve client details","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Client details"},"404":{"description":"Client not found"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"put":{"operationId":"updateClient","summary":"Update client","description":"Update client configuration","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClientDto"}}}},"responses":{"200":{"description":"Client updated"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"delete":{"operationId":"deleteClient","summary":"Delete client","description":"Permanently delete an API client","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Client deleted"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{id}/embed-origins":{"get":{"operationId":"getClientEmbedOrigins","summary":"Resolve a client's registered embed origins by client_id (#6090)","description":"Lightweight public resolver for hosted Elements frame-ancestors CSP and postMessage trust. Returns only the owning client's allowed_embed_origins and PCI approval bit. Fails closed to an empty list.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Registered embed origins resolved"}},"tags":["Authentication"]}},"/v1/iam/clients/{id}/client-secrets":{"post":{"operationId":"generateClientSecret","summary":"Generate client secret","description":"Create a new client secret for API authentication. The plaintext is returned exactly once and is never stored in the HTTP replay cache. A retry under the same Idempotency-Key returns 409 IDEMPOTENCY_KEY_NOT_REPLAYABLE; recover with a fresh key.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateClientSecretDto"}}}},"responses":{"201":{"description":"Client secret created","content":{"application/json":{"schema":{"example":{"success":true,"secret":{"id":"secret-456","clientId":"client-123","secret":"sk_live_abc123...","environment":"production","createdAt":"2025-11-01T00:00:00Z"}}}}}},"409":{"description":"The Idempotency-Key already delivered a one-time secret and cannot replay it (`IDEMPOTENCY_KEY_NOT_REPLAYABLE`)"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"get":{"operationId":"listClientSecrets","summary":"List client secrets","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{id}/client-secrets/{environment}":{"get":{"operationId":"getClientSecret","summary":"Get client secret by environment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"environment","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"delete":{"operationId":"revokeClientSecret","summary":"Revoke client secret","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"environment","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{id}/client-secrets/{environment}/rotate":{"post":{"operationId":"rotateClientSecret","summary":"Rotate client secret","description":"Mints a replacement client secret and revokes the previous one in a single atomic\nswap. The plaintext secret is returned exactly once, in this response — store it\nbefore you acknowledge the call. Nothing server-side keeps a copy you can read back:\nthe response body is never written to the idempotency replay store, and no endpoint\nreturns a production secret.\n\n**A same-key retry cannot replay this response.** The first request claims its\n`Idempotency-Key` and stores only a secret-free completion receipt. Reusing that key\nreturns `409 IDEMPOTENCY_KEY_NOT_REPLAYABLE` and does not rotate again. A\nrotation whose response was lost is not recoverable: rotate again with a fresh key.\n\n**Concurrent rotations.** Rotation is a compare-and-swap on the credential holder,\nso two rotations in flight for the same (client, environment) cannot both commit.\nExactly one succeeds; the other returns `409` with\n`error_code: \"CLIENT_SECRET_ROTATION_CONFLICT\"` having changed nothing — this is what\na double-clicked \"Rotate\" surfaces. Re-read the current secret before retrying.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"environment","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Client secret rotated; the new secret is returned once"},"409":{"description":"Rotation conflict (`CLIENT_SECRET_ROTATION_CONFLICT`) or consumed one-time response (`IDEMPOTENCY_KEY_NOT_REPLAYABLE`); nothing was changed"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{clientId}/webhooks":{"post":{"operationId":"registerWebhook","summary":"Register webhook","description":"Register a webhook endpoint to receive event notifications","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}},{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterWebhookDto"}}}},"responses":{"201":{"description":"Webhook registered","content":{"application/json":{"schema":{"example":{"success":true,"webhook":{"id":"webhook-789","url":"https://myapp.com/webhooks/billbutler","events":["bill.created","bill.updated"],"environment":"production","enabled":true,"secret":"whsec_abc123..."}}}}}}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"get":{"operationId":"getWebhooks","summary":"Get webhooks for client","description":"List all registered webhooks","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"example":{"webhooks":[{"id":"webhook-789","url":"https://myapp.com/webhooks","events":["bill.created"],"environment":"production"}]}}}}}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{clientId}/client-secrets/{environment}/webhook":{"put":{"operationId":"updateWebhookConfiguration","summary":"Update webhook configuration","description":"Update webhook URL and events for an environment","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}},{"name":"environment","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookDto"}}}},"responses":{"200":{"description":"Webhook updated"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]},"get":{"operationId":"getWebhookConfiguration","summary":"Get webhook configuration","description":"Retrieve webhook details for an environment","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}},{"name":"environment","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook details"},"404":{"description":"Webhook not found"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{clientId}/webhooks/{webhookId}":{"delete":{"operationId":"deleteWebhook","summary":"Delete webhook subscription","description":"Removes a webhook subscription. Emits a webhook_endpoint.deleted activity event for the audit feed.","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}},{"name":"webhookId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook deleted","content":{"application/json":{"schema":{"example":{"success":true,"message":"Webhook deleted","webhook_id":"webhook-789"}}}}},"404":{"description":"Webhook not found"}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{clientId}/webhooks/{webhookId}/test":{"post":{"operationId":"testWebhook","summary":"Send a test webhook delivery","description":"POSTs a signed synthetic event to the registered webhook URL. The event_type must be included in the subscription. #6262: the delivery OUTCOME is reported in a 200 envelope — a non-2xx from your endpoint sets success=false and status_code, and never becomes the status of this API call.","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}},{"name":"webhookId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestWebhookDto"}}}},"responses":{"200":{"description":"Delivery attempt finished. Branch on `success`: false means your endpoint rejected the delivery (`status_code` is its HTTP status, or 0 when no HTTP response was received at all — DNS/TLS/connect/timeout, with the transport error in `message`).","content":{"application/json":{"schema":{"example":{"success":true,"status_code":200,"delivery_id":"evt_test_abc123","message":"Test webhook delivered"}}}}}},"tags":["Authentication"],"security":[{"jwt-auth":[]}]}},"/v1/sandbox/account-links":{"post":{"operationId":"createSandboxAccountLink","summary":"Create a sandbox account link without Connect","description":"Creates an owner-scoped, deterministic account link directly in Sandbox so server-side integrations can test bill retrieval without running the Connect SDK. This endpoint accepts sandbox API keys only. The initial sandbox event sequence is produced once (`bill.created` when the fixture has bills, followed by `connection.ready`); because Connect did not run, `link.completed` is never generated. Configure webhook subscriptions before this request if you want to observe those initial events.\n\nIdempotency is scoped to the authenticated client. Repeating the same request body with the same `Idempotency-Key` returns the original 201 response and does not generate duplicate events. Reusing the key with a different body returns 409 `IDEMPOTENCY_CONFLICT`. Revoking the created link removes its replay record, so a later request with the same key creates a new link.","servers":[{"url":"https://sandbox.api.billerapi.com","description":"Sandbox only"}],"parameters":[{"name":"Idempotency-Key","required":true,"in":"header","description":"1-255 printable ASCII characters. Reuse only when retrying the identical request body.","schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\u0020-\\u007E]+$","example":"create-test-link-user-123"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxAccountLinkDto"},"example":{"biller_id":"sb_utility","scenario":"success","client_user_id":"user_123"}}}},"responses":{"201":{"description":"Account link created, or the original response replayed for an identical idempotent retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxAccountLinkResponseDto"}}}},"400":{"description":"`INVALID_INPUT`: malformed idempotency key or body, unknown field, invalid biller, or invalid scenario value.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"401":{"description":"`UNAUTHORIZED`: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"403":{"description":"`WRONG_ENVIRONMENT`: a production API key was sent to the sandbox endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"409":{"description":"`IDEMPOTENCY_CONFLICT`: this client already used the key with a different request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"422":{"description":"`FIXTURE_UNAVAILABLE`: the scenario requires Connect or has no direct-link fixture.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"429":{"description":"`CAPACITY_EXCEEDED`: this client already has 100 active direct sandbox account links. Revoke one or wait for expiry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}}},"tags":["Account Linking"],"security":[{"client-api-key":[]}]}},"/v1/sandbox/account-links/{account_link_id}":{"delete":{"operationId":"revokeSandboxAccountLink","summary":"Revoke a directly created sandbox account link","description":"Revokes an active account link created by `POST /v1/sandbox/account-links`. Ownership is scoped to the authenticated client. Connect-created links cannot be revoked through this endpoint. After success, bill reads for this link return an empty page; retrying the original create request may create a new link because revocation removes that resource's idempotency replay record.","servers":[{"url":"https://sandbox.api.billerapi.com","description":"Sandbox only"}],"parameters":[{"name":"account_link_id","required":true,"in":"path","description":"Direct sandbox account-link identifier returned by the create endpoint.","schema":{"type":"string","pattern":"^sandbox_link_[a-f0-9]{24}$","example":"sandbox_link_0123456789abcdef01234567"}}],"responses":{"200":{"description":"The account link was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeSandboxAccountLinkResponseDto"}}}},"401":{"description":"`UNAUTHORIZED`: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"403":{"description":"`WRONG_ENVIRONMENT`: a production API key was sent to the sandbox endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}},"404":{"description":"`NOT_FOUND`: the link does not exist, has expired, belongs to another client, was already revoked, or was created through Connect.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxErrorResponseDto"}}}}},"tags":["Account Linking"],"security":[{"client-api-key":[]}]}},"/v1/bills":{"get":{"operationId":"getBills","summary":"Get bills for account link","description":"Retrieve bills filtered by account link and date range. Requires client credentials. `total_count` is the number of bills in this response page, not the total number across every page; use `has_more` and `next_cursor` to continue.","parameters":[{"name":"account_link_id","required":true,"in":"query","description":"Account link ID","schema":{"example":"link-456","type":"string"}},{"name":"start_date","required":false,"in":"query","description":"Start date (ISO format)","schema":{"example":"2025-01-01","type":"string"}},{"name":"end_date","required":false,"in":"query","description":"End date (ISO format)","schema":{"example":"2025-12-31","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of bills to return (1-500)","schema":{"example":100,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Pagination cursor","schema":{"example":"cursor_abc123","type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Unique key for safely retrying this billable bill-fetch request.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of bills","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillListResponseDto"}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]},"post":{"operationId":"createClientBill","summary":"Create an owner-scoped manual bill","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientBillDto"}}}},"responses":{"201":{"description":"Owner-scoped Bill created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientBillResponseDto"}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/sync/trigger":{"post":{"operationId":"triggerBillSync","summary":"Trigger bill sync","description":"Initiate a bill synchronization for an account link","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerBillSyncDto"}}}},"responses":{"202":{"description":"Sync initiated","content":{"application/json":{"schema":{"example":{"syncId":"sync-789","status":"INITIATED","account_link_id":"link-456"}}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/backfill-payment-matches":{"post":{"operationId":"backfillBillPaymentMatches","summary":"Backfill bill-paid signals","description":"One-shot replay of historical ObservedPayments + Statements through the matcher pipeline for an accountLinkId. Idempotent — safe to re-run.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackfillBillPaymentMatchesDto"}}}},"responses":{"200":{"description":"Backfill complete","content":{"application/json":{"schema":{"example":{"success":true,"observed_payments_processed":24,"observed_payments_applied":18,"statements_processed":6,"statement_credits_applied":3}}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/{id}/transitions":{"get":{"operationId":"listBillTransitions","summary":"List bill audit transitions","description":"Returns the append-only timeline of every status flip on a bill, with the signal that drove each transition and an evidence reference (payment_id / statement_id / attempt_id).","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Transition list","content":{"application/json":{"schema":{"example":{"transitions":[{"transition_id":"...","bill_id":"b-1","from_status":"PENDING","to_status":"PAID","signal":"OBSERVED_PAYMENT","paid_reason":"OBSERVED_PAYMENT","evidence_payment_id":"op-1","occurred_at":"2026-05-29T14:00:00Z"}],"next_cursor":"","has_more":false}}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/links/{linkId}/accounts/{accountId}/outstanding":{"get":{"operationId":"getAccountOutstandingSummary","summary":"Get carry-over-safe outstanding balance for an account","description":"Anchors on the latest fresh Statement; falls back to sum-of-unpaid when no fresh statement exists. Avoids double-counting prior-balance carry-over on utility-style billers.","parameters":[{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}},{"name":"accountId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Outstanding summary","content":{"application/json":{"schema":{"example":{"outstanding_balance":170,"currency":"USD","as_of_statement_date":"2026-04-15","freshness":"fresh","freshness_hint_reason":"","freshness_hint_action":"","freshness_hint_retry_after":0}}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/sync":{"get":{"operationId":"getSyncStatus","summary":"Get sync status for account link","description":"Check the synchronization status for an account link","parameters":[{"name":"account_link_id","required":true,"in":"query","description":"Account link ID to sync","schema":{"example":"link-456","type":"string"}},{"name":"since","required":false,"in":"query","description":"Sync bills since this date","schema":{"example":"2025-01-01T00:00:00Z","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of bills to sync","schema":{"example":100,"type":"number"}},{"name":"include_deleted","required":false,"in":"query","description":"Include deleted bills","schema":{"example":false,"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"account_link_id":"link-456","status":"COMPLETED","billsFound":5,"completedAt":"2025-11-01T12:00:00Z"}}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/accounts":{"get":{"operationId":"getAccounts","summary":"Get connected accounts","description":"Retrieve all connected accounts for the authenticated client","parameters":[],"responses":{"200":{"description":"Connected accounts"}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/{id}/statement":{"get":{"operationId":"getStatement","summary":"Get the statement for a bill","description":"Returns the structured statement (period, balance breakdown, line items, biller metadata) for the bill. Returns 425 STATEMENT_NOT_EXTRACTED when extraction has not yet succeeded — call POST /:id/statement/refresh to trigger.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Statement payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatementDto"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"404":{"description":"Bill not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"425":{"description":"Statement not yet extracted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/{id}/statement/refresh":{"post":{"operationId":"refreshStatement","summary":"Refresh a bill statement","description":"Triggers asynchronous statement extraction for the bill. Returns 202 immediately with a request_id; clients poll the request_id for completion (status endpoint TBD in a follow-up PR) or subscribe to bill.statement.refreshed webhooks. Idempotent: identical Idempotency-Key headers within 5 minutes return the same in-flight request_id.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshStatementBodyDto"}}}},"responses":{"202":{"description":"Refresh accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshStatementResponseDto"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"404":{"description":"Bill not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"422":{"description":"Biller does not support refresh","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/{id}/statement/refresh/{request_id}":{"get":{"operationId":"getRefreshStatus","summary":"Get refresh status by request_id","description":"Returns the lifecycle of a refresh dispatched via POST /:id/statement/refresh. Status is \"pending\" until the extraction worker completes; then \"complete\" or \"failed\". Records expire 24h after creation. Cross-tenant lookups return 404 (no existence leak).","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"request_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Refresh request status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"404":{"description":"Request not found or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bills/webhooks/test-events":{"post":{"operationId":"fireTestWebhookEvent","summary":"Fire a synthetic webhook event (test-only)","description":"Publishes a synthetic bill.paid / bill.partially_paid / bill.status_reverted event to the caller's registered webhook URL through the standard delivery pipeline (signing, retries, subscription filter).","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FireTestWebhookEventDto"}}}},"responses":{"202":{"description":"Event published","content":{"application/json":{"schema":{"example":{"event_id":"evt_synth_1234","event_type":"bill.paid"}}}}}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/bill_imports":{"post":{"operationId":"create","summary":"Create a bill import and direct-upload target","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBillImportDto"}}}},"responses":{"201":{"description":"Import and presigned upload target created."}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]}},"/v1/bill_imports/{id}/complete_upload":{"post":{"operationId":"completeUpload","summary":"Verify the immutable upload and start processing","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteBillImportUploadDto"}}}},"responses":{"202":{"description":"Upload accepted for asynchronous processing."}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]}},"/v1/bill_imports/{id}":{"get":{"operationId":"retrieve","summary":"Retrieve a bill import","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-client-user-id","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Client-User-ID","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]},"delete":{"operationId":"cancel","summary":"Cancel an uncommitted import and schedule document deletion","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-client-user-id","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Client-User-ID","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]}},"/v1/bill_imports/{id}/source_document":{"get":{"operationId":"getSourceDocument","summary":"Get a short-lived URL for the imported source document","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-client-user-id","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Client-User-ID","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]}},"/v1/bill_imports/{id}/review_draft":{"patch":{"operationId":"updateReviewDraft","summary":"Conditionally update the review draft","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBillImportReviewDraftDto"}}}},"responses":{"409":{"description":"Draft version conflict with current draft."}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]}},"/v1/bill_imports/{id}/confirm":{"post":{"operationId":"confirm","summary":"Atomically commit the reviewed import to one Bill","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmBillImportDto"}}}},"responses":{"200":{"description":"Import committed to a canonical Bill.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmBillImportResponseDto"}}}},"409":{"description":"Lifecycle or draft version conflict."}},"tags":["Bill imports"],"security":[{"client-api-key":[]}]}},"/v1/bills/{id}/attest_external_payment":{"post":{"operationId":"attestExternalPayment","summary":"Attest that an EXTERNAL_ONLY bill was paid elsewhere","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttestExternalPaymentDto"}}}},"responses":{"201":{"description":""}},"tags":["Bills"],"security":[{"client-api-key":[]}]}},"/v1/insights":{"get":{"operationId":"listInsights","summary":"List insights for an account","description":"Returns insights for a specific account (account_id) under one of your biller connections (account_link_id), newest first. Both account_link_id and account_id are required. Optionally filter by user_aid and status. Cursor-paginated.","parameters":[{"name":"account_link_id","required":true,"in":"query","description":"The account_link_id (biller connection) to list insights for.","schema":{"example":"alink_01HX...","type":"string"}},{"name":"account_id","required":true,"in":"query","description":"The account_id (the account within the connection) to list insights for.","schema":{"example":"acct_01HX...","type":"string"}},{"name":"user_aid","required":false,"in":"query","description":"Optional filter to insights for a specific end-user (your client_user_id).","schema":{"example":"user_42","type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by lifecycle status.","schema":{"example":"OPEN","enum":["OPEN","SNOOZED","DISMISSED","RESOLVED"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of insights to return (1-100).","schema":{"example":50,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor from a prior response.","schema":{"example":"cursor_abc123","type":"string"}}],"responses":{"200":{"description":"List of insights","content":{"application/json":{"schema":{"example":{"insights":[{"id":"insight_01HX5...","user_aid":"user_42","account_link_id":"alink_01HX...","account_id":"acct_01HX...","biller_id":"test_electric_company","bill_id":"bill_01HX...","type":"duplicate_charge","severity":"warn","status":"OPEN","evidence":{},"proposed_actions":[{"action_type":"review_bill","label":"Review bill","params":{}}],"reasoning":"Two charges of the same amount within 24h.","created_at":"2026-06-13T12:00:00.000Z","snoozed_until":null,"resolved_at":null}],"has_more":false,"next_cursor":""}}}}}},"tags":["Insights"],"security":[{"client-api-key":[]}]}},"/v1/insights/{id}":{"get":{"operationId":"getInsightById","summary":"Get an insight by id","description":"Returns a single insight with full evidence, proposed actions, and reasoning. Cross-tenant lookups return 404 (no existence leak).","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_aid","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Insight detail"},"404":{"description":"Insight not found"}},"tags":["Insights"],"security":[{"client-api-key":[]}]}},"/v1/insights/{id}/snooze":{"post":{"operationId":"snoozeInsight","summary":"Snooze an insight","description":"Snooze the insight until a future instant. Idempotent on the same `until`.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_aid","required":true,"in":"query","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnoozeInsightBodyDto"}}}},"responses":{"200":{"description":"Snoozed insight"},"404":{"description":"Insight not found"}},"tags":["Insights"],"security":[{"client-api-key":[]}]}},"/v1/insights/{id}/dismiss":{"post":{"operationId":"dismissInsight","summary":"Dismiss an insight","description":"Dismiss the insight (terminal). Idempotent once dismissed.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_aid","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Dismissed insight"},"404":{"description":"Insight not found"}},"tags":["Insights"],"security":[{"client-api-key":[]}]}},"/v1/insights/{id}/resolve":{"post":{"operationId":"resolveInsight","summary":"Resolve an insight","description":"Resolve the insight. Terminal after a dismiss (the user action wins).","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_aid","required":true,"in":"query","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveInsightBodyDto"}}}},"responses":{"200":{"description":"Resolved insight"},"404":{"description":"Insight not found"}},"tags":["Insights"],"security":[{"client-api-key":[]}]}},"/v1/billers":{"get":{"operationId":"listBillers","summary":"List billers","description":"Retrieve list of available billers with optional filtering. Requires client credentials.","parameters":[{"name":"search_term","required":false,"in":"query","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","schema":{"type":"string"}},{"name":"consent_scope","required":false,"in":"query","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of billers to return (1–500, default 100).","schema":{"minimum":1,"maximum":500,"default":100,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor from a prior response’s `next_cursor`. Omit for the first page; the response always returns `next_cursor` / `has_more`.","schema":{"type":"string"}},{"name":"sort_by","required":false,"in":"query","schema":{"type":"string"}},{"name":"sort_order","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"List of billers"}},"tags":["Billers"],"security":[{"client-api-key":[]}]}},"/v1/billers/search/by-email":{"get":{"operationId":"searchBillersByEmail","summary":"Search billers by email domain","description":"Find billers matching an email domain","parameters":[{"name":"email","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Matching billers"}},"tags":["Billers"],"security":[{"client-api-key":[]}]}},"/v1/billers/{id}":{"patch":{"operationId":"updateBillerType","summary":"Correct an agent-classified biller type","description":"Updates the biller_type on an existing BillerConfig. Only biller_type is settable from this public endpoint; full editing is operator-only.","parameters":[{"name":"id","required":true,"in":"path","description":"BillerConfig ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBillerTypeDto"}}}},"responses":{"200":{"description":"Biller updated"},"400":{"description":"Invalid biller_type"},"404":{"description":"Biller not found"}},"tags":["Billers"],"security":[{"client-api-key":[]}]},"get":{"operationId":"getById","summary":"Get biller by id (global catalog)","description":"Returns the biller catalog entry (name, type, status, capability flags). Authenticated portal users may view any catalog biller; per-client scoping lives in the activity feed, not the entity itself. 404 if unknown id.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Biller entity."},"401":{"description":"No portal session (NEEDS_RESIGNIN)."},"404":{"description":"Biller not found (BILLER_NOT_FOUND)."}},"tags":["Billers"]}},"/v1/emails/messages/{messageId}/attachments/{attachmentId}/download-url":{"get":{"operationId":"getAttachmentDownloadUrl","summary":"Get presigned download URL for email attachment","parameters":[{"name":"messageId","required":true,"in":"path","schema":{"type":"string"}},{"name":"attachmentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns presigned download URL"},"404":{"description":"Message or attachment not found"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails":{"get":{"operationId":"getMessages","summary":"Get email messages for client","parameters":[],"responses":{"200":{"description":"Returns paginated email messages"},"401":{"description":"Unauthorized - invalid client credentials"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]},"post":{"operationId":"createMessage","summary":"Create a new email message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailMessageDto"}}}},"responses":{"201":{"description":"Message created successfully"},"400":{"description":"Invalid message data"},"401":{"description":"Unauthorized - invalid client credentials"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/gmail/connection/{connectionId}":{"delete":{"operationId":"disconnectGmailConnection","summary":"Disconnect a Gmail connection","parameters":[{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Gmail connection disconnected"},"401":{"description":"Unauthorized - invalid client credentials"},"404":{"description":"Connection not found"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]},"get":{"operationId":"getGmailConnection","summary":"Get Gmail connection details","parameters":[{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns Gmail connection details"},"401":{"description":"Unauthorized - invalid client credentials"},"404":{"description":"Connection not found"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/{messageId}":{"get":{"operationId":"getMessageById","summary":"Get email message by ID","parameters":[{"name":"messageId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns message details"},"401":{"description":"Unauthorized - invalid client credentials"},"404":{"description":"Message not found"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/classify":{"post":{"operationId":"classifyEmail","summary":"Classify an email message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassifyEmailDto"}}}},"responses":{"200":{"description":"Email classification started successfully"},"401":{"description":"Unauthorized - invalid client credentials"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/classification/{classificationId}":{"get":{"operationId":"getClassification","summary":"Get classification result by ID","parameters":[{"name":"classificationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns classification details"},"401":{"description":"Unauthorized - invalid client credentials"},"404":{"description":"Classification not found"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/find-biller":{"post":{"operationId":"findBillerByEmail","summary":"Find biller by email sender","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindBillerByEmailDto"}}}},"responses":{"200":{"description":"Returns biller information if found"},"401":{"description":"Unauthorized - invalid client credentials"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/workflows":{"get":{"operationId":"listWorkflows","summary":"List email processing workflows","parameters":[],"responses":{"200":{"description":"Returns list of workflows"},"401":{"description":"Unauthorized - invalid client credentials"}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/gmail/oauth-sessions":{"post":{"operationId":"createGmailOAuthSession","summary":"Create a short-lived Gmail OAuth PKCE session","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGmailOAuthSessionDto"}}}},"responses":{"200":{"description":"Session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionResponseDto"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/gmail/oauth-sessions/{session_id}/complete":{"post":{"operationId":"completeGmailOAuthSession","summary":"Complete an authorized Gmail OAuth PKCE session","parameters":[{"name":"session_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteGmailOAuthSessionDto"}}}},"responses":{"200":{"description":"Session reached a terminal state synchronously","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionResponseDto"}}}},"202":{"description":"Completion accepted; poll session status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionAcceptedResponseDto"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/emails/gmail/oauth-sessions/{session_id}":{"get":{"operationId":"getGmailOAuthSession","summary":"Get Gmail OAuth session completion status","parameters":[{"name":"session_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_id","required":true,"in":"query","description":"End user id used when this session was created.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionResponseDto"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailOAuthSessionErrorResponseDto"}}}}},"tags":["Email Discovery"],"security":[{"client-api-key":[]}]}},"/v1/metering/api-calls":{"get":{"operationId":"getApiCallRecords","summary":"Get API call records for client","description":"Retrieve API usage metrics for billing and monitoring. Requires client credentials.","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"test-client-123","type":"string"}},{"name":"start_date","required":false,"in":"query","description":"Start date (ISO format)","schema":{"example":"2025-01-01","type":"string"}},{"name":"end_date","required":false,"in":"query","description":"End date (ISO format)","schema":{"example":"2025-12-31","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of records to return","schema":{"example":"100","type":"string"}},{"name":"next_token","required":false,"in":"query","description":"Opaque pagination cursor. Pass the `next_token` from a previous response to fetch the following page. Omit for the first page.","schema":{"type":"string"}},{"name":"include_portal_noise","required":false,"in":"query","description":"When 'true', include portal-browsing requests (session-mode 2xx GETs) in the response. Default 'false' hides them. Errors and integration calls are always shown regardless.","schema":{"example":"false","enum":["true","false"],"type":"string"}},{"name":"env","required":false,"in":"query","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true,"schema":{"type":"string"}},{"name":"environment","required":false,"in":"query","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"records":[{"endpoint":"/bills","method":"GET","statusCode":200,"responseTime":125,"timestamp":"2025-11-01T12:00:00Z"}],"totalCalls":1234}}}}}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/webhook-deliveries":{"get":{"operationId":"getWebhookDeliveryRecords","summary":"Get webhook delivery records","description":"Track webhook delivery success rates and history","parameters":[{"name":"webhook_url","required":false,"in":"query","description":"Webhook URL to filter delivery records","schema":{"example":"https://example.com/webhooks","type":"string"}},{"name":"client_id","required":false,"in":"query","description":"Client ID","schema":{"example":"test-client-123","type":"string"}},{"name":"start_date","required":false,"in":"query","description":"Start date (ISO format)","schema":{"example":"2025-01-01","type":"string"}},{"name":"end_date","required":false,"in":"query","description":"End date (ISO format)","schema":{"example":"2025-12-31","type":"string"}},{"name":"event_type","required":false,"in":"query","description":"Event type filter","schema":{"example":"bill.created","type":"string"}},{"name":"delivery_status","required":false,"in":"query","description":"Delivery status filter","schema":{"example":"delivered","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max records to return","schema":{"example":50,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"records":[{"id":"wd_01HXA7C2F3K9M4P8Q","client_id":"client-123","webhook_url":"https://example.com/hook","event_type":"bill.created","status_code":200,"delivery_status":"SUCCESS","timestamp":"2025-11-01T12:00:00Z","attempt_number":1,"max_attempts":3,"delivery_group_id":"dg_01HXA7C2F3K9M4P8Q","latency_ms":142}]}}}}}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/accounts/active":{"get":{"operationId":"getActiveAccountCount","summary":"Get active account count","description":"Get the number of active account links for billing purposes","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"test-client-123","type":"string"}},{"name":"date","required":false,"in":"query","description":"Date to check active accounts (ISO format)","schema":{"example":"2025-11-01","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"clientId":"test-client-123","activeAccounts":15,"date":"2025-11-01"}}}}}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/accounts/snapshot":{"get":{"operationId":"getAccountSnapshot","summary":"Get account snapshot","description":"Historical snapshot of account counts for a specific date","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"test-client-123","type":"string"}},{"name":"date","required":false,"in":"query","description":"Snapshot date (ISO format)","schema":{"example":"2025-11-01","type":"string"}}],"responses":{"200":{"description":"Account snapshot data"}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/consumption-usage":{"get":{"operationId":"getConsumptionUsage","summary":"Get consumption usage (bill fetch / bill pay counts)","description":"Get bill fetch and bill pay counts for a client in a date range for billing","parameters":[{"name":"clientId","required":true,"in":"query","schema":{"type":"string"}},{"name":"startDate","required":true,"in":"query","schema":{"type":"string"}},{"name":"endDate","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"success":true,"bill_fetch_count":100,"bill_pay_count":25,"message":"Consumption usage retrieved successfully"}}}}}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/api-calls/{id}":{"get":{"operationId":"getApiCallRecordById","summary":"Get single API call record with full payload detail","description":"Retrieve a single API call record including request/response payloads. Used for expandable log detail view.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"clientId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"API call record with payloads"},"404":{"description":"Record not found"}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/api-calls/{id}/with-relations":{"get":{"operationId":"getApiCallRecordWithRelations","summary":"Get API call with its webhook deliveries and related requests","description":"Composite drilldown payload for the /logs detail drawer. Returns the request plus every webhook delivery triggered by its correlation_id plus every request sharing its idempotency_key (newest first, capped at 20).","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"clientId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"API call with relations"},"404":{"description":"Record not found"}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/account-link-events":{"get":{"operationId":"getAccountLinkRecords","summary":"Get account link events","description":"List account link/unlink events for the Events timeline","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"test-client-123","type":"string"}},{"name":"start_date","required":false,"in":"query","description":"Start date (ISO format)","schema":{"example":"2025-01-01","type":"string"}},{"name":"end_date","required":false,"in":"query","description":"End date (ISO format)","schema":{"example":"2025-12-31","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max records to return","schema":{"example":"100","type":"string"}},{"name":"next_token","required":false,"in":"query","description":"Opaque pagination cursor. Pass the `next_token` from a previous response to fetch the following page. Omit for the first page.","schema":{"type":"string"}}],"responses":{"200":{"description":"Account link events"}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/metering/consumption-events":{"get":{"operationId":"getConsumptionRecords","summary":"Get consumption events (bill fetches, bill payments)","description":"List individual consumption events for the Events timeline","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"test-client-123","type":"string"}},{"name":"start_date","required":false,"in":"query","description":"Start date (ISO format)","schema":{"example":"2025-01-01","type":"string"}},{"name":"end_date","required":false,"in":"query","description":"End date (ISO format)","schema":{"example":"2025-12-31","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max records to return","schema":{"example":"100","type":"string"}},{"name":"next_token","required":false,"in":"query","description":"Opaque pagination cursor. Pass the `next_token` from a previous response to fetch the following page. Omit for the first page.","schema":{"type":"string"}}],"responses":{"200":{"description":"Consumption events"}},"tags":["Metering"],"security":[{"client-api-key":[]}]}},"/v1/webhook-endpoints":{"post":{"operationId":"create","summary":"Create a webhook endpoint","description":"Registers a new webhook endpoint for the authenticated environment. Returns the whsec_ signing secret ONCE in the response — it is never shown again (rotate to get a new one). N endpoints per environment are supported; each has its own event filter and secret.","parameters":[{"name":"Idempotency-Key","in":"header","description":"Stable printable-ASCII key (1-255 characters) for this registration.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookEndpointDto"}}}},"responses":{"201":{"description":"Endpoint created; secret returned once. May carry an additive `warnings` array — WEBHOOK_URL_NOT_PUBLICLY_DELIVERABLE means the URL does not resolve to a public address, so deliveries to it will be refused. The endpoint is still created (#6361); a future API version will reject instead (#6472)."},"400":{"description":"Missing or malformed Idempotency-Key."},"401":{"description":"Missing/invalid client credentials."},"409":{"description":"Idempotency-Key reused with different parameters."},"503":{"description":"Outcome unknown; retry with the same Idempotency-Key."}},"tags":["Webhook Endpoints"],"security":[{"client-api-key":[]}]},"get":{"operationId":"list","summary":"List webhook endpoints","description":"Lists every webhook endpoint registered for the authenticated environment. Signing secrets are NEVER included in list responses.","parameters":[],"responses":{"200":{"description":"List of endpoints (no secrets)."}},"tags":["Webhook Endpoints"],"security":[{"client-api-key":[]}]}},"/v1/webhook-endpoints/{id}":{"get":{"operationId":"getOne","summary":"Get a webhook endpoint","description":"Fetches a single webhook endpoint by id. No signing secret in the response.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"The endpoint (no secret)."},"404":{"description":"Unknown or cross-client id (WEBHOOK_ENDPOINT_NOT_FOUND)."}},"tags":["Webhook Endpoints"],"security":[{"client-api-key":[]}]},"patch":{"operationId":"update","summary":"Update a webhook endpoint","description":"Updates a webhook endpoint (url, events filter, enabled state, description). Only supplied fields change. No secret in the response.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Stable printable-ASCII key (1-255 characters) for this update.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookEndpointDto"}}}},"responses":{"200":{"description":"Updated endpoint (no secret)."},"400":{"description":"Missing or malformed Idempotency-Key."},"404":{"description":"Unknown or cross-client id (WEBHOOK_ENDPOINT_NOT_FOUND)."},"409":{"description":"Concurrent update or key reuse with different parameters."},"503":{"description":"Outcome unknown; retry with the same Idempotency-Key."}},"tags":["Webhook Endpoints"],"security":[{"client-api-key":[]}]},"delete":{"operationId":"remove","summary":"Delete a webhook endpoint","description":"Removes a webhook endpoint. Idempotent from the caller's view (404 on unknown id).","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Endpoint deleted."},"404":{"description":"Unknown or cross-client id (WEBHOOK_ENDPOINT_NOT_FOUND)."}},"tags":["Webhook Endpoints"],"security":[{"client-api-key":[]}]}},"/v1/webhook-endpoints/{id}/rotate-secret":{"post":{"operationId":"rotateSecret","summary":"Rotate a webhook endpoint signing secret","description":"Generates a NEW whsec_ signing secret for the endpoint and returns it ONCE. The previous secret stays valid for a 24h grace window — during that window deliveries are signed with BOTH secrets, so a consumer can roll its verification over to the new secret without dropped events. After the window the old secret stops verifying. Retries must reuse the same Idempotency-Key so an ambiguous outcome can be recovered while the receipt and current endpoint state still agree.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Stable printable-ASCII key (1-255 characters) for this rotation.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Rotated; new secret returned once, previous_secret_expires_at is the grace deadline."},"400":{"description":"Missing or malformed Idempotency-Key."},"404":{"description":"Unknown or cross-client id (WEBHOOK_ENDPOINT_NOT_FOUND)."},"409":{"description":"Idempotency-Key reused for a different rotation."},"503":{"description":"Outcome unknown; retry with the same Idempotency-Key."}},"tags":["Webhook Endpoints"],"security":[{"client-api-key":[]}]}},"/v1/customers/{user_aid}/messages":{"post":{"operationId":"sendMessage","summary":"Deprecated compatibility message sender","description":"Fintech client credentials do not authorize a caller to speak for a biller. Use the authenticated biller producer surface instead.","deprecated":true,"parameters":[],"responses":{"403":{"description":"Fintech credentials cannot speak for a biller."}},"tags":["Customer Messaging"],"security":[{"client-api-key":[]}]}},"/v1/customers/{user_aid}/consents":{"post":{"operationId":"updateConsent","summary":"Update customer's per-category consent","parameters":[{"name":"user_aid","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerConsentDto"}}}},"responses":{"200":{"description":""}},"tags":["Customer Messaging"],"security":[{"client-api-key":[]}]},"get":{"operationId":"getConsents","summary":"Inspect customer's per-category consent state","parameters":[{"name":"user_aid","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Customer Messaging"],"security":[{"client-api-key":[]}]}},"/v1/customers/{user_aid}/complaints":{"post":{"operationId":"recordComplaint","summary":"Record a customer complaint about a message","parameters":[{"name":"user_aid","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordCustomerComplaintDto"}}}},"responses":{"202":{"description":"Complaint recorded; suppression added; webhook fan-out triggered."}},"tags":["Customer Messaging"],"security":[{"client-api-key":[]}]}},"/v1/clients/me/suppressions":{"get":{"operationId":"list","summary":"List suppression rows for this client","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list"}},"tags":["Customer Messaging"],"security":[{"client-api-key":[]}]}},"/v1/clients/me/suppressions/{user_aid}":{"delete":{"operationId":"remove","summary":"Manually remove a suppression row","parameters":[{"name":"user_aid","required":true,"in":"path","schema":{"type":"string"}},{"name":"biller_id","required":true,"in":"query","schema":{"type":"string"}},{"name":"category","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Customer Messaging"],"security":[{"client-api-key":[]}]}},"/v1/request-to-links":{"get":{"operationId":"list","summary":"List request-to-link records for the calling client","parameters":[{"name":"limit","required":false,"in":"query","description":"Page size (1–200, default 50).","schema":{"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor from a prior response’s `next_cursor`. Omit for the first page; the response always returns `next_cursor` / `has_more`.","schema":{"type":"string"}}],"responses":{"200":{"description":"List of request-to-link records"}},"tags":["Request To Link"],"security":[{"client-api-key":[]}]},"post":{"operationId":"create","summary":"Create a request-to-link resource","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequestToLinkDto"}}}},"responses":{"201":{"description":""}},"tags":["Request To Link"],"security":[{"client-api-key":[]}]}},"/v1/request-to-links/{id}":{"get":{"operationId":"getById","summary":"Get request-to-link details","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Request-to-link details"},"404":{"description":"Request-to-link not found"}},"tags":["Request To Link"],"security":[{"client-api-key":[]}]}},"/v1/request-to-links/{id}/status":{"patch":{"operationId":"updateStatus","summary":"Update request-to-link status","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRequestToLinkStatusDto"}}}},"responses":{"200":{"description":""}},"tags":["Request To Link"],"security":[{"client-api-key":[]}]}},"/v1/request-to-links/{id}/cancel":{"post":{"operationId":"cancel","summary":"Cancel request-to-link","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelRequestToLinkDto"}}}},"responses":{"201":{"description":""}},"tags":["Request To Link"],"security":[{"client-api-key":[]}]}},"/v1/request-to-links/{id}/proceed":{"post":{"operationId":"proceed","summary":"Proceed request-to-link to link session","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["Request To Link"],"security":[{"client-api-key":[]}]}},"/v1/link-tokens/validate":{"post":{"operationId":"validateLinkToken","summary":"Validate link token","description":"Validate a link token via gRPC","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateLinkTokenBodyDto"}}}},"responses":{"200":{"description":"Token validated successfully"},"400":{"description":"Invalid token"}},"tags":["Account Linking"]}},"/v1/access-tokens/validate":{"post":{"operationId":"validateAccessToken","summary":"Validate access token","description":"Validate an access token via gRPC","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateAccessTokenBodyDto"}}}},"responses":{"200":{"description":"Access token validated successfully"},"400":{"description":"Invalid access token"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/status":{"get":{"operationId":"getLinkTokenStatus","summary":"Get link token status","description":"Get the status of a link token","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Link token status retrieved successfully"},"404":{"description":"Link token not found"}},"tags":["Account Linking"]}},"/v1/link-tokens/hosted/{token}/status":{"get":{"operationId":"getHostedSessionStatus","summary":"Poll hosted connect session status (#4768)","description":"Lightweight status poll for the hosted connect page, keyed by the opaque link-token string. Never returns the public token.","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Session status retrieved"},"404":{"description":"Unknown link token"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/flow-state":{"get":{"operationId":"getFlowState","summary":"Get flow state","description":"Get the current flow state of a link token","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Flow state retrieved successfully"},"404":{"description":"Link token not found"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/billers":{"get":{"operationId":"listBillersForLinkToken","summary":"List billers for a link token","description":"Returns available billers, scoped to a valid link token. Used by the connect iframe biller picker.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}},{"name":"bootstrap","required":true,"in":"query","description":"Must be `true`. The bootstrap payload is the only supported shape for this route.","schema":{"example":true,"type":"boolean"}},{"name":"preselected_biller_id","required":false,"in":"query","description":"Biller to hydrate into `preselected_biller` so the modal can open at consent. Accepts EITHER the prefixed id returned by `GET /v1/billers` (`biller_<uuid>`) or the bare uuid returned on this route's own `billers[].id`. Unknown ids are not an error — `preselected_biller` is simply omitted.","schema":{"example":"biller_9f2a1c34-5b6d-4e7f-8a9b-0c1d2e3f4a5b","type":"string"}}],"responses":{"200":{"description":"Billers retrieved successfully"},"401":{"description":"Invalid or expired link token"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/billers/search":{"post":{"operationId":"searchBillersForLinkToken","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkBillerDirectorySearchDto"}}}},"responses":{"200":{"description":""}},"tags":["Account Linking"]}},"/v1/link-tokens/{token}/embed-origins":{"get":{"operationId":"getLinkTokenEmbedOrigins","summary":"Resolve a link token's registered embed origins (#4783)","description":"Lightweight resolver for the hosted connect page's dynamic frame-ancestors CSP. Returns only the owning client's allowed_embed_origins. Fails closed to an empty list.","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Registered embed origins resolved"},"401":{"description":"Invalid or expired link token"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/stream":{"options":{"operationId":"handleSSEPreflight","summary":"SSE preflight","description":"Handle CORS preflight for SSE endpoint","parameters":[],"responses":{"200":{"description":""}},"tags":["Account Linking"]},"get":{"operationId":"streamLinkTokenUpdates","summary":"Stream link token updates","description":"Establish SSE connection to receive real-time link token status updates via gRPC stream","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream established"},"404":{"description":"Link token not found"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/public-token":{"get":{"operationId":"getPublicToken","summary":"Get public token","description":"Get the public token for a link token","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Public token retrieved successfully"},"404":{"description":"Link token not found or public token not generated"}},"tags":["Account Linking"]}},"/v1/links/{linkId}/status":{"get":{"operationId":"getLinkStatus","summary":"Get link status","description":"Get the status of a link","parameters":[{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Link status retrieved successfully"},"404":{"description":"Link not found"}},"tags":["Account Linking"]}},"/v1/links/{linkId}":{"get":{"operationId":"getLink","summary":"Get link","description":"Get link details by link ID","parameters":[{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Link retrieved successfully"},"404":{"description":"Link not found"}},"tags":["Account Linking"]},"put":{"operationId":"updateLink","summary":"Update link","description":"Update link details","parameters":[{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLinkBodyDto"}}}},"responses":{"200":{"description":"Link updated successfully"},"404":{"description":"Link not found"}},"tags":["Account Linking"]},"delete":{"operationId":"deleteLink","summary":"Delete link","description":"Delete a link","parameters":[{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Link deleted successfully"},"404":{"description":"Link not found"}},"tags":["Account Linking"]}},"/v1/links/{linkId}/confirm-region":{"post":{"operationId":"confirmLinkUserRegion","summary":"Confirm Link userRegion (#3729 follow-up)","description":"Affirm or override user_region on a Link; stamps regionConfirmedAt.","parameters":[{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmLinkUserRegionBodyDto"}}}},"responses":{"200":{"description":"Confirmation persisted"},"404":{"description":"Link not found"}},"tags":["Account Linking"]}},"/v1/link-tokens":{"post":{"operationId":"createLinkToken","summary":"Create link token","description":"Create a new link token for initiating account linking flow. Server-to-server: requires client credentials.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkTokenBodyDto"}}}},"responses":{"201":{"description":"Link token created successfully"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid client credentials"},"403":{"description":"Body client_id does not match the authenticated client, or update.link_id names a Link owned by another client/user"},"404":{"description":"update.link_id names a Link that does not exist"}},"tags":["Account Linking"],"security":[{"client-api-key":[]}]}},"/v1/link-tokens/{linkTokenId}/select-biller":{"post":{"operationId":"selectBiller","summary":"Select biller","description":"Select a biller for the linking flow","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectBillerBodyDto"}}}},"responses":{"200":{"description":"Biller selected successfully"},"400":{"description":"Invalid request"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/credentials":{"put":{"operationId":"submitCredentialsPut","summary":"Submit credentials (PUT)","description":"Submit credentials using credentialId (matches frontend SDK)","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitCredentialsPutBodyDto"}}}},"responses":{"200":{"description":"Credentials submitted successfully"},"400":{"description":"Invalid credentials"},"429":{"description":"Too many submission attempts — throttled (#3627)"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/submit-credentials":{"post":{"operationId":"submitCredentials","summary":"Submit credentials (POST)","description":"Submit user credentials for account linking using username/password","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitCredentialsBodyDto"}}}},"responses":{"200":{"description":"Credentials submitted successfully"},"400":{"description":"Invalid credentials"},"429":{"description":"Too many submission attempts — throttled (#3627)"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/submit-mfa":{"post":{"operationId":"submitMfa","summary":"Submit MFA code","description":"Submit MFA verification code. Resolves credentialId + challengeId server-side from LinkToken + PendingMfa; the iframe only sends the user-typed OTP.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitMfaBodyDto"}}}},"responses":{"200":{"description":"MFA code submitted successfully"},"400":{"description":"Invalid request body"},"404":{"description":"LinkToken not found"},"409":{"description":"LinkToken in wrong state or no active MFA challenge"},"422":{"description":"PendingMfa carries no usable challenge"},"429":{"description":"Too many submission attempts — throttled (#3627)"},"502":{"description":"Vault upstream failed to record submission"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/resend-mfa":{"post":{"operationId":"resendMfa","summary":"Resend MFA code","description":"Request a fresh MFA code. Re-drives the biller login server-side; the iframe only sends the link token in the path.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Fresh MFA code requested"},"400":{"description":"Invalid request"},"404":{"description":"LinkToken not found"},"409":{"description":"LinkToken not awaiting an MFA challenge"},"429":{"description":"Resend rate limit exceeded"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/discover-accounts":{"post":{"operationId":"discoverAccounts","summary":"Discover accounts","description":"Trigger account discovery for the link token","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverAccountsBodyDto"}}}},"responses":{"200":{"description":"Accounts discovered successfully"},"400":{"description":"Failed to discover accounts"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/select-accounts":{"post":{"operationId":"selectAccounts","summary":"Select accounts","description":"Select accounts to link and complete the flow","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectAccountsBodyDto"}}}},"responses":{"200":{"description":"Accounts selected successfully"},"400":{"description":"Invalid account selection"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/background":{"post":{"operationId":"backgroundLinkToken","summary":"Continue connect flow in background (#4786)","description":"Marks the link token for backgrounded auto-completion: all discovered accounts are auto-selected and the public token is exchanged server-side.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"Link token backgrounded"},"400":{"description":"Link token not eligible for backgrounding"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/exit":{"post":{"operationId":"reportHostedSessionExit","summary":"Report hosted connect session exit (#4768)","description":"Reports a user-initiated close/abandon of the hosted connect page. Emits the link.session_finished (exited) webhook.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportHostedSessionExitBodyDto"}}}},"responses":{"201":{"description":"Exit recorded"},"400":{"description":"Invalid request"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/events":{"post":{"operationId":"recordConnectEvent","summary":"Ingest a hosted connect-event for the server-side funnel (#4918)","description":"Raw-appends one connect/* taxonomy event keyed by the link token. Fire-and-forget: always returns 201, never surfaces telemetry failure to the client. Strict metadata allowlist (no PII).","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordConnectEventBodyDto"}}}},"responses":{"201":{"description":"Event accepted (fire-and-forget)"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/set-region":{"post":{"operationId":"setUserRegion","summary":"Set user region on LinkToken (#3729)","description":"Persist the user-selected region for region-gated billers.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetUserRegionBodyDto"}}}},"responses":{"200":{"description":"Region persisted"},"400":{"description":"Invalid region payload"}},"tags":["Account Linking"]}},"/v1/link-tokens/{linkTokenId}/exchange":{"post":{"operationId":"exchangePublicToken","summary":"Exchange public token","description":"Exchange a public token for an access token. Server-to-server: requires client credentials.","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangePublicTokenBodyDto"}}}},"responses":{"200":{"description":"Token exchanged successfully"},"400":{"description":"Invalid public token"},"401":{"description":"Missing or invalid client credentials"},"403":{"description":"Body client_id does not match the authenticated client"}},"tags":["Account Linking"],"security":[{"client-api-key":[]}]}},"/v1/link-tokens/{linkTokenId}/complete":{"post":{"operationId":"completeFlow","summary":"Complete linking flow","description":"Explicitly complete the linking flow for a link token","parameters":[{"name":"linkTokenId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Flow completed successfully"},"400":{"description":"Invalid request or flow cannot be completed"}},"tags":["Account Linking"]}},"/v1/links/{id}":{"get":{"operationId":"getById","summary":"Get link by id for the authenticated client","description":"Returns the full link entity (biller, status, scopes, dates, accounts) scoped to the session client_id. 404 if the link is unknown; 403 CLIENT_ID_MISMATCH if it belongs to a different client. The `:id` accepts BOTH the Stripe-style prefixed form `link_<uuid>` and a bare UUID (bare UUIDs remain accepted for backwards compatibility); responses return the prefixed `link_<uuid>` form.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Link entity."},"401":{"description":"No portal session (NEEDS_RESIGNIN)."},"403":{"description":"Link belongs to a different client (CLIENT_ID_MISMATCH)."},"404":{"description":"Link not found (LINK_NOT_FOUND)."}},"tags":["Links"]}},"/v1/activity":{"get":{"operationId":"list","summary":"List activity events for the authenticated client","description":"Returns a time-descending page of activity events scoped to the session's client_id. Filter by event_type (repeatable), resource (resource_type + resource_id), or time window. Pagination via opaque cursor. Default page size 50, max 200.","parameters":[{"name":"event_type","required":false,"in":"query","description":"Event type filter (repeatable). OR semantics across values.","schema":{"example":["webhook.delivered","webhook.delivery-failed"],"type":"array","items":{"type":"string"}}},{"name":"resource_type","required":false,"in":"query","description":"Resource type filter (e.g. \"link\", \"bill\")","schema":{"type":"string"}},{"name":"resource_id","required":false,"in":"query","description":"Resource ID filter; pairs with resource_type","schema":{"type":"string"}},{"name":"since","required":false,"in":"query","description":"ISO 8601 lower bound (inclusive)","schema":{"example":"2026-01-01T00:00:00Z","type":"string"}},{"name":"until","required":false,"in":"query","description":"ISO 8601 upper bound (exclusive)","schema":{"example":"2026-02-01T00:00:00Z","type":"string"}},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor from a prior response","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size; default 50, clamped to [1, 200]","schema":{"example":50,"type":"number"}},{"name":"correlation_id","required":false,"in":"query","description":"Filter to events with this correlation_id (the x-correlation-id of the originating request).","schema":{"type":"string"}},{"name":"env","required":false,"in":"query","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true,"schema":{"type":"string"}},{"name":"environment","required":false,"in":"query","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Page of activity events."},"401":{"description":"No portal session (NEEDS_RESIGNIN)."},"403":{"description":"client_id query did not match session (CLIENT_ID_MISMATCH)."}},"tags":["Activity"]}},"/v1/activity/.csv":{"get":{"operationId":"listCsv","summary":"Export activity events as CSV","description":"Same filters as GET /v1/activity. Returns a CSV download (Content-Disposition: attachment). Capped at the same page size as the JSON endpoint — for larger windows, paginate with cursor.","parameters":[{"name":"event_type","required":false,"in":"query","description":"Event type filter (repeatable). OR semantics across values.","schema":{"example":["webhook.delivered","webhook.delivery-failed"],"type":"array","items":{"type":"string"}}},{"name":"resource_type","required":false,"in":"query","description":"Resource type filter (e.g. \"link\", \"bill\")","schema":{"type":"string"}},{"name":"resource_id","required":false,"in":"query","description":"Resource ID filter; pairs with resource_type","schema":{"type":"string"}},{"name":"since","required":false,"in":"query","description":"ISO 8601 lower bound (inclusive)","schema":{"example":"2026-01-01T00:00:00Z","type":"string"}},{"name":"until","required":false,"in":"query","description":"ISO 8601 upper bound (exclusive)","schema":{"example":"2026-02-01T00:00:00Z","type":"string"}},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor from a prior response","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size; default 50, clamped to [1, 200]","schema":{"example":50,"type":"number"}},{"name":"correlation_id","required":false,"in":"query","description":"Filter to events with this correlation_id (the x-correlation-id of the originating request).","schema":{"type":"string"}},{"name":"env","required":false,"in":"query","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true,"schema":{"type":"string"}},{"name":"environment","required":false,"in":"query","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"CSV file with one row per activity event."}},"tags":["Activity"]}},"/v1/activity/{id}":{"get":{"operationId":"getById","summary":"Fetch a single activity event by id","description":"Returns the event scoped to the session's client_id. 404 when the event is not found or belongs to a different client.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Single activity event."},"401":{"description":"No portal session (NEEDS_RESIGNIN)."},"404":{"description":"Event not found for this client."}},"tags":["Activity"]}},"/v1/activity/{id}/deliveries":{"get":{"operationId":"getDeliveries","summary":"Per-event webhook delivery timeline","description":"Returns the time-ordered list of webhook delivery attempts (succeeded / failed / exhausted) that fired for this event. Joined by correlation_id. Empty array when the event has no deliveries; 404 if the source event is missing.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Delivery timeline for the event."},"401":{"description":"No portal session."},"404":{"description":"Source event not found for this client."}},"tags":["Activity"]}},"/v1/activity/{id}/related":{"get":{"operationId":"getRelated","summary":"Other activity events sharing this event's correlation_id","description":"Returns the time-ordered list of activity events that share the source event's correlation_id, minus the source itself. Empty array when the event has no correlation_id; 404 if the source is missing.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Related events for the trace."},"401":{"description":"No portal session."},"404":{"description":"Source event not found for this client."}},"tags":["Activity"]}},"/v1/activity/replay":{"post":{"operationId":"replay","summary":"Replay a webhook delivery from the activity feed","description":"Re-enqueue a webhook delivery for re-send. delivery_id mirrors the activity row resource_id for webhook events. Rate-limited 1/30s/delivery; 429 carries retry_after_ms.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayActivityDto"}}}},"responses":{"201":{"description":"Replay initiated."},"422":{"description":"Delivery has no backing dead letter (not replayable)."},"429":{"description":"Rate limited; retry after retry_after_ms."}},"tags":["Activity"]}},"/v1/webhook-deliveries":{"get":{"operationId":"getDeliveryRecords","summary":"Get webhook delivery records","description":"Retrieve delivery history for a client","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"client-123","type":"string"}},{"name":"start_date","required":false,"in":"query","description":"Start date (ISO format)","schema":{"type":"string"}},{"name":"end_date","required":false,"in":"query","description":"End date (ISO format)","schema":{"type":"string"}},{"name":"event_type","required":false,"in":"query","description":"Filter by event type","schema":{"type":"string"}},{"name":"delivery_status","required":false,"in":"query","description":"Filter by delivery status (SUCCESS/FAILED)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max records to return","schema":{"default":50,"type":"number"}}],"responses":{"200":{"description":"Delivery records returned"}},"tags":["Webhook Deliveries"],"security":[{"jwt-auth":[]}]}},"/v1/webhook-deliveries/dead-letters":{"get":{"operationId":"getDeadLetters","summary":"Get dead letter webhooks","description":"Retrieve webhooks that exhausted all retries","parameters":[{"name":"client_id","required":true,"in":"query","description":"Client ID","schema":{"example":"client-123","type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status (DEAD/REPLAYED)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max records to return","schema":{"default":20,"type":"number"}},{"name":"last_evaluated_key","required":false,"in":"query","description":"Pagination cursor","schema":{"type":"string"}}],"responses":{"200":{"description":"Dead letter records returned"}},"tags":["Webhook Deliveries"],"security":[{"jwt-auth":[]}]}},"/v1/webhook-deliveries/dead-letters/{id}/replay":{"post":{"operationId":"replayDeadLetter","summary":"Replay a dead letter webhook","description":"Re-enqueue a dead letter for delivery","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayWebhookDto"}}}},"responses":{"201":{"description":"Replay initiated"},"404":{"description":"Dead letter not found"}},"tags":["Webhook Deliveries"],"security":[{"jwt-auth":[]}]}},"/v1/webhook-deliveries/{id}/replay":{"post":{"operationId":"replayDelivery","summary":"Replay a webhook delivery from /events","description":"Re-enqueue a failed delivery for re-send. Rate-limited 1/30s/delivery.","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayDeliveryDto"}}}},"responses":{"201":{"description":"Replay initiated"},"422":{"description":"Delivery has no backing dead letter (not replayable)"},"429":{"description":"Rate limited; retry after retry_after_ms"}},"tags":["Webhook Deliveries"],"security":[{"jwt-auth":[]}]}},"/v1/webhook-deliveries/resend-failed":{"post":{"operationId":"resendFailed","summary":"Resend all failed webhook deliveries since a timestamp","description":"Re-enqueues every dead-lettered delivery with exhausted_at >= since (optionally scoped to one endpoint). Rate-limited 1/30s/endpoint; capped at 100 deliveries per invocation.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendFailedWebhooksDto"}}}},"responses":{"202":{"description":"Bulk resend accepted and enqueued"},"429":{"description":"Rate limited; retry after retry_after_ms"}},"tags":["Webhook Deliveries"],"security":[{"jwt-auth":[]}]}},"/v1/pay-tokens":{"post":{"operationId":"createPayToken","summary":"Create pay token","description":"Mint a pay_token for the hosted Elements add-payment-method / pay flows. Server-to-server: requires client credentials. Short-lived (15 min).","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePayTokenDto"}}}},"responses":{"201":{"description":"Pay token created successfully"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid client credentials"},"403":{"description":"Body client_id does not match the authenticated client"}},"tags":["Pay"],"security":[{"client-api-key":[]}]}},"/v1/pay-tokens/validate":{"post":{"operationId":"validatePayToken","summary":"Validate pay token","description":"Validate a pay_token and read its scope (status / bill / amount / payment method). Unauthenticated — the token itself is the credential.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidatePayTokenDto"}}}},"responses":{"200":{"description":"Token validated (check `valid` flag)"},"400":{"description":"Invalid request"}},"tags":["Pay"]}},"/v1/pay-tokens/{token}/embed-origins":{"get":{"operationId":"getPayTokenEmbedOrigins","summary":"Resolve a pay token's PCI-embed approval + registered embed origins (#4895)","description":"Lightweight resolver for the hosted /elements card pages' dynamic frame-ancestors CSP. Returns the owning client's allowed_embed_origins ONLY when elements_embed_approved is true (operator-approved, PCI). Fails closed to { elements_embed_approved: false, allowed_embed_origins: [] }.","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"PCI-embed approval + registered embed origins resolved"},"401":{"description":"Invalid or expired pay token"}},"tags":["Pay"]}},"/v1/discovery-runs/{id}":{"get":{"operationId":"getDiscoveryRun","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}}}},"/v1/discovery-runs":{"get":{"operationId":"getLatestForConnection","parameters":[{"name":"email_connection_id","required":true,"in":"query","schema":{"type":"string"}},{"name":"user_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}}}},"/v1/discovery-runs/{id}/stream":{"get":{"operationId":"streamDiscoveryRun","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}}}},"/v1/user-discovery-runs/stream":{"get":{"operationId":"streamUserDiscoveryRuns","parameters":[{"name":"user_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}}}},"/v1/retrieval/{accountLinkId}":{"get":{"operationId":"getRetrievalRun","parameters":[{"name":"accountLinkId","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}}}},"/v1/retrieval/{accountLinkId}/stream":{"get":{"operationId":"streamRetrievalRun","parameters":[{"name":"accountLinkId","required":true,"in":"path","schema":{"type":"string"}},{"name":"user_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}}}},"/v1/auth/webauthn/register-options":{"post":{"operationId":"registerOptions","summary":"Generate passkey registration options","description":"Step 1 of WebAuthn enrollment. Returns the `PublicKeyCredentialCreationOptionsJSON` the browser passes to `startRegistration()`.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebAuthnRegisterOptionsDto"}}}},"responses":{"201":{"description":""}},"tags":["🔐 Auth - WebAuthn (step-up)"]}},"/v1/auth/webauthn/register-verify":{"post":{"operationId":"registerVerify","summary":"Verify passkey registration response","description":"Step 2 of WebAuthn enrollment.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebAuthnRegisterVerifyDto"}}}},"responses":{"201":{"description":""}},"tags":["🔐 Auth - WebAuthn (step-up)"]}},"/v1/auth/webauthn/authenticate-options":{"post":{"operationId":"authenticateOptions","summary":"Generate passkey step-up assertion options","parameters":[],"responses":{"201":{"description":""}},"tags":["🔐 Auth - WebAuthn (step-up)"]}},"/v1/auth/webauthn/authenticate-verify":{"post":{"operationId":"authenticateVerify","summary":"Verify passkey step-up assertion + mint step-up token","description":"Step 2 of WebAuthn step-up. On success, sets `bb_stepup_token` HttpOnly cookie scoped to `/v1/portal/`.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebAuthnAuthenticateVerifyDto"}}}},"responses":{"201":{"description":""}},"tags":["🔐 Auth - WebAuthn (step-up)"]}},"/v1/auth/webauthn/credentials":{"get":{"operationId":"listCredentials","summary":"List registered passkeys for the current user","parameters":[],"responses":{"200":{"description":""}},"tags":["🔐 Auth - WebAuthn (step-up)"]}},"/v1/auth/webauthn/credentials/{credentialId}":{"delete":{"operationId":"revokeCredential","summary":"Revoke a single passkey","parameters":[{"name":"credentialId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["🔐 Auth - WebAuthn (step-up)"]}},"/v1/auth/step-up/verify-password":{"post":{"operationId":"verifyPassword","summary":"Re-verify the operator password and mint a step-up token (fallback path)","description":"For users who haven't enrolled a passkey, or whose browser doesn't support WebAuthn. The password is re-checked against Cognito; the existing session continues — no new tokens issued.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpVerifyPasswordDto"}}}},"responses":{"201":{"description":""}},"tags":["🔐 Auth - Step-up"]}},"/v1/docs-feedback":{"post":{"operationId":"submitDocsFeedback","summary":"Record docs \"Was this helpful?\" feedback (public, unauthenticated)","description":"Public ingest for the docs feedback widget. No auth, no PII. Records a thumbs-up/down (and optional bounded comment) against a docs path. Rate-limited per IP. Always returns 202 on a valid body; malformed bodies return the coded 400 error envelope.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitDocsFeedbackDto"}}}},"responses":{"202":{"description":"Feedback accepted"},"400":{"description":"Malformed body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}}}},"tags":["Docs Feedback"]}},"/v1/biller-connect/ticket":{"post":{"operationId":"mintTicket","summary":"Mint a single-use biller-connect WSS capability ticket (server-to-server)","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintTicketDto"}}}},"responses":{"201":{"description":"Ticket minted"}},"tags":["Biller Connect"],"security":[{"client-api-key":[]}]}},"/v1/biller_messages":{"get":{"operationId":"list","summary":"List canonical biller messages for a client user","parameters":[{"name":"client_user_id","required":true,"in":"query","description":"Your stable user identifier.","schema":{"type":"string"}},{"name":"account_link_id","required":false,"in":"query","description":"Limit results to one connected account.","schema":{"type":"string"}},{"name":"unread_only","required":false,"in":"query","description":"Return only unread messages.","schema":{"enum":["true","false"],"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":50,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque pagination cursor.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillerMessagesPageDto"}}}}},"tags":["Biller Messages"],"security":[{"client-api-key":[]}]}},"/v1/biller_messages/{message_id}":{"get":{"operationId":"retrieve","summary":"Retrieve a canonical biller message","parameters":[{"name":"message_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"client_user_id","required":true,"in":"query","description":"Your stable user identifier.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillerMessageResourceDto"}}}}},"tags":["Biller Messages"],"security":[{"client-api-key":[]}]}},"/v1/biller_messages/{message_id}/read":{"post":{"operationId":"markRead","summary":"Persist canonical read state","parameters":[{"name":"message_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"client_user_id","required":true,"in":"query","description":"Your stable user identifier.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillerMessageReadResponseDto"}}}}},"tags":["Biller Messages"],"security":[{"client-api-key":[]}]}},"/v1/biller_messages/{message_id}/report":{"post":{"operationId":"report","summary":"Report a message and apply scoped suppression","parameters":[{"name":"message_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"client_user_id","required":true,"in":"query","description":"Your stable user identifier.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportBillerMessageDto"}}}},"responses":{"202":{"description":"Report recorded for the message biller and category.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillerMessageReportResponseDto"}}}}},"tags":["Biller Messages"],"security":[{"client-api-key":[]}]}},"/v1/iam/clients/{clientId}/elements-embed-approval":{"get":{"operationId":"get","summary":"Get the current PCI Elements embed approval status","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Current client-safe approval status and workflow write capability","content":{"application/json":{"schema":{"example":{"success":true,"workflow_enabled":false,"approval":{"client_id":"client-id","status":"NOT_REQUESTED","origin_snapshot":[]}}}}}}},"tags":["Elements embed approval"],"security":[{"jwt-auth":[]}]}},"/v1/iam/clients/{clientId}/elements-embed-approval/requests":{"post":{"operationId":"request","summary":"Request review of the currently registered HTTPS origins","parameters":[{"name":"clientId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestElementsEmbedApprovalDto"}}}},"responses":{"201":{"description":""}},"tags":["Elements embed approval"],"security":[{"jwt-auth":[]}]}},"/v1/identity":{"get":{"operationId":"getIdentity","summary":"Describe the authenticated API-key identity","parameters":[],"responses":{"200":{"description":""}},"tags":["Identity"],"security":[{"client-api-key":[]}]}}},"info":{"title":"BillerAPI Client API","description":"REST API for external developers integrating with BillerAPI. All protected server-side endpoints require a BillerAPI API key sent as Authorization: Bearer bak_test_... for sandbox or Authorization: Bearer bak_live_... for production.","version":"1.0","contact":{}},"tags":[{"name":"Authentication","description":"User authentication and session management"},{"name":"Bills","description":"Bill retrieval and synchronization"},{"name":"Billers","description":"Biller discovery and account linking"},{"name":"Email Discovery","description":"Email-based bill discovery"},{"name":"Account Linking","description":"Account linking and credentials"},{"name":"Metering","description":"Usage metrics and billing information"},{"name":"Webhooks","description":"Webhook configuration and event delivery"},{"name":"Health","description":"Health checks and system status"}],"servers":[{"url":"https://sandbox.api.billerapi.com","description":"Sandbox"},{"url":"https://api.billerapi.com","description":"Production"}],"components":{"securitySchemes":{"client-api-key":{"scheme":"bearer","bearerFormat":"BillerAPI API key","type":"http","description":"BillerAPI API key. Use bak_test_... for sandbox and bak_live_... for production."},"jwt-auth":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"JWT token for authenticated users"}},"schemas":{"IngestUnifiedPortalEventDto":{"type":"object","properties":{"message_id":{"type":"string","description":"SQS message id, also used as the fallback correlation id."},"raw_body":{"type":"string","description":"Verbatim SQS message body. Un-capped by design."}},"required":["message_id","raw_body"]},"SignInDto":{"type":"object","properties":{"email":{"type":"string","description":"Worker email address","example":"worker@example.com"},"password":{"type":"string","description":"Worker password","example":"SecurePass123!"}},"required":["email","password"]},"SignUpDto":{"type":"object","properties":{"email":{"type":"string","description":"Worker email address","example":"worker@example.com"},"password":{"type":"string","description":"Worker password","example":"SecurePass123!"},"given_name":{"type":"string","description":"Worker first name","example":"John"},"family_name":{"type":"string","description":"Worker last name","example":"Doe"},"client_name":{"type":"string","description":"Client application name","example":"Example integration"},"legal_acceptances":{"type":"array","minItems":1,"maxItems":3,"description":"Authoritative acceptance receipts copied exactly from GET /v1/iam/auth/legal-documents after explicit user consent.","items":{"type":"object","properties":{"document_kind":{"type":"string","enum":["terms","privacy","dpa"]},"document_version":{"type":"string"},"document_effective_date":{"type":"string","format":"date"},"accepted":{"type":"boolean","enum":[true]}},"required":["document_kind","document_version","document_effective_date","accepted"]}},"terms_accepted":{"type":"boolean","enum":[true],"example":true,"description":"Required legacy compatibility projection; must not contradict legal_acceptances."},"terms_version":{"type":"string","example":"<matching terms document_version from registry>","description":"Legacy compatibility projection of the accepted terms receipt version."},"privacy_version":{"type":"string","example":"<matching privacy document_version from registry>","description":"Legacy compatibility projection of the accepted privacy receipt version."},"accepted_at":{"type":"string","format":"date-time","example":"2026-08-24T12:34:56.000Z","description":"Timestamp when the caller recorded the explicit acceptance."},"acceptance_source":{"type":"string","enum":["portal_signup","billerapi_cli"],"example":"portal_signup","description":"Caller-asserted signup channel; not authenticated caller identity"}},"required":["email","password","given_name","family_name","client_name","legal_acceptances","terms_accepted","terms_version","privacy_version","accepted_at","acceptance_source"]},"SignOutDto":{"type":"object","properties":{"refresh_token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","description":"Refresh token to invalidate"}},"required":["refresh_token"]},"ConfirmSignUpDto":{"type":"object","properties":{"email":{"type":"string","description":"Worker email address","example":"worker@example.com"},"confirmation_code":{"type":"string","description":"Verification code from email","example":"123456"}},"required":["email","confirmation_code"]},"ConfirmSignUpAndSignInDto":{"type":"object","properties":{"email":{"type":"string","example":"developer@example.com","description":"User email address"},"confirmation_code":{"type":"string","example":"123456","description":"Confirmation code sent to email"},"password":{"type":"string","example":"SecurePassword123!","description":"User password (min 12 characters)"}},"required":["email","confirmation_code","password"]},"ForgotPasswordDto":{"type":"object","properties":{"email":{"type":"string","description":"Worker email address","example":"worker@example.com"}},"required":["email"]},"ResetPasswordDto":{"type":"object","properties":{"email":{"type":"string","description":"Worker email address","example":"worker@example.com"},"confirmation_code":{"type":"string","description":"Reset code sent to email","example":"123456"},"new_password":{"type":"string","description":"New password (min 12 characters)","example":"NewSecurePass123!"}},"required":["email","confirmation_code","new_password"]},"RefreshTokenDto":{"type":"object","properties":{"refresh_token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","description":"Refresh token obtained from signin (optional — falls back to bb_refresh_token httpOnly cookie)"},"username":{"type":"string","description":"Cognito username (typically the email). Server derives it from id_token cookie when omitted. #2384"}}},"CreateClientDto":{"type":"object","properties":{"name":{"type":"string","example":"My Application","description":"Client application name"},"description":{"type":"string","example":"Production API client for MyApp","description":"Client description"},"redirect_uris":{"example":["https://myapp.com/callback"],"description":"Allowed redirect URIs for OAuth","type":"array","items":{"type":"string"}}},"required":["name"]},"LinkCustomizationDto":{"type":"object","properties":{"primary_color":{"type":"string","example":"#4F46E5","description":"Accent color as a strict 6-digit hex (#RRGGBB). Injected as a CSS custom property."},"mode":{"type":"string","example":"system","description":"Connect modal color mode.","enum":["light","dark","system"]},"border_radius":{"type":"string","example":"md","description":"Connect modal corner-radius preset.","enum":["sm","md","lg"]},"client_logo_url":{"type":"string","example":"https://cdn.customer.com/logo.png","description":"Self-hosted https logo URL rendered as <img src> in the consent handshake mark. https only — http, javascript:, data:, blob:, and non-URLs are rejected."},"pinned_biller_ids":{"example":["biller_9f2a1c34-5b6d-4e7f-8a9b-0c1d2e3f4a5b"],"description":"Biller ids surfaced first in the modal popular list. Optimistic (no live existence check; unknown ids are skipped at render time). Max 24 string entries. Accepts either the prefixed (`biller_<uuid>`) or bare-uuid form; always returned prefixed.","type":"array","items":{"type":"string"}}}},"UpdateClientDto":{"type":"object","properties":{"name":{"type":"string","example":"My Updated Application","description":"Client application name"},"description":{"type":"string","example":"Updated description","description":"Client description"},"environment":{"type":"string","example":"sandbox","description":"Client environment","enum":["sandbox","development","production"]},"status":{"type":"string","example":"active","description":"Client status"},"allowed_embed_origins":{"example":["https://app.customer.com"],"description":"Exact origins allowed to embed the hosted connect/elements iframes for this client (#4770). https only (http allowed for localhost), no paths or wildcards. Omit for no change; an empty array clears the registry (first-party-only embedding). Deep validation (scheme/path/wildcard rules) is enforced by the client-iam domain.","type":"array","items":{"type":"string"}},"redirect_uris":{"example":["https://app.customer.com/callback"],"description":"Registered OAuth redirect_uris (#4768). The hosted connect page top-navigates to redirect_uri on completion, so a hosted link token's redirect_uri must exactly match one of these at mint. Full callback URLs (paths + query allowed); https only (http allowed for localhost); no wildcards or fragments. Omit for no change; an empty array clears the allowlist.","type":"array","items":{"type":"string"}},"link_customization":{"description":"Dashboard-driven Connect (Link) customization (#4768 Phase 6.2): theme (color/mode/radius/logo) + pinned billers. Injected into the hosted Connect modal at link-token bootstrap. Omit for no change; an empty object clears customization back to default. Each field is re-validated in the client-iam domain (defense-in-depth).","allOf":[{"$ref":"#/components/schemas/LinkCustomizationDto"}]}}},"GenerateClientSecretDto":{"type":"object","properties":{"environment":{"type":"string","example":"sandbox","description":"Environment for the client secret","enum":["sandbox","development","production"]}},"required":["environment"]},"RegisterWebhookDto":{"type":"object","properties":{"environment":{"type":"string","example":"sandbox","description":"Environment for the webhook","enum":["sandbox","development","production"]},"url":{"type":"string","example":"https://myapp.com/webhooks/billbutler","description":"Webhook callback URL"},"events":{"example":["bill.created","bill.updated","link.completed"],"description":"Event types this subscription delivers. Must be deliverable event types — one of: bill.created, bill.deleted, bill.updated, bill_import.updated, biller.unsupported, connection.ready, customer.message.complaint, customer.message.created, insight.created, insight.updated, link.completed, link.disconnected, link.failure_reason_corrected, link.session_finished, link_request.cancelled, link_request.created, link_request.updated, link_token.completed, pay.escalated, pay.failed, pay.scheduled, pay.succeeded, payment.observed. Legacy collapse/rename sources (e.g. `bill.paid`, `link.expired`, `request-to-link.updated`, and the historic PascalCase forms like `BillCreated`) are ACCEPTED and normalized to the name they are actually delivered under — the stored + echoed value is the normalized one, so the response shows exactly what was saved. Any other string is rejected with a 400 (`error_code: VALIDATION_ERROR`, `errors[].code: unknown_event_type`) rather than silently stored as a subscription that can never fire. `*` and `all` subscribe to everything.","type":"array","items":{"type":"string"}},"description":{"type":"string","example":"BillEBox partner-app webhook","description":"Human-readable description of the webhook"},"secret":{"type":"string","example":"whsec_secret123","description":"Webhook secret for signature verification"}},"required":["environment","url","events"]},"UpdateWebhookDto":{"type":"object","properties":{"webhook_url":{"type":"string","example":"https://myapp.com/webhooks/billerapi/v2","description":"Updated webhook callback URL"},"webhook_events":{"example":["bill.created","bill.updated","bill.deleted"],"description":"Event types this subscription delivers. Must be deliverable event types — one of: bill.created, bill.deleted, bill.updated, bill_import.updated, biller.unsupported, connection.ready, customer.message.complaint, customer.message.created, insight.created, insight.updated, link.completed, link.disconnected, link.failure_reason_corrected, link.session_finished, link_request.cancelled, link_request.created, link_request.updated, link_token.completed, pay.escalated, pay.failed, pay.scheduled, pay.succeeded, payment.observed. Legacy collapse/rename sources (e.g. `bill.paid`, `link.expired`, `request-to-link.updated`, and the historic PascalCase forms like `BillCreated`) are ACCEPTED and normalized to the name they are actually delivered under — the stored + echoed value is the normalized one, so the response shows exactly what was saved. Any other string is rejected with a 400 (`error_code: VALIDATION_ERROR`, `errors[].code: unknown_event_type`) rather than silently stored as a subscription that can never fire. `*` and `all` subscribe to everything.","type":"array","items":{"type":"string"}},"description":{"type":"string","example":"BillEBox partner-app webhook","description":"Updated description"}},"required":["webhook_url","webhook_events"]},"VerifyEmailCodeDto":{"type":"object","properties":{"code":{"type":"string","example":"123456","description":"Verification code emailed to the user."}},"required":["code"]},"ChangePasswordDto":{"type":"object","properties":{"current_password":{"type":"string","description":"The user's current password."},"new_password":{"type":"string","description":"The replacement password."}}},"SubmitVerificationRequestDto":{"type":"object","properties":{"company_legal_name":{"type":"string","example":"Acme Inc","description":"Legal business name"},"company_type":{"type":"string","example":"LLC","description":"Company type (e.g. LLC, Corporation)"},"website":{"type":"string","example":"https://acme.com","description":"Company website"},"use_case":{"type":"string","example":"Bill pay integration","description":"Primary use case"},"expected_volume":{"type":"string","example":"1000","description":"Expected monthly volume"}}},"TestWebhookDto":{"type":"object","properties":{"event_type":{"type":"string","example":"link.completed","description":"Subscribed event type to deliver as a synthetic test payload"}},"required":["event_type"]},"UpdateProfileDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Worker ID","example":"worker_abc123"},"given_name":{"type":"string","description":"Updated first name","example":"Jane"},"family_name":{"type":"string","description":"Updated last name","example":"Smith"},"phone_number":{"type":"string","description":"Updated phone number in E.164 format","example":"+15555555556"}},"required":["worker_id"]},"ValidateClientSecretDto":{"type":"object","properties":{"client_id":{"type":"string","description":"Client whose secret is being validated."},"client_secret":{"type":"string","description":"The candidate secret."}},"required":["client_id","client_secret"]},"InternalUpdateClientDto":{"type":"object","properties":{"elements_embed_approved":{"type":"boolean","example":true,"description":"PCI-embed approval (#4895). When true, the hosted /elements card pages may be framed by this client's registered allowed_embed_origins (dynamic frame-ancestors). Default false (fail-closed; /elements stays first-party-only). Operator-only; requires CSO sign-off."}}},"GetBillsQueryDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"link-456","description":"Account link ID"},"start_date":{"type":"string","example":"2025-01-01","description":"Start date (ISO format)"},"end_date":{"type":"string","example":"2025-12-31","description":"End date (ISO format)"},"limit":{"type":"number","example":100,"description":"Maximum number of bills to return (1-500)"},"cursor":{"type":"string","example":"cursor_abc123","description":"Pagination cursor"}},"required":["account_link_id"]},"SyncBillsQueryDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"link-456","description":"Account link ID to sync"},"since":{"type":"string","example":"2025-01-01T00:00:00Z","description":"Sync bills since this date"},"limit":{"type":"number","example":100,"description":"Maximum number of bills to sync"},"include_deleted":{"type":"boolean","example":false,"description":"Include deleted bills"}},"required":["account_link_id"]},"TriggerBillSyncDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"link-456","description":"Account link ID to trigger sync for"},"force":{"type":"boolean","example":false,"description":"Force full sync even if recent sync exists"}},"required":["account_link_id"]},"StatementPeriodDto":{"type":"object","properties":{"start":{"type":"string","example":"2026-03-01","description":"First day of the statement window (YYYY-MM-DD)."},"end":{"type":"string","example":"2026-03-31","description":"Last day of the statement window (YYYY-MM-DD)."},"statement_date":{"type":"string","example":"2026-04-01","description":"When the statement was issued (YYYY-MM-DD). Always >= end."}},"required":["start","end","statement_date"]},"BalanceBreakdownDto":{"type":"object","properties":{"previous_balance":{"type":"number","example":1240.5},"payments_credits":{"type":"number","example":-1240.5,"description":"Negative for credits."},"new_charges":{"type":"number","example":873.42},"fees":{"type":"number","example":0},"interest":{"type":"number","example":0},"taxes":{"type":"number","example":0},"current_balance":{"type":"number","example":873.42,"description":"New balance / total currently due."},"minimum_payment_due":{"type":"number","example":35},"due_date":{"type":"string","example":"2026-04-28","description":"Payment due date (YYYY-MM-DD)."},"currency":{"type":"string","example":"USD","description":"#4040 PR4 — ISO-4217 currency for the whole statement. Every line item inherits this currency."},"reconciled":{"type":"boolean","example":true,"description":"#4040 PR3 — COMPUTED reconciliation flag (never the model self-report). true when the balance identity (previous_balance − |payments_credits| + new_charges + fees + interest + taxes ≈ current_balance) held within $0.01; false when it broke (the statement is downgraded to data_quality=PARTIAL + needs_review). Absent when there were not enough signed fields to compute it."}},"required":["current_balance","minimum_payment_due","due_date","currency"]},"BillerMetadataDto":{"type":"object","properties":{"masked_account_number":{"type":"string","example":"****4421"},"autopay_enabled":{"type":"boolean","example":true},"paperless":{"type":"boolean","example":true},"plan_name":{"type":"string","example":"Cash Rewards Visa"}},"required":["masked_account_number"]},"ServicePeriodDto":{"type":"object","properties":{"start":{"type":"string","example":"2026-04-01"},"end":{"type":"string","example":"2026-04-30"}},"required":["start","end"]},"LineItemUsageDto":{"type":"object","properties":{"quantity":{"type":"number","example":642,"description":"Quantity consumed (e.g. kWh, GB, minutes)."},"unit":{"type":"string","example":"kWh"},"rate":{"type":"number","example":0.1528,"description":"Per-unit rate."},"tier":{"type":"string","example":"tier-2"},"service_period":{"$ref":"#/components/schemas/ServicePeriodDto"}},"required":["quantity","unit"]},"LineItemDto":{"type":"object","properties":{"description":{"type":"string","example":"AMAZON MARKETPLACE","description":"Cleaned (trimmed, whitespace-collapsed)."},"description_raw":{"type":"string","example":"AMAZON  MARKETPLACE  ","description":"#4040 PR4 — verbatim source text."},"posted_date":{"type":"string","example":"2026-03-08"},"amount":{"type":"number","example":24.99,"description":"#4040 PR4 — ABSOLUTE value, always >= 0. The signed value is derived from `kind` (CREDIT/PAYMENT/ADJUSTMENT read negative)."},"kind":{"type":"string","enum":["CHARGE","USAGE_CHARGE","FEE","REGULATORY_FEE","TAX","INTEREST","ADJUSTMENT","CREDIT","PAYMENT","LATE_FEE","INSTALLMENT","DEPOSIT"],"example":"CHARGE","description":"#4040 PR4 — closed line-item kind vocabulary; the sole source of sign. CREDIT/PAYMENT/ADJUSTMENT make the signed amount negative."},"currency":{"type":"string","example":"USD","description":"#4040 PR4 — ISO-4217, inherited from the statement."},"category":{"type":"string","enum":["USAGE","SERVICE","EQUIPMENT","PLAN","PAYMENT","CREDIT","REFUND","PRINCIPAL","INTEREST","ESCROW","FEE","TAX","REGULATORY","LATE_FEE","GROCERIES","DINING","FUEL","TRAVEL","SHOPPING","SUBSCRIPTION","INSURANCE","OTHER"],"example":"SHOPPING","description":"#4040 PR4 — closed line-item category vocabulary (nullable)."},"reference_id":{"type":"string","example":"TRX-99183"},"quantity":{"type":"number","example":1},"usage":{"description":"#4040 PR4 — metered usage (utilities/telecom).","allOf":[{"$ref":"#/components/schemas/LineItemUsageDto"}]},"confidence":{"type":"number","example":0.95,"description":"Per-line confidence in [0, 1]."}},"required":["description","description_raw","posted_date","amount","kind","currency","confidence"]},"StatementCompletenessDto":{"type":"object","properties":{"fields_present":{"example":["statement_period","balance_breakdown","line_items"],"description":"Top-level field paths populated in this statement.","type":"array","items":{"type":"string"}},"fields_missing":{"example":[],"description":"Top-level field paths the agent could not populate.","type":"array","items":{"type":"string"}},"reasons":{"type":"object","example":{},"description":"Per-missing-field reason codes (e.g. \"biller_does_not_disclose\").","additionalProperties":{"type":"string"}},"refreshable":{"type":"boolean","example":false,"description":"Whether a future POST /refresh might fill the gaps. False if the biller permanently does not disclose this data."},"data_quality":{"type":"string","enum":["VERIFIED","INFERRED","PARTIAL"],"example":"VERIFIED","description":"VERIFIED = all required fields exact-match. INFERRED = some derived from indirect signals. PARTIAL = at least one required field missing."},"extraction_method":{"type":"string","enum":["CREDENTIALED","EMAIL","BANK_FEED","USER_UPLOAD"],"example":"CREDENTIALED","description":"How BillerAPI obtained the underlying document. User-comprehensible category — does NOT leak internal pipeline mechanics (scrape vs IMAP vs OFX)."},"needs_review":{"type":"boolean","example":false,"description":"true when this statement was persisted below the extraction confidence threshold (or otherwise flagged) and should be re-checked. Always paired with data_quality=PARTIAL. Recipients may call POST /refresh to attempt a higher-confidence re-extraction."},"needs_review_reason":{"type":"string","example":"overall_confidence below threshold","description":"Short machine-readable reason for needs_review, when set."},"truncated":{"type":"boolean","example":false,"description":"#4040 PR4 — true when the source emitted more than 500 line items and the tail was dropped (the first 500 are kept). Computed at ingest, never the model self-report."}},"required":["fields_present","fields_missing","reasons","refreshable","data_quality","extraction_method"]},"StatementDto":{"type":"object","properties":{"bill_id":{"type":"string","example":"bill_01HXY1234567890ABCDEFGHJK"},"client_id":{"type":"string","example":"client_01HXY..."},"version":{"type":"number","example":3,"description":"Optimistic concurrency version. Increments on every refresh."},"extracted_at":{"type":"string","example":"2026-04-25T14:32:00.000Z","description":"When BillerAPI extracted this snapshot from the source document. Use this, not fetched_at — fetched_at was renamed pre-launch."},"stale":{"type":"boolean","example":false,"description":"true when the statement is older than its TTL or upstream marked it stale; recipients should call POST /refresh."},"statement_period":{"$ref":"#/components/schemas/StatementPeriodDto"},"balance_breakdown":{"$ref":"#/components/schemas/BalanceBreakdownDto"},"biller_metadata":{"$ref":"#/components/schemas/BillerMetadataDto"},"line_items":{"description":"Capped at 500 per statement for v1.","type":"array","items":{"$ref":"#/components/schemas/LineItemDto"}},"completeness":{"$ref":"#/components/schemas/StatementCompletenessDto"},"overall_confidence":{"type":"number","example":0.97,"description":"Aggregate confidence in [0, 1]."}},"required":["bill_id","client_id","version","extracted_at","stale","statement_period","balance_breakdown","biller_metadata","line_items","completeness","overall_confidence"]},"RefreshStatementBodyDto":{"type":"object","properties":{"source_hint":{"type":"string","enum":["CREDENTIALED","EMAIL","BANK_FEED","USER_UPLOAD"],"description":"Optional hint about which pipeline to prefer for the refresh. Best-effort."}}},"RefreshStatementResponseDto":{"type":"object","properties":{"request_id":{"type":"string","example":"d94f5e2a-8c3b-4f1e-9a7d-6b2c1e0f8a34"},"status":{"type":"string","example":"pending","enum":["pending","complete","failed"]},"started_at":{"type":"string","example":"2026-04-25T14:32:00.000Z"}},"required":["request_id","status","started_at"]},"ApiErrorDto":{"type":"object","properties":{"error_code":{"type":"string","enum":["BILL_NOT_FOUND","INVALID_CURSOR","ACCOUNT_LINK_NOT_FOUND","STATEMENT_NOT_EXTRACTED","EXTRACTION_FAILED","EXTRACTION_UNSUPPORTED_FOR_BILLER","STATEMENT_TOO_LARGE","RATE_LIMITED","UNAUTHORIZED","SERVICE_UNAVAILABLE","IDEMPOTENCY_KEY_MISMATCH","IDEMPOTENCY_KEY_NOT_REPLAYABLE","PAYMENT_EXECUTION_NOT_AVAILABLE","FEEDBACK_RUN_NOT_FOUND","FEEDBACK_RUN_NOT_OWNED","FEEDBACK_RUN_EXPIRED","FEEDBACK_INVALID_CATEGORY","FEEDBACK_INVALID_SIGNAL","FEEDBACK_ALREADY_SUBMITTED","FEEDBACK_RATE_LIMITED","MESSAGING_CONSENT_NOT_GRANTED","MESSAGING_LIVE_ACCESS_REQUIRED","MESSAGING_SENDER_NOT_AUTHORIZED","MESSAGING_CONTENT_FLAGGED","MESSAGING_RATE_LIMITED","MESSAGING_SUPPRESSED","MESSAGING_AUP_NOT_ACCEPTED","MESSAGING_AUP_REACCEPT_REQUIRED","MESSAGING_INVALID_PAYLOAD","MESSAGING_INVALID_CATEGORY","MESSAGING_PERSIST_FAILED","MESSAGING_INTERNAL_ERROR","MESSAGING_NOT_FOUND","LINK_TOKEN_NOT_FOUND","BACKGROUND_NOT_ELIGIBLE","BILLER_UNSUPPORTED","UPDATE_BILLER_MISMATCH","INVALID_UPDATE_REASON","LINK_UPDATE_FORBIDDEN","LINK_NOT_FOUND","BILLER_NOT_FOUND","REDIRECT_URI_NOT_REGISTERED"],"example":"STATEMENT_NOT_EXTRACTED","description":"Stable identifier — third parties branch on this. Additive-only contract."},"error_type":{"type":"string","enum":["invalid_request","rate_limit","auth","upstream","api_error"],"example":"invalid_request","description":"Coarse category clients branch on for retry/backoff."},"error_message":{"type":"string","example":"Statement has not yet been extracted for bill bill_abc123. Call POST /v1/bills/:bill_id/statement/refresh to trigger extraction.","description":"Human-readable explanation. Safe to show end users in dev contexts."},"hint":{"type":"string","example":"Call POST /v1/bills/:bill_id/statement/refresh, then retry after the statement is extracted.","description":"Actionable next step for resolving this error."},"request_id":{"type":"string","example":"d94f5e2a-8c3b-4f1e-9a7d-6b2c1e0f8a34","description":"Correlation id (UUID) for support tickets. Also returned as the X-Request-Id response header on every response."},"docs_url":{"type":"string","example":"https://docs.billerapi.com/errors/STATEMENT_NOT_EXTRACTED","description":"Canonical, LIVE docs page for this error code."},"retryable":{"type":"boolean","example":false,"description":"Whether retrying the same operation is supported."},"documentation_url":{"type":"string","example":"https://docs.billerapi.com/errors/STATEMENT_NOT_EXTRACTED","deprecated":true,"description":"DEPRECATED alias for docs_url, retained for back-compat during the DX P0 migration window. Read docs_url instead — this field will be removed."},"retry_after":{"type":"number","example":30,"description":"On 429, the seconds the client should wait before retrying."},"errors":{"type":"array","description":"On 400 validation failures, the per-field problems.","example":[{"param":"given_name","code":"required","message":"given_name should not be empty"}]}},"required":["error_code","error_type","error_message","hint","request_id","docs_url"]},"Iso20022AmountResponseDto":{"type":"object","properties":{"value":{"type":"string","example":"123.45"},"currency":{"type":"string","example":"USD"}},"required":["value","currency"]},"PublicBillResponseDto":{"type":"object","properties":{"total_amount":{"$ref":"#/components/schemas/Iso20022AmountResponseDto"},"due_date_iso":{"type":"string","example":"2026-09-30","nullable":true},"amount":{"type":"number","deprecated":true,"description":"Legacy major-unit amount. Use total_amount.value."},"currency":{"type":"string","deprecated":true,"description":"Legacy currency. Use total_amount.currency."},"due_date":{"type":"string","deprecated":true,"nullable":true,"description":"Legacy due date. Use due_date_iso."},"id":{"type":"string","example":"bill_abc123"}},"required":["amount","currency","id"]},"CreateSandboxAccountLinkDto":{"type":"object","additionalProperties":false,"properties":{"biller_id":{"type":"string","minLength":1,"example":"sb_utility","description":"Sandbox test biller identifier. Production biller identifiers are rejected."},"scenario":{"type":"string","default":"success","enum":["success","auth_failure","biller_unavailable","mfa_required","account_locked","past_due","auto_pay","payment_plan","multiple_accounts","network_error","slow_background","security_question","will_retry"],"description":"Deterministic sandbox scenario. The resource-backed values success, past_due, auto_pay, payment_plan, and multiple_accounts create direct links. Authentication, challenge, and transient-failure scenarios are recognized but return 422 FIXTURE_UNAVAILABLE because they must be tested through Connect."},"client_user_id":{"type":"string","maxLength":255,"example":"user_123","description":"Optional caller-owned end-user reference stored on the test link."}},"required":["biller_id"]},"SandboxAccountLinkResponseDto":{"type":"object","properties":{"account_link_id":{"type":"string","pattern":"^sandbox_link_[a-f0-9]{24}$","example":"sandbox_link_0123456789abcdef01234567"},"biller_id":{"type":"string","example":"sb_utility"},"status":{"type":"string","enum":["active"]},"scenario":{"type":"string","enum":["success","past_due","auto_pay","payment_plan","multiple_accounts"]},"created_at":{"type":"string","format":"date-time","description":"When this sandbox account link was created."},"expires_at":{"type":"string","format":"date-time","description":"When this ephemeral sandbox account link expires."},"events_generated":{"type":"array","description":"Event types produced once for the sandbox delivery pipeline. This is not a delivery receipt; subscription matching and delivery are separate.","items":{"type":"string","enum":["bill.created","connection.ready"]},"example":["bill.created","connection.ready"]}},"required":["account_link_id","biller_id","status","scenario","created_at","expires_at","events_generated"]},"RevokeSandboxAccountLinkResponseDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"sandbox_link_0123456789abcdef01234567"},"status":{"type":"string","enum":["revoked"]}},"required":["account_link_id","status"]},"SandboxErrorResponseDto":{"type":"object","properties":{"error_code":{"type":"string","enum":["UNAUTHORIZED","WRONG_ENVIRONMENT","INVALID_INPUT","IDEMPOTENCY_CONFLICT","CAPACITY_EXCEEDED","FIXTURE_UNAVAILABLE","NOT_FOUND","INTERNAL_ERROR"],"description":"Stable sandbox error code."},"error_message":{"type":"string","description":"Human-readable explanation of this request failure."},"hint":{"type":"string","description":"Actionable next step."},"docs_url":{"type":"string","format":"uri","description":"Documentation for this error category."},"request_id":{"type":"string","description":"Correlation identifier to include in support requests."},"errors":{"type":"array","description":"Per-field validation details, present only for validation failures.","items":{"type":"object","additionalProperties":true}}},"required":["error_code","error_message","hint","docs_url","request_id"]},"BillListResponseDto":{"type":"object","properties":{"bills":{"type":"array","items":{"$ref":"#/components/schemas/PublicBillResponseDto"}},"total_count":{"type":"integer","minimum":0,"description":"Number of bills in this response page. This is page-bound, not the collection-wide total."},"has_more":{"type":"boolean","description":"Whether another page is available."},"next_cursor":{"type":"string","description":"Opaque cursor for the next page, or an empty string on the final page."}},"required":["bills","total_count","has_more","next_cursor"]},"BackfillBillPaymentMatchesDto":{"type":"object","properties":{"account_link_id":{"type":"string","description":"Account link to replay ObservedPayments + Statements for."},"account_id":{"type":"string","description":"Narrow the replay to a single account on the link."}},"required":["account_link_id"]},"FireTestWebhookEventDto":{"type":"object","properties":{"event_type":{"type":"string","description":"bill.paid | bill.partially_paid | bill.status_reverted (dot.lowercase)."},"bill_id":{"type":"string","description":"Bill the synthetic event refers to."},"link_id":{"type":"string","description":"Link the synthetic event refers to."},"biller_id":{"type":"string","description":"Biller stamped onto the synthetic envelope."},"account_id":{"type":"string","description":"Account stamped onto the synthetic envelope."},"revert_reason":{"type":"string","description":"NEXT_STATEMENT_SHOWS_BALANCE | MANUAL_ADMIN | OBSERVED_PAYMENT_REVERSED (bill.status_reverted only)."},"previous_status":{"type":"string","description":"Prior bill status stamped onto the synthetic envelope."}},"required":["event_type","bill_id","link_id"]},"BillDetailDataResponseDto":{"type":"object","properties":{"total_amount":{"$ref":"#/components/schemas/Iso20022AmountResponseDto"},"due_date_iso":{"type":"string","example":"2026-09-30","nullable":true},"amount":{"type":"number","deprecated":true,"description":"Legacy major-unit amount. Use total_amount.value."},"currency":{"type":"string","deprecated":true,"description":"Legacy currency. Use total_amount.currency."},"due_date":{"type":"string","deprecated":true,"nullable":true,"description":"Legacy due date. Use due_date_iso."},"bill_id":{"type":"string","example":"bill_abc123"}},"required":["amount","currency","bill_id"]},"BillDetailResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BillDetailDataResponseDto"}},"required":["success","data"]},"CreateBillImportDto":{"type":"object","properties":{}},"CompleteBillImportUploadDto":{"type":"object","properties":{}},"BillImportStringOperationDto":{"type":"object","properties":{}},"BillImportAmountOperationDto":{"type":"object","properties":{"operation":{"type":"string","enum":["set","clear"]},"value":{"type":"number","example":123.45}},"required":["operation"]},"IsoMoneyInputDto":{"type":"object","properties":{"value":{"type":"string","example":"123.45","description":"Decimal string using the currency minor-unit exponent."},"currency":{"type":"string","example":"USD","description":"ISO 4217 currency code."}},"required":["value","currency"]},"BillImportIsoMoneyOperationDto":{"type":"object","properties":{"operation":{"type":"string","enum":["set","clear"]},"value":{"$ref":"#/components/schemas/IsoMoneyInputDto"}},"required":["operation"]},"BillImportDateOperationDto":{"type":"object","properties":{"operation":{"type":"string","enum":["set","clear"]},"value":{"type":"string","example":"2026-07-22"}},"required":["operation"]},"BillImportCurrencyOperationDto":{"type":"object","properties":{"operation":{"type":"string","enum":["set","clear"]},"value":{"type":"string","example":"USD"}},"required":["operation"]},"BillImportServicePeriodOperationDto":{"type":"object","properties":{}},"BillImportRemitToAddressOperationDto":{"type":"object","properties":{}},"BillImportUrlOperationDto":{"type":"object","properties":{}},"BillImportLineItemsOperationDto":{"type":"object","properties":{}},"BillImportClassificationOperationDto":{"type":"object","properties":{}},"BillImportReviewChangesDto":{"type":"object","properties":{"payee_name":{"$ref":"#/components/schemas/BillImportStringOperationDto"},"amount_due":{"deprecated":true,"allOf":[{"$ref":"#/components/schemas/BillImportAmountOperationDto"}]},"total_amount":{"$ref":"#/components/schemas/BillImportIsoMoneyOperationDto"},"due_date":{"deprecated":true,"allOf":[{"$ref":"#/components/schemas/BillImportDateOperationDto"}]},"due_date_iso":{"$ref":"#/components/schemas/BillImportDateOperationDto"},"account_number":{"$ref":"#/components/schemas/BillImportStringOperationDto"},"reference_number":{"$ref":"#/components/schemas/BillImportStringOperationDto"},"bill_number":{"$ref":"#/components/schemas/BillImportStringOperationDto"},"currency":{"deprecated":true,"allOf":[{"$ref":"#/components/schemas/BillImportCurrencyOperationDto"}]},"service_period":{"$ref":"#/components/schemas/BillImportServicePeriodOperationDto"},"remit_to_address":{"$ref":"#/components/schemas/BillImportRemitToAddressOperationDto"},"payment_url":{"$ref":"#/components/schemas/BillImportUrlOperationDto"},"line_items":{"$ref":"#/components/schemas/BillImportLineItemsOperationDto"},"payment_date":{"$ref":"#/components/schemas/BillImportDateOperationDto"},"payment_method":{"$ref":"#/components/schemas/BillImportStringOperationDto"},"classification_override":{"$ref":"#/components/schemas/BillImportClassificationOperationDto"},"override_reason":{"$ref":"#/components/schemas/BillImportStringOperationDto"}}},"UpdateBillImportReviewDraftDto":{"type":"object","properties":{"changes":{"$ref":"#/components/schemas/BillImportReviewChangesDto"}},"required":["changes"]},"ConfirmBillImportDto":{"type":"object","properties":{"final_changes":{"$ref":"#/components/schemas/BillImportReviewChangesDto"}},"required":["final_changes"]},"ConfirmBillImportResponseDto":{"type":"object","properties":{"outcome":{"type":"string","example":"committed"},"bill":{"$ref":"#/components/schemas/PublicBillResponseDto"}},"required":["outcome","bill"]},"CreateClientBillDto":{"type":"object","properties":{"client_user_id":{"type":"string","example":"user_abc123"},"payee_name":{"type":"string","example":"Example Utility"},"amount_due":{"type":"number","deprecated":true,"description":"Legacy major-unit amount. Prefer total_amount."},"currency":{"type":"string","deprecated":true,"description":"Legacy currency companion to amount_due. Prefer total_amount.currency."},"total_amount":{"$ref":"#/components/schemas/IsoMoneyInputDto"},"due_date":{"type":"string","deprecated":true,"description":"Legacy date field. Prefer due_date_iso."},"due_date_iso":{"type":"string","example":"2026-07-22","description":"Canonical ISO 8601 calendar date (YYYY-MM-DD)."},"bill_number":{"type":"string"},"account_number":{"type":"string"},"reference_number":{"type":"string"},"payment_url":{"type":"string"},"description":{"type":"string"}},"required":["client_user_id","payee_name"]},"CreateClientBillResponseDto":{"type":"object","properties":{"bill":{"$ref":"#/components/schemas/PublicBillResponseDto"},"replayed":{"type":"boolean"}},"required":["bill","replayed"]},"AttestExternalPaymentDto":{"type":"object","properties":{}},"AccountLinkBillSyncDataResponseDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"link_abc123"},"added":{"type":"array","items":{"$ref":"#/components/schemas/PublicBillResponseDto"}},"modified":{"type":"array","items":{"$ref":"#/components/schemas/PublicBillResponseDto"}},"removed":{"type":"array","items":{"$ref":"#/components/schemas/PublicBillResponseDto"}},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"},"added_count":{"type":"number"},"updated_count":{"type":"number"},"removed_count":{"type":"number"},"request_id":{"type":"string","nullable":true}},"required":["account_link_id","added","modified","removed","has_more","added_count","updated_count","removed_count"]},"AccountLinkBillSyncResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AccountLinkBillSyncDataResponseDto"}},"required":["success","data"]},"ListInsightsQueryDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"alink_01HX...","description":"The account_link_id (biller connection) to list insights for."},"account_id":{"type":"string","example":"acct_01HX...","description":"The account_id (the account within the connection) to list insights for."},"user_aid":{"type":"string","example":"user_42","description":"Optional filter to insights for a specific end-user (your client_user_id)."},"status":{"type":"string","example":"OPEN","description":"Filter by lifecycle status.","enum":["OPEN","SNOOZED","DISMISSED","RESOLVED"]},"limit":{"type":"number","example":50,"description":"Maximum number of insights to return (1-100)."},"cursor":{"type":"string","example":"cursor_abc123","description":"Opaque pagination cursor from a prior response."}},"required":["account_link_id","account_id"]},"SnoozeInsightBodyDto":{"type":"object","properties":{"until":{"type":"string","example":"2026-07-01T00:00:00.000Z","description":"ISO-8601 instant to snooze the insight until. Must be in the future."}},"required":["until"]},"ResolveInsightBodyDto":{"type":"object","properties":{"resolved_at":{"type":"string","example":"2026-06-13T12:00:00.000Z","description":"Optional ISO-8601 instant the insight was resolved at. Defaults to server-now."}}},"ProcessBillDto":{"type":"object","properties":{"worker_id":{"type":"string","example":"worker-123","description":"Worker ID processing the bill"},"notes":{"type":"string","example":"Verified bill amount and due date","description":"Processing notes"}},"required":["worker_id"]},"ApproveBillDto":{"type":"object","properties":{"worker_id":{"type":"string","example":"worker-123","description":"Worker ID approving the bill"},"notes":{"type":"string","example":"Bill verified and approved for payment","description":"Approval notes"}},"required":["worker_id"]},"RejectBillDto":{"type":"object","properties":{"worker_id":{"type":"string","example":"worker-123","description":"Worker ID rejecting the bill"},"reason":{"type":"string","example":"Amount mismatch - requires user verification","description":"Rejection reason"}},"required":["worker_id","reason"]},"SyncBillsDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID to sync bills for"},"account_link_ids":{"example":["link-456","link-789"],"description":"Account link IDs to sync (optional)","type":"array","items":{"type":"string"}}},"required":["client_id"]},"ListBillsQueryDto":{"type":"object","properties":{"status":{"type":"string"},"biller_id":{"type":"string"},"account_link_id":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"limit":{"type":"number","default":100},"cursor":{"type":"string"}}},"MoneyValueDto":{"type":"object","properties":{"value":{"type":"number","example":100.5,"description":"Amount value"},"currency":{"type":"string","example":"USD","description":"Currency code","default":"USD"}},"required":["value","currency"]},"CreateBillDto":{"type":"object","properties":{"account_link_id":{"type":"string","example":"link-456","description":"Account link ID"},"biller_id":{"type":"string","example":"biller-123","description":"Biller ID"},"bill_number":{"type":"string","example":"BILL-2025-001","description":"Bill number"},"amount":{"description":"Bill amount","allOf":[{"$ref":"#/components/schemas/MoneyValueDto"}]},"due_date":{"type":"string","example":"2025-02-15T00:00:00Z","description":"Due date (ISO format)"},"description":{"type":"string","example":"Monthly utility bill","description":"Bill description"},"client_id":{"type":"string","example":"client-123","description":"Client ID"},"metadata":{"type":"object","example":{"category":"UTILITIES","userId":"user-123"},"description":"Additional metadata"},"pdf_file":{"type":"object","example":{"file_name":"bill.pdf","file_size":1024,"file_url":"https://example.com/bill.pdf","mime_type":"application/pdf","checksum":"abc123"},"description":"PDF file metadata"}},"required":["account_link_id","biller_id","bill_number","amount","due_date"]},"UpdateBillerTypeDto":{"type":"object","properties":{"biller_type":{"type":"string","description":"Corrected biller category.","enum":["UTILITY","TELECOM","INSURANCE","CREDIT_CARD","LOAN","SUBSCRIPTION","BANKING","OTHER"]}},"required":["biller_type"]},"CreateBillerConfigDto":{"type":"object","properties":{"operation_id":{"type":"string","description":"Caller-generated identifier retained across retries of the same create operation.","example":"c56a4180-65aa-42ec-a945-5fd21dec0538"},"name":{"type":"string"},"type":{"type":"string"},"status":{"type":"string"},"base_url":{"type":"string"},"credentials_required":{"type":"boolean"},"mfa_required":{"type":"boolean"},"session_timeout_minutes":{"type":"number"},"max_retry_attempts":{"type":"number"},"connection_methods_json":{"type":"string","description":"JSON-encoded BillerConnectionMethod[] (scraping | oauth | api_key arms)."},"default_connection_kind":{"type":"string","description":"scraping | oauth | api_key — must match a kind in connection_methods_json."},"identity_registry_json":{"type":"string","description":"JSON-encoded BillerIdentityRegistry (sender emails + websites)."},"supported_consent_scopes":{"type":"array","items":{"type":"string"}},"metadata_json":{"type":"string"}},"required":["operation_id","name","type","status","base_url","credentials_required","mfa_required","session_timeout_minutes","max_retry_attempts"]},"UpdateBillerConfigDto":{"type":"object","properties":{"company_name":{"type":"string","description":"Company name"},"service_regions":{"description":"Supported ISO 3166-2 service regions.","type":"array","items":{"type":"string"}},"website":{"type":"string","description":"Company website URL"},"support_email":{"type":"string","description":"Support email address"},"support_phone":{"type":"string","description":"Support phone number"},"integration_type":{"type":"string","description":"Integration type","enum":["OAUTH_API","IP_WHITELIST","DOCKER_GATEWAY","HYBRID","DIRECT_API"]},"integration_config":{"type":"object","description":"Type-specific integration configuration"}}},"SaveRecordedSelectorsDto":{"type":"object","properties":{"selector_type":{"type":"string","enum":["login","account_discovery","retrieve_bill","retrieve_observed_payment"],"description":"Which scraping selector bucket this recording targets."},"selectors_json":{"type":"string","description":"JSON-encoded recorded selectors — flat snake_case map or { webScraping: { selectors } }."},"login_url":{"type":"string","description":"Page URL where the selectors were captured. Recommended for `login` so replays know where to navigate."}},"required":["selector_type","selectors_json"]},"AdditionalRecordingOriginEntryDto":{"type":"object","properties":{"origin":{"type":"string","example":"i-doxs.net","description":"Bare eTLD+1 (registrable domain). Lowercase, no scheme, no path, no port, no subdomain."},"vendor":{"type":"string","example":"Kubra","description":"Operator-facing vendor label (display only)."},"reason":{"type":"string","example":"Eversource bills viewer hosted on Kubra portal","description":"Free-text operator justification (for audit display)."}},"required":["origin"]},"UpdateAdditionalRecordingOriginsDto":{"type":"object","properties":{"entries":{"description":"Full replacement list of allowlisted origins. Empty array clears the allowlist; the runtime gateway origin check then falls back to base_url match only.","type":"array","items":{"$ref":"#/components/schemas/AdditionalRecordingOriginEntryDto"}}},"required":["entries"]},"MarkBillerScriptUnhealthyDto":{"type":"object","properties":{"script_type":{"type":"string","description":"Script lane to mark unhealthy: LOGIN | ACCOUNT_DISCOVERY | RETRIEVE_BILL."},"client_id":{"type":"string","description":"Owning client for a manual post-login re-record (#4228)."}},"required":["script_type"]},"RestoreRecordingHistoryDto":{"type":"object","properties":{"history_sk":{"type":"string","description":"Full SK of the snapshot row to restore."}}},"VerifyBillerIdentityEntryDto":{"type":"object","properties":{"entry_kind":{"type":"string","enum":["sender_email","website"]},"key":{"type":"string","description":"The sender pattern or website domain being verified."},"verified_by":{"type":"string","description":"Operator who verified the entry. Controller defaults to \"unknown\"."}},"required":["entry_kind","key"]},"SplitBillerConfigDto":{"type":"object","properties":{"sender_patterns":{"description":"Sender patterns to split off.","type":"array","items":{"type":"string"}},"website_domains":{"description":"Website domains to split off.","type":"array","items":{"type":"string"}},"into_biller_name":{"type":"string","description":"Name for the newly created BillerConfig."},"correlation_id":{"type":"string","description":"Correlation id threaded into the split command."}}},"SetBillerScrapingPausedDto":{"type":"object","properties":{"paused":{"type":"boolean","description":"True pauses autonomous scraping for this biller."}},"required":["paused"]},"OffPeakWindowDto":{"type":"object","properties":{"timezone":{"type":"string","example":"America/New_York","description":"IANA timezone id."},"start_hour":{"type":"number","example":2,"description":"Window start hour, 0-23 inclusive."},"end_hour":{"type":"number","example":6,"description":"Window end hour, 0-23 exclusive; <= start_hour wraps midnight."}},"required":["timezone","start_hour","end_hour"]},"SetScrapePolicyDto":{"type":"object","properties":{"off_peak_window":{"$ref":"#/components/schemas/OffPeakWindowDto"},"max_concurrent_scrapes":{"type":"number","example":3,"description":"Max concurrent scrapes; integer 1-100."},"sanctioned":{"type":"boolean","example":false,"description":"Legal-sanction marker; true records the biller as sanctioned."},"sanctioned_note":{"type":"string","description":"Free-text sanction note (<= 500 chars)."}}},"RecipePreferenceDto":{"type":"object","properties":{"recipe_replay_override":{"type":"string","enum":["force_on","force_off",""],"example":"force_on","description":"Tri-state replay override. 'force_on'/'force_off' override the global RECIPE_MODE flag; '' clears the override (follow-global)."}},"required":["recipe_replay_override"]},"BulkUpdateBillerConfigsDto":{"type":"object","properties":{"biller_ids":{"type":"array","items":{"type":"string"}},"updates_json":{"type":"string"}},"required":["biller_ids","updates_json"]},"BulkDeleteBillerConfigsDto":{"type":"object","properties":{"biller_ids":{"type":"array","items":{"type":"string"}}},"required":["biller_ids"]},"CreateFromTemplateDto":{"type":"object","properties":{"template_name":{"type":"string"},"biller_name":{"type":"string"},"customizations_json":{"type":"string"}},"required":["template_name","biller_name"]},"RequestManualBillerOnboardingDto":{"type":"object","properties":{"operation_id":{"type":"string"},"biller_name":{"type":"string"},"biller_type":{"type":"string"},"biller_url":{"type":"string"}},"required":["operation_id","biller_name","biller_type","biller_url"]},"ClaimBillerOnboardingDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Worker taking or releasing the claim"}},"required":["worker_id"]},"SelectExistingBillerDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Existing biller to resolve the request against."},"prompt_version":{"type":"string","description":"Version of the prompt that produced the selection."}},"required":["biller_id","prompt_version"]},"CompleteBillerOnboardingReviewDto":{"type":"object","properties":{"edited_by":{"type":"string"},"draft_config_json":{"type":"string"},"override":{"type":"object","description":"Override for the strong-match gate (set when operator chose create-new despite suggestions)","example":{"reason_code":"different_region_or_entity","reason_text":"East coast subsidiary, separate billing entity","suggested_biller_ids":["biller-abc"]}}},"required":["edited_by","draft_config_json"]},"StartStage2ScriptRecordingDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller whose stage-2 script is being recorded."},"script_type":{"type":"string","enum":["ACCOUNT_DISCOVERY","RETRIEVE_BILL","RETRIEVE_OBSERVED_PAYMENT"]},"client_id":{"type":"string","description":"Owning client. Omitted by Stage2RecorderFlow when the task carries no client_id; the controller then resolves it from the biller links."}},"required":["biller_id","script_type"]},"StartLoginRecordingBodyDto":{"type":"object","properties":{"website":{"type":"string","description":"Biller website to open in the recording browser."},"biller_name":{"type":"string","description":"Biller display name (context for AI identify)."},"biller_type":{"type":"string","description":"Biller type (context for AI identify)."}},"required":["website"]},"StartStage2RecordingBodyDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller whose stage-2 script is being recorded."},"link_id":{"type":"string","description":"Optional link id the credentials came from."},"base_url":{"type":"string","description":"Biller login page URL."},"login_config":{"type":"object","description":"Recorded login config blob ({ webScraping: { selectors: … } })."},"username":{"type":"string","description":"Biller account username."},"password":{"type":"string","description":"Biller account password."},"biller_name":{"type":"string","description":"Biller display name."}},"required":["biller_id","base_url","login_config","username","password"]},"RecordingEntryActionStepDto":{"type":"object","properties":{"kind":{"type":"string","enum":["click","wait_for_selector","wait_ms"]},"selector":{"type":"string","description":"CSS selector for click / wait_for_selector."},"timeout_ms":{"type":"number","description":"Timeout for wait_for_selector (ms)."},"ms":{"type":"number","description":"Fixed wait duration for wait_ms (ms)."}},"required":["kind"]},"IdentifyRecordingFormBodyDto":{"type":"object","properties":{"dom_snapshot":{"type":"string","description":"DOM snapshot HTML. Omitted by the portal — the recorder captures the live session DOM."},"page_url":{"type":"string","description":"Page URL the snapshot was taken from."},"biller_name":{"type":"string","description":"Biller display name (context for AI identify)."},"entry_action":{"description":"#4658 (D21) — operator-captured nav steps (nav_recipe). Only meaningful on identify-account-discovery / identify-retrieve-bill.","type":"array","items":{"$ref":"#/components/schemas/RecordingEntryActionStepDto"}}}},"VerifyBillerDto":{"type":"object","properties":{"verified_by":{"type":"string"}},"required":["verified_by"]},"RejectBillerVerificationDto":{"type":"object","properties":{"rejection_reason":{"type":"string"},"rejected_by":{"type":"string"}},"required":["rejection_reason","rejected_by"]},"GmailPubSubPushDto":{"type":"object","properties":{"message":{"type":"object","description":"Pub/Sub message envelope. Opaque: only `message.data` is read, and unknown Google-owned keys must survive."},"subscription":{"type":"string","description":"Pub/Sub subscription name. Accepted; unused."},"deliveryAttempt":{"type":"number","description":"Google's redelivery counter. Accepted; unused."}}},"CreateEmailMessageDto":{"type":"object","properties":{"user_id":{"type":"string","description":"End user this message belongs to, in the client's namespace."},"from_email":{"type":"string","description":"Sender address."},"gmail_connection_id":{"type":"string","description":"Gmail connection this message arrived through."},"provider_message_id":{"type":"string","description":"Provider's own id for the message."},"to_email":{"type":"string","description":"Recipient address."},"subject":{"type":"string","description":"Message subject."},"body_text":{"type":"string","description":"Plain-text body."},"body_html":{"type":"string","description":"HTML body."},"received_at":{"type":"string","description":"ISO-8601 receipt time. Defaults to now."},"labels":{"description":"Provider labels.","type":"array","items":{"type":"string"}}},"required":["user_id","from_email"]},"ClassifyEmailDto":{"type":"object","properties":{"message_id":{"type":"string","description":"Message to classify."},"user_id":{"type":"string","description":"End user the message belongs to."},"force_reclassify":{"type":"boolean","description":"Re-run classification even if a result exists."}},"required":["message_id"]},"FindBillerByEmailDto":{"type":"object","properties":{"sender_email":{"type":"string","description":"Sender address to resolve to a biller."}},"required":["sender_email"]},"CreateGmailOAuthSessionDto":{"type":"object","properties":{"user_id":{"type":"string","description":"End user id in the authenticated client's namespace."},"redirect_uri":{"type":"string","description":"Allowlisted first-party callback URL after Google consent."},"code_challenge":{"type":"string","description":"Base64url SHA-256 challenge for the client-held PKCE verifier."},"code_challenge_method":{"type":"string","enum":["S256"],"default":"S256"}},"required":["user_id","redirect_uri","code_challenge"]},"GmailOAuthSessionDataDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"session_id":{"type":"string","example":"a92fb709-d311-45af-9456-394d87f1c221"},"status":{"type":"string","enum":["INITIATED","AUTHORIZED","CLAIMED","COMPLETED","DENIED","PROVIDER_ERROR","EXPIRED","REAUTHORIZE_REQUIRED","MAILBOX_ALREADY_CONNECTED"],"example":"INITIATED"},"expires_at":{"type":"string","format":"date-time","example":"2026-08-13T20:10:00.000Z"},"oauth_url":{"type":"string","description":"Google authorization URL. Present only on create."},"connection_id":{"type":"string","example":"gmail-connection-id"},"email_address":{"type":"string","example":"person@example.com"},"discovery_run_id":{"type":"string","example":"discovery-run-id"},"failure_code":{"type":"string","example":"GMAIL_OAUTH_REAUTHORIZE_REQUIRED"}},"required":["success","session_id","status","expires_at"]},"GmailOAuthSessionResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GmailOAuthSessionDataDto"}},"required":["success","data"]},"GmailOAuthSessionErrorResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"GMAIL_OAUTH_SESSION_EXPIRED"},"message":{"type":"string","example":"Gmail OAuth session expired."}},"required":["success","error","message"]},"CompleteGmailOAuthSessionDto":{"type":"object","properties":{"user_id":{"type":"string","description":"End user id used when this session was created."},"completion_token":{"type":"string","description":"One-time proof returned by the provider callback handoff."},"code_verifier":{"type":"string","description":"Original PKCE verifier held by the initiating client."}},"required":["user_id","completion_token","code_verifier"]},"GmailOAuthSessionAcceptedDataDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"session_id":{"type":"string","example":"a92fb709-d311-45af-9456-394d87f1c221"},"status":{"type":"string","enum":["INITIATED","AUTHORIZED","CLAIMED","COMPLETED","DENIED","PROVIDER_ERROR","EXPIRED","REAUTHORIZE_REQUIRED","MAILBOX_ALREADY_CONNECTED"],"example":"INITIATED"},"expires_at":{"type":"string","format":"date-time","example":"2026-08-13T20:10:00.000Z"},"oauth_url":{"type":"string","description":"Google authorization URL. Present only on create."},"connection_id":{"type":"string","example":"gmail-connection-id"},"email_address":{"type":"string","example":"person@example.com"},"discovery_run_id":{"type":"string","example":"discovery-run-id"},"failure_code":{"type":"string","example":"GMAIL_OAUTH_REAUTHORIZE_REQUIRED"},"status_url":{"type":"string","example":"/v1/emails/gmail/oauth-sessions/a92fb709-d311-45af-9456-394d87f1c221"}},"required":["success","session_id","status","expires_at","status_url"]},"GmailOAuthSessionAcceptedResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GmailOAuthSessionAcceptedDataDto"}},"required":["success","data"]},"CreateHumanReviewDto":{"type":"object","properties":{"classification_id":{"type":"string","description":"Classification the review is about."},"message_id":{"type":"string","description":"Message the review is about."},"user_id":{"type":"string","description":"End user the message belongs to."},"priority":{"type":"string","description":"Queue priority. Defaults to 'medium'."},"review_context":{"type":"string","description":"Free-text context shown to the reviewer."}}},"ClaimEmailReviewDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Worker taking or releasing the claim"}},"required":["worker_id"]},"CompleteHumanReviewDto":{"type":"object","properties":{"classification":{"type":"string","description":"Reviewer decision; anything but 'BILLER' means NOT_BILLER."},"decision":{"type":"string","description":"Legacy alias for `classification`."},"notes":{"type":"string","description":"Reviewer notes."},"review_notes":{"type":"string","description":"Alternate notes field the handler falls back to."},"confidence":{"type":"object","description":"Reviewer confidence, 0..1. Defaults to 1."},"biller_config":{"type":"object","description":"Biller config captured during review. Opaque stored shape — forwarded to email-service as JSON without re-keying."},"biller_config_json":{"type":"string","description":"Pre-stringified form of `biller_config`."},"reasoning":{"type":"string","description":"Reviewer rationale. Falls back to `notes`."},"client_id":{"type":"string","description":"Client the reviewed message belongs to."}}},"GetApiCallRecordsQueryDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID"},"start_date":{"type":"string","example":"2025-01-01","description":"Start date (ISO format)"},"end_date":{"type":"string","example":"2025-12-31","description":"End date (ISO format)"},"limit":{"type":"string","example":"100","description":"Maximum number of records to return"},"next_token":{"type":"string","description":"Opaque pagination cursor. Pass the `next_token` from a previous response to fetch the following page. Omit for the first page."},"include_portal_noise":{"type":"string","example":"false","description":"When 'true', include portal-browsing requests (session-mode 2xx GETs) in the response. Default 'false' hides them. Errors and integration calls are always shown regardless.","enum":["true","false"]},"env":{"type":"string","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true},"environment":{"type":"string","description":"DEPRECATED — value ignored. Removal scheduled 2026-08-23.","deprecated":true}},"required":["client_id"]},"GetWebhookDeliveryRecordsQueryDto":{"type":"object","properties":{"webhook_url":{"type":"string","example":"https://example.com/webhooks","description":"Webhook URL to filter delivery records"},"client_id":{"type":"string","example":"test-client-123","description":"Client ID"},"start_date":{"type":"string","example":"2025-01-01","description":"Start date (ISO format)"},"end_date":{"type":"string","example":"2025-12-31","description":"End date (ISO format)"},"event_type":{"type":"string","example":"bill.created","description":"Event type filter"},"delivery_status":{"type":"string","example":"delivered","description":"Delivery status filter"},"limit":{"type":"number","example":50,"description":"Max records to return"}}},"GetActiveAccountCountQueryDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID"},"date":{"type":"string","example":"2025-11-01","description":"Date to check active accounts (ISO format)"}},"required":["client_id"]},"GetAccountSnapshotQueryDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID"},"date":{"type":"string","example":"2025-11-01","description":"Snapshot date (ISO format)"}},"required":["client_id"]},"RecordApiCallDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID making the API call"},"endpoint":{"type":"string","example":"/bills","description":"API endpoint called"},"method":{"type":"string","example":"GET","description":"HTTP method"},"status_code":{"type":"number","example":200,"description":"Response status code"},"response_time":{"type":"number","example":125,"description":"Response time in milliseconds"}},"required":["client_id","endpoint","method"]},"RecordWebhookDeliveryDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID receiving the webhook"},"webhook_id":{"type":"string","example":"webhook-789","description":"Webhook ID"},"event_type":{"type":"string","example":"bill.created","description":"Event type"},"status_code":{"type":"number","example":200,"description":"Delivery status code"},"success":{"type":"boolean","example":true,"description":"Whether delivery was successful"}},"required":["client_id","webhook_id","event_type","success"]},"RecordAccountLinkDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID"},"account_link_id":{"type":"string","example":"link-456","description":"Account link ID"},"status":{"type":"string","example":"ACTIVE","description":"Link status"}},"required":["client_id","account_link_id","status"]},"RecordWorkerTaskCompletionDto":{"type":"object","properties":{"worker_id":{"type":"string","example":"worker-123","description":"Worker ID"},"task_type":{"type":"string","example":"BILL_PROCESSING","description":"Task type"},"duration_seconds":{"type":"number","example":320,"description":"Task duration in seconds"},"success":{"type":"boolean","example":true,"description":"Whether task was successful"}},"required":["worker_id","task_type","success"]},"SnapshotAccountCountsDto":{"type":"object","properties":{"client_id":{"type":"string","example":"test-client-123","description":"Client ID to snapshot"},"date":{"type":"string","example":"2025-11-01","description":"Snapshot date (ISO format)"}},"required":["client_id"]},"GetWorkerStatsQueryDto":{"type":"object","properties":{"worker_id":{"type":"string","example":"worker-123","description":"Worker ID"},"start_date":{"type":"string","example":"2025-01-01","description":"Start date (ISO format)"},"end_date":{"type":"string","example":"2025-12-31","description":"End date (ISO format)"}}},"GetWorkerTaskHistoryQueryDto":{"type":"object","properties":{"worker_id":{"type":"string","example":"worker-123","description":"Worker ID"},"start_date":{"type":"string","example":"2025-01-01","description":"Start date (ISO format)"},"end_date":{"type":"string","example":"2025-12-31","description":"End date (ISO format)"}},"required":["worker_id"]},"SetClientBillingStatusDto":{"type":"object","properties":{"billing_status":{"type":"string","description":"Billing status to apply. ACTIVE makes the client invoiceable.","enum":["BETA","ACTIVE","SUSPENDED"],"example":"ACTIVE"},"reason":{"type":"string","description":"Why this client is being promoted or suspended (8-500 characters, trimmed). Recorded on the durable audit row.","example":"Design-partner contract signed; promoting off BETA."}},"required":["billing_status","reason"]},"CreateInvoiceRunDto":{"type":"object","properties":{"client_ids":{"description":"Restrict the run to these client ids. Omit to invoice every ACTIVE client from client-iam.","example":["client-1"],"type":"array","items":{"type":"string"}},"period_start":{"type":"string","description":"Inclusive start of the billing period (ISO 8601). Must be supplied together with period_end. Omit both for the previous UTC calendar month.","example":"2026-07-01T00:00:00.000Z"},"period_end":{"type":"string","description":"End of the billing period (ISO 8601). Must be supplied together with period_start, and must already have passed.","example":"2026-07-31T23:59:59.999Z"},"reason":{"type":"string","description":"Why this run is being triggered outside the monthly schedule (8-500 characters, trimmed). Recorded on the durable audit row.","example":"Re-running July after the metering backfill in #6650."}},"required":["reason"]},"AdjudicateSpotCheckDto":{"type":"object","properties":{}},"DashboardClientsDto":{"type":"object","properties":{"total":{"type":"number"}},"required":["total"]},"BillerPipelineItemDto":{"type":"object","properties":{"biller_id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"created_at":{"type":"string"}},"required":["biller_id","name","status","created_at"]},"DashboardBillersDto":{"type":"object","properties":{"total":{"type":"number"},"active":{"type":"number"},"inactive":{"type":"number"},"maintenance":{"type":"number"},"onboarding_pipeline":{"type":"array","items":{"$ref":"#/components/schemas/BillerPipelineItemDto"}}},"required":["total","active","inactive","maintenance","onboarding_pipeline"]},"DashboardAccountsDto":{"type":"object","properties":{"total_linked":{"type":"number"},"active":{"type":"number"},"pending":{"type":"number"},"error":{"type":"number"}},"required":["total_linked","active","pending","error"]},"DashboardBillsDto":{"type":"object","properties":{"fetched_count":{"type":"number"},"paid_count":{"type":"number"},"fetch_success_rate":{"type":"number"}},"required":["fetched_count","paid_count","fetch_success_rate"]},"DashboardOperationsDto":{"type":"object","properties":{"api_call_count":{"type":"number"},"worker_success_rate":{"type":"number"},"avg_task_duration_ms":{"type":"number"}},"required":["api_call_count","worker_success_rate","avg_task_duration_ms"]},"DashboardOnboardingCostDto":{"type":"object","properties":{"avg_tasks_per_biller":{"type":"number"},"avg_duration_per_biller_ms":{"type":"number"}},"required":["avg_tasks_per_biller","avg_duration_per_biller_ms"]},"DashboardSummaryDto":{"type":"object","properties":{"clients":{"$ref":"#/components/schemas/DashboardClientsDto"},"billers":{"$ref":"#/components/schemas/DashboardBillersDto"},"accounts":{"$ref":"#/components/schemas/DashboardAccountsDto"},"bills":{"$ref":"#/components/schemas/DashboardBillsDto"},"operations":{"$ref":"#/components/schemas/DashboardOperationsDto"},"onboarding_cost":{"$ref":"#/components/schemas/DashboardOnboardingCostDto"}},"required":["clients","billers","accounts","bills","operations","onboarding_cost"]},"ReplayDeadLetterDto":{"type":"object","properties":{"client_id":{"type":"string","description":"Owning client of the dead letter (dead letters are client-partitioned)"},"replay_reason":{"type":"string","description":"Reason shown as \"last replayed by X: <reason>\""}},"required":["client_id"]},"RequestToLinkOnboardingDto":{"type":"object","properties":{"biller_name":{"type":"string","description":"Display name supplied by the end user. BillerAPI preserves this value exactly when creating the biller.","example":"Town of Westport Water"},"biller_url":{"type":"string","description":"HTTPS login or account URL for the biller. BillerAPI validates DNS/IP safety and canonicalizes the URL server-side.","example":"https://example.com/account/login"}},"required":["biller_name","biller_url"]},"CreateRequestToLinkDto":{"type":"object","properties":{"client_id":{"type":"string","description":"Optional client tenant id. When supplied, it must match the authenticated client.","example":"cli_abc123"},"client_user_id":{"type":"string","description":"Your end-user identifier — opaque to BillerAPI; ties an RTL to one user in your system.","example":"usr_xyz789"},"biller_id":{"type":"string","description":"Existing biller id from GET /v1/billers. Supply exactly one of biller_id or onboarding.","example":"test_electric_company"},"onboarding":{"description":"Explicit request for BillerAPI to onboard a biller that is not in the catalog. Supply exactly one of biller_id or onboarding.","allOf":[{"$ref":"#/components/schemas/RequestToLinkOnboardingDto"}]},"consents":{"description":"Consent scopes the end user is granting for the resulting link session.","type":"array","items":{"type":"string"}},"metadata":{"type":"object","description":"Arbitrary client-supplied metadata, echoed back on GET.","additionalProperties":true}},"required":["client_user_id"]},"UpdateRequestToLinkStatusDto":{"type":"object","properties":{}},"CancelRequestToLinkDto":{"type":"object","properties":{}},"CompleteOpsExtractionTaskDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Worker completing the review."},"result_json":{"type":"string","description":"Reviewed extraction result as a JSON string. Controller defaults to \"{}\"."},"notes":{"type":"string","description":"Reviewer notes."}},"required":["worker_id"]},"FlagExtractionTaskDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Ops worker recording the flag"},"reason":{"type":"string","description":"Why the document cannot be extracted"}},"required":["worker_id","reason"]},"AssignOpsExtractionTaskDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Worker the task is assigned to."}},"required":["worker_id"]},"CreateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","example":"https://myapp.com/webhooks/billerapi","description":"Destination URL BillerAPI POSTs signed events to."},"events":{"example":["bill.created","bill.updated","link.completed"],"description":"Per-endpoint event filter. Event types this subscription delivers. Must be deliverable event types — one of: bill.created, bill.deleted, bill.updated, bill_import.updated, biller.unsupported, connection.ready, customer.message.complaint, customer.message.created, insight.created, insight.updated, link.completed, link.disconnected, link.failure_reason_corrected, link.session_finished, link_request.cancelled, link_request.created, link_request.updated, link_token.completed, pay.escalated, pay.failed, pay.scheduled, pay.succeeded, payment.observed. Legacy collapse/rename sources (e.g. `bill.paid`, `link.expired`, `request-to-link.updated`, and the historic PascalCase forms like `BillCreated`) are ACCEPTED and normalized to the name they are actually delivered under — the stored + echoed value is the normalized one, so the response shows exactly what was saved. Any other string is rejected with a 400 (`error_code: VALIDATION_ERROR`, `errors[].code: unknown_event_type`) rather than silently stored as a subscription that can never fire. `*` and `all` subscribe to everything.","type":"array","items":{"type":"string"}},"description":{"type":"string","example":"Prod billing sync endpoint","description":"Human-readable label for the endpoint."}},"required":["url","events"]},"UpdateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","example":"https://myapp.com/webhooks/billerapi/v2","description":"Updated destination URL."},"events":{"example":["bill.created","bill.deleted"],"description":"Replacement event filter for this endpoint. Event types this subscription delivers. Must be deliverable event types — one of: bill.created, bill.deleted, bill.updated, bill_import.updated, biller.unsupported, connection.ready, customer.message.complaint, customer.message.created, insight.created, insight.updated, link.completed, link.disconnected, link.failure_reason_corrected, link.session_finished, link_request.cancelled, link_request.created, link_request.updated, link_token.completed, pay.escalated, pay.failed, pay.scheduled, pay.succeeded, payment.observed. Legacy collapse/rename sources (e.g. `bill.paid`, `link.expired`, `request-to-link.updated`, and the historic PascalCase forms like `BillCreated`) are ACCEPTED and normalized to the name they are actually delivered under — the stored + echoed value is the normalized one, so the response shows exactly what was saved. Any other string is rejected with a 400 (`error_code: VALIDATION_ERROR`, `errors[].code: unknown_event_type`) rather than silently stored as a subscription that can never fire. `*` and `all` subscribe to everything.","type":"array","items":{"type":"string"}},"enabled":{"type":"boolean","example":false,"description":"Enable or disable deliveries to this endpoint."},"description":{"type":"string","example":"Renamed endpoint","description":"Updated human-readable label."}}},"SendCustomerMessageDto":{"type":"object","properties":{}},"UpdateCustomerConsentDto":{"type":"object","properties":{}},"RecordCustomerComplaintDto":{"type":"object","properties":{}},"ValidateLinkTokenBodyDto":{"type":"object","properties":{"link_token":{"type":"string","description":"The `lt_`-prefixed link token to validate."}},"required":["link_token"]},"ValidateAccessTokenBodyDto":{"type":"object","properties":{"access_token":{"type":"string","description":"The link-scoped access token to validate."}},"required":["access_token"]},"LinkBillerDirectorySearchDto":{"type":"object","properties":{}},"UpdateLinkBodyDto":{"type":"object","properties":{"access_token":{"type":"string","description":"Replacement link-scoped access token."},"refresh_token":{"type":"string","description":"Replacement link-scoped refresh token."},"token_expires_at":{"type":"string","description":"When the access token expires (ISO-8601)."},"consent_scopes":{"description":"Consent scopes granted on this link.","type":"array","items":{"type":"string"}},"consent_expires_at":{"type":"string","description":"When consent expires (ISO-8601)."},"metadata":{"type":"object","description":"Opaque integrator metadata, forwarded verbatim."}}},"ConfirmLinkUserRegionBodyDto":{"type":"object","properties":{"user_region":{"type":"string","description":"Override region; omit to affirm the stored value."}}},"CreateLinkTokenUpdateDto":{"type":"object","properties":{"link_id":{"type":"string","description":"The id of the Link to repair."},"reason":{"type":"string","description":"Normalized reason echoed from the link.disconnected webhook: credentials_invalid | mfa_required | session_expired | consent_expired."}},"required":["link_id"]},"CreateLinkTokenBodyDto":{"type":"object","properties":{"client_user_id":{"type":"string","description":"Your stable identifier for the end user this link belongs to."},"consents":{"description":"Consent scopes the user is granting.","type":"array","items":{"type":"string"}},"client_id":{"type":"string","description":"Explicit client id. Validated against the credential; 403 on mismatch."},"biller_id":{"type":"string","description":"Pin the flow to a specific biller."},"connectivity_type":{"type":"string","description":"Preferred connectivity type for the link."},"redirect_uri":{"type":"string","description":"Where to send the user after a hosted flow."},"request_to_link_id":{"type":"string","description":"Associate the token with an existing request-to-link."},"metadata_json":{"type":"string","description":"Opaque JSON metadata string echoed back on the token."},"update":{"description":"Update-mode mint: repair an EXISTING Link (#4831).","allOf":[{"$ref":"#/components/schemas/CreateLinkTokenUpdateDto"}]},"hosted":{"type":"object","description":"Request a hosted connect flow: `true` or an options object."},"language":{"type":"string","description":"BCP-47 UI language for the connect flow (#4937). Defaults to `en`."},"webhook_url":{"type":"string","description":"Ignored. Webhook delivery is governed by your registered webhook config.","deprecated":true}},"required":["client_user_id"]},"SelectBillerBodyDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller the user picked."},"biller_name":{"type":"string","description":"Display name for the selected biller."},"biller_logo":{"type":"string","description":"Logo URL or data URI for the selected biller."},"connectivity_type":{"type":"string","description":"Connectivity type for the selection (e.g. `scraping`)."}},"required":["biller_id"]},"SubmitCredentialsPutBodyDto":{"type":"object","properties":{"credentialId":{"type":"string","description":"Vault credential id to submit. camelCase is the SDK wire name."}},"required":["credentialId"]},"SubmitCredentialsBodyDto":{"type":"object","properties":{"username":{"type":"string","description":"Username the user typed for the biller."},"password":{"type":"string","description":"Password the user typed for the biller."},"credential_id":{"type":"string","description":"Existing vault credential id to resubmit against."}},"required":["username","password"]},"SubmitMfaBodyDto":{"type":"object","properties":{"mfa_code":{"type":"string","description":"The OTP the user typed."},"mfa_type":{"type":"string","description":"Challenge type when the user picked from a picker."},"operation_id":{"type":"string","description":"Client-generated idempotency id for the submission."}},"required":["mfa_code"]},"DiscoverAccountsBodyDto":{"type":"object","properties":{"credential_id":{"type":"string","description":"Vault credential id to discover accounts with."}},"required":["credential_id"]},"SelectAccountsBodyDto":{"type":"object","properties":{"account_ids":{"description":"Discovered account ids to link. Must contain at least one id.","type":"array","items":{"type":"string"}}},"required":["account_ids"]},"ReportHostedSessionExitBodyDto":{"type":"object","properties":{"exit_reason":{"type":"string","description":"`error`, or anything else for `user_closed`."}}},"RecordConnectEventBodyDto":{"type":"object","properties":{"event_name":{"type":"string","description":"A `connect/*` taxonomy event name."},"metadata":{"type":"object","description":"Funnel metadata. Server-side allowlisted; no PII persisted."}}},"SetUserRegionBodyDto":{"type":"object","properties":{"user_region":{"type":"string","description":"The region the user selected (e.g. `MA` or `US-MA`)."}},"required":["user_region"]},"ExchangePublicTokenBodyDto":{"type":"object","properties":{"client_id":{"type":"string","description":"Explicit client id. Validated against the credential; 403 on mismatch."},"public_token":{"type":"string","description":"Public token, when not supplied in the path."}}},"ParameterResponseDto":{"type":"object","properties":{"name":{"type":"string","description":"Parameter name","example":"/billerapi/iam-service/dev/PORT"},"value":{"type":"string","description":"Parameter value (masked for SecureString)","example":"3001"},"type":{"type":"string","description":"Parameter type","enum":["String","StringList","SecureString"],"example":"String"},"serviceName":{"type":"string","description":"Service name","example":"iam-service"},"lastModifiedDate":{"type":"string","description":"Last modified date","example":"2025-01-15T10:30:00Z"},"version":{"type":"number","description":"Parameter version","example":1},"description":{"type":"string","description":"Parameter description or ARN"}},"required":["name","value","type","serviceName","lastModifiedDate","version"]},"ServiceInfoDto":{"type":"object","properties":{"serviceName":{"type":"string","description":"Service name","example":"iam-service"},"count":{"type":"number","description":"Number of parameters for this service","example":10}},"required":["serviceName","count"]},"UpdateParameterDto":{"type":"object","properties":{"name":{"type":"string","description":"Full parameter name (must start with /billerapi/)","example":"/billerapi/iam-service/dev/PORT"},"value":{"type":"string","description":"New parameter value","example":"3001"},"type":{"type":"string","description":"Parameter type","enum":["String","StringList","SecureString"],"example":"String"}},"required":["name","value","type"]},"EventResponseDto":{"type":"object","properties":{"eventId":{"type":"string","description":"Unique event identifier"},"eventType":{"type":"string","description":"Event type name"},"source":{"type":"string","description":"Source service that published the event"},"timestamp":{"type":"string","description":"Event timestamp"},"aggregateId":{"type":"string","description":"Aggregate ID associated with the event"},"correlationId":{"type":"string","description":"Correlation ID for tracking related events"},"userId":{"type":"string","description":"User ID associated with the event"},"payload":{"type":"object","description":"Event payload data"},"metadata":{"type":"object","description":"Event metadata"}},"required":["eventId","eventType","source","timestamp","payload","metadata"]},"EventQueryResponseDto":{"type":"object","properties":{"events":{"description":"Array of events matching the query","type":"array","items":{"$ref":"#/components/schemas/EventResponseDto"}},"lastKey":{"type":"string","description":"Pagination key for next page"},"total":{"type":"number","description":"Total number of events returned in this page"}},"required":["events","total"]},"BillerSignUpDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address for the biller account"},"password":{"type":"string","description":"Password (minimum 12 characters)"},"given_name":{"type":"string","description":"First name"},"family_name":{"type":"string","description":"Last name"},"company_name":{"type":"string","description":"Company name"}},"required":["email","password","given_name","family_name"]},"BillerConfirmSignUpDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address used during signup"},"confirmation_code":{"type":"string","description":"Verification code sent to email"}},"required":["email","confirmation_code"]},"BillerSignInDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address"},"password":{"type":"string","description":"Account password"}},"required":["email","password"]},"BillerForgotPasswordDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address for password reset"}},"required":["email"]},"BillerConfirmForgotPasswordDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address"},"confirmation_code":{"type":"string","description":"Verification code sent to email"},"new_password":{"type":"string","description":"New password (minimum 12 characters)"}},"required":["email","confirmation_code","new_password"]},"BillerResendCodeDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address to resend verification code"}},"required":["email"]},"SubmitBillerVerificationDto":{"type":"object","properties":{"biller_id":{"type":"string"},"legal_business_name":{"type":"string"},"ein_tax_id":{"type":"string"},"business_address":{"type":"string"},"website_url":{"type":"string"},"biller_type":{"type":"string"}},"required":["biller_id","legal_business_name","business_address","website_url","biller_type"]},"SubmitOnboardingDto":{"type":"object","properties":{"operation_id":{"type":"string","description":"Caller-generated identifier retained across retries."},"company_name":{"type":"string","description":"Company name"},"website":{"type":"string","description":"Company website URL"},"support_email":{"type":"string","description":"Support email address"},"support_phone":{"type":"string","description":"Support phone number"},"integration_type":{"type":"string","description":"Integration type","enum":["OAUTH_API","IP_WHITELIST","DOCKER_GATEWAY","HYBRID","DIRECT_API"]},"integration_config":{"type":"object","description":"Type-specific integration configuration"}},"required":["operation_id","company_name","website","support_email","integration_type"]},"ReportScriptIssueDto":{"type":"object","properties":{"description":{"type":"string","description":"Description of the issue"}},"required":["description"]},"InviteTeamMemberDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address of the team member to invite"},"role":{"type":"string","description":"Role to assign","enum":["admin","editor","viewer"]}},"required":["email","role"]},"CreateAgentKeyDto":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable label for the key."},"allowed_task_kinds":{"description":"Task kinds this key may claim. `['*']` grants all kinds. Defaults to [] (no kinds) when omitted.","type":"array","items":{"type":"string"}},"rate_limit_rpm":{"type":"number","description":"Per-key request budget, requests/minute. Defaults to 60."}},"required":["name"]},"RotateAgentKeyDto":{"type":"object","properties":{"grace_period_minutes":{"type":"number","description":"How long the outgoing secret keeps working after rotation. Defaults to 60 minutes when omitted."}}},"GetBillerCredentialsDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller whose credentials are requested."},"client_id":{"type":"string","description":"Owning client; scopes the vault lookup."},"task_id":{"type":"string","description":"Recording/execution task the fetch is authorized against."},"account_link_id":{"type":"string","description":"#4838 — real Link UUID used to derive user_region."}}},"GetBillerExecutionBundleDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller to build the server-side bundle for."},"client_id":{"type":"string"},"client_user_id":{"type":"string","description":"#3847 — end-user scope for the credential lookup."},"task_id":{"type":"string"},"account_link_id":{"type":"string"},"task_kind":{"type":"string","enum":["RETRIEVE_BILL","RETRIEVE_OBSERVED_PAYMENT"]}}},"GetBillerLoginBundleDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"client_user_id":{"type":"string"},"task_id":{"type":"string"},"credentials_only":{"type":"boolean","description":"#5607 — credentials-only mode for the LOGIN recording."},"script_type":{"type":"string","enum":["LOGIN","ACCOUNT_DISCOVERY","RETRIEVE_BILL","RETRIEVE_OBSERVED_PAYMENT"]},"task_generation":{"type":"number","description":"Lifecycle generation of the claiming task."}}},"GetClientBrowserExecutionBundleDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller to build the client-browser bundle for."},"task_id":{"type":"string","description":"Runner task id."},"task_kind":{"type":"string","enum":["LOGIN_EXECUTE","ACCOUNT_DISCOVERY_EXECUTE","RETRIEVE_BILL"]},"link_token_id":{"type":"string"},"client_id":{"type":"string"},"credential_id":{"type":"string"},"client_bootstrap":{"type":"boolean","description":"True only on the bootstrap leg."},"account_link_id":{"type":"string"},"account_id":{"type":"string"}},"required":["biller_id","task_id","task_kind"]},"PromoteClientBrowserBootstrapProofDto":{"type":"object","properties":{"proof":{"type":"object","description":"Client-browser bootstrap proof document. Shape-checked by validateClientBrowserBootstrapProof() in the handler, not here."}}},"PromoteClientApiRecipeDto":{"type":"object","properties":{"proof":{"type":"object","description":"Client-API recipe promotion proof. Shape-checked by validateClientApiRecipePromotionProof() in the handler, not here."}}},"ClientApiRecipeReviewBindingDto":{"type":"object","properties":{"task_id":{"type":"string"},"biller_id":{"type":"string"},"link_token_id":{"type":"string"},"client_id":{"type":"string"},"credential_id":{"type":"string"},"credential_revision":{"type":"string"},"account_id":{"type":"string"},"expected_recipe_revision":{"type":"number","description":"Recipe revision the candidate was produced against."}},"required":["task_id","biller_id","link_token_id","client_id","credential_id","credential_revision","account_id","expected_recipe_revision"]},"ClientApiRecipeReviewClaimDto":{"type":"object","properties":{"nonce_id":{"type":"string"},"claim_id":{"type":"string"},"idempotency_key":{"type":"string"}},"required":["nonce_id","claim_id","idempotency_key"]},"RecordClientApiRecipeReviewCandidateDto":{"type":"object","properties":{"binding":{"$ref":"#/components/schemas/ClientApiRecipeReviewBindingDto"},"claim":{"$ref":"#/components/schemas/ClientApiRecipeReviewClaimDto"},"approved_origin":{"type":"string","description":"Origin the candidate was captured against."},"candidate":{"type":"object","description":"Candidate evidence document; validated in the handler."}},"required":["binding","claim","approved_origin","candidate"]},"AgentRunnerBillerTaskRefDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller being looked up."},"task_id":{"type":"string","description":"Runner task id, for correlation only."}}},"MarkBillerUnsupportedDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller to flag unsupported."},"task_id":{"type":"string","description":"Recording task that hit the unsupported platform."},"reason":{"type":"string","enum":["auth_platform_unsupported","manual_capture_required"]},"detected_platform":{"type":"string","enum":["okta","auth0","ping","shibboleth"]}},"required":["biller_id","task_id","reason"]},"MarkRequiresClientBrowserDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller to flag as requiring the end user’s own browser."},"reason":{"type":"string","description":"Free-form audit provenance, e.g. 'captcha_detected_at_login_recording'."},"correlation_id":{"type":"string","description":"Correlation id (usually the runner task id)."}}},"ScoreBillerCandidatesDto":{"type":"object","properties":{"sender_domain":{"type":"string"},"candidate_base_url":{"type":"string"}}},"MarkScriptUnhealthyDto":{"type":"object","properties":{"biller_id":{"type":"string"},"script_type":{"type":"string","enum":["LOGIN","ACCOUNT_DISCOVERY","RETRIEVE_BILL"]},"reason":{"type":"string","description":"Why the script was escalated. Free text, uncapped."}},"required":["biller_id","script_type","reason"]},"SaveSelectorsDto":{"type":"object","properties":{"biller_id":{"type":"string"},"selector_type":{"type":"string","enum":["login","account_discovery","retrieve_bill","retrieve_observed_payment"]},"selectors_json":{"type":"string","description":"Serialized selector document. Uncapped."},"login_url":{"type":"string","description":"Capture URL; required in practice for `login`."},"requires_extended_hydration":{"type":"boolean","description":"#2791 — replays opt into the longer hydration wait."}}},"SaveLoginIndicatorsDto":{"type":"object","properties":{"biller_id":{"type":"string"},"logged_in_selector":{"type":"string","description":"Post-login presence selector. Uncapped."},"logged_in_user_selector":{"type":"string","description":"Post-login username selector. Uncapped."},"cached_session_url_hint":{"type":"string","description":"#4307 — post-login URL hint."},"selector_evidence":{"type":"object","description":"Selector grounding evidence document. Shape-checked by validateSelectorGroundingEvidence() in the handler, not here."}}},"RecordRetrievalSuccessDto":{"type":"object","properties":{"biller_id":{"type":"string"},"bill_count":{"type":"number","description":"Bills produced by the run."},"bill_list_reachable":{"type":"boolean"},"served_route":{"type":"string"},"execution_id":{"type":"string"},"fencing_token":{"type":"string","description":"Stringified numeric fencing token."},"outcome_sequence":{"type":"string","description":"Stringified monotonic outcome sequence."},"outcome_id":{"type":"string"},"probe_lease_id":{"type":"string"},"expected_health_version":{"type":"string","description":"Stringified health version for the CAS write."}}},"RecordSelectorOutcomeDto":{"type":"object","properties":{"biller_id":{"type":"string"},"slot_category":{"type":"string","enum":["login","account_discovery","retrieve_bill"]},"slot_key":{"type":"string"},"entry_value":{"type":"string","description":"The selector that matched or failed. Uncapped."},"outcome":{"type":"string","enum":["success","failure"]},"client_id":{"type":"string"}},"required":["biller_id","slot_category","slot_key","entry_value","outcome"]},"ProposeShadowSelectorsDto":{"type":"object","properties":{"biller_id":{"type":"string"},"slot_category":{"type":"string","enum":["login","account_discovery","retrieve_bill"]},"slot_key":{"type":"string"},"candidates":{"description":"Shadow selector candidates. Uncapped.","type":"array","items":{"type":"string"}},"client_id":{"type":"string"}},"required":["biller_id","slot_category","slot_key","candidates"]},"RecordRecordingFailureDto":{"type":"object","properties":{"biller_id":{"type":"string"},"reason":{"type":"string","description":"Why the recording failed. Free text, uncapped."}}},"ReportCredentialsRejectedDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"source":{"type":"string","description":"Which leg reported the rejection. Open vocabulary."},"correlation_id":{"type":"string"},"link_token_id":{"type":"string","description":"#3627 — exact LinkToken, skips the tier-2 lookup."},"reason":{"type":"string","description":"#3836 — failure-reason taxonomy. Open vocabulary."},"account_locked_action":{"type":"string","description":"#7200 — account-lockout remedy. Open vocabulary."}}},"ReportMfaRejectedDto":{"type":"object","properties":{"link_token_id":{"type":"string"},"credential_id":{"type":"string"},"biller_id":{"type":"string"},"client_id":{"type":"string"},"reason":{"type":"string","description":"e.g. 'WRONG_CODE' | 'EXPIRED' | 'LOCKED_OUT'."},"source":{"type":"string","description":"Defaults client-side to 'mfa_submit'."},"correlation_id":{"type":"string"}}},"ReportLoginSucceededDto":{"type":"object","properties":{"link_token_id":{"type":"string"},"credential_id":{"type":"string"},"biller_id":{"type":"string"},"client_id":{"type":"string"},"source":{"type":"string","description":"Defaults client-side to 'login_execute'."},"correlation_id":{"type":"string"}}},"IngestBillDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"account_link_id":{"type":"string","description":"#3841 — real Link UUID, or the legacy synthetic form."},"account_id":{"type":"string","description":"#1816 — canonical per-account identifier."},"task_id":{"type":"string"},"account_index":{"type":"number"},"bill_index":{"type":"number"},"amount":{"type":"string","description":"Amount as a scraped string, e.g. \"123.45\"."},"currency":{"type":"string"},"due_date":{"type":"string"},"reference":{"type":"string"},"document_url":{"type":"string"},"document_mime_type":{"type":"string"},"document_file_name":{"type":"string"},"document_file_size":{"type":"number"},"document_checksum":{"type":"string"},"provenance":{"type":"string","description":"#4247 — e.g. 'client_browser'."},"source_run_id":{"type":"string","description":"D11 — producing agent run id."}}},"IngestObservedPaymentDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"account_link_id":{"type":"string"},"account_id":{"type":"string"},"task_id":{"type":"string"},"account_index":{"type":"number"},"payment_index":{"type":"number"},"amount":{"type":"number","description":"Major-unit payment amount as a number."},"currency":{"type":"string"},"payment_date":{"type":"string"},"status":{"type":"string"},"confirmation_number":{"type":"string"},"payment_method_label":{"type":"string","description":"Scraped label, e.g. \"Visa ending 1234\"."},"row_hash":{"type":"string","description":"Row fingerprint used for idempotency."},"identity_hash":{"type":"string","description":"Identity fingerprint used for idempotency."},"duplicate_ordinal":{"type":"number","description":"Nth identical row in the same snapshot."},"scraped_at":{"type":"string"}}},"AgentCreateInsightDto":{"type":"object","properties":{"client_id":{"type":"string"},"account_link_id":{"type":"string"},"account_id":{"type":"string"},"user_aid":{"type":"string"},"biller_id":{"type":"string"},"bill_id":{"type":"string"},"type":{"type":"string"},"severity":{"type":"string"},"evidence_json":{"type":"string","description":"JSON object string. Uncapped (model output)."},"proposed_actions_json":{"type":"string","description":"JSON array string. Uncapped (model output)."},"reasoning":{"type":"string","description":"Model rationale. Uncapped."},"created_at":{"type":"string"},"correlation_id":{"type":"string"}}},"AgentBillRefDto":{"type":"object","properties":{"bill_id":{"type":"string"},"requesting_client_id":{"type":"string","description":"Tenant scope; the bill’s owning client_id."}}},"GetBillHistoryDto":{"type":"object","properties":{"account_link_id":{"type":"string"},"biller_id":{"type":"string"},"account_id":{"type":"string"},"requesting_client_id":{"type":"string"},"limit":{"type":"number","description":"Clamped server-side (default 12, max 50)."}}},"GetAccountLinkBillsDto":{"type":"object","properties":{"account_link_id":{"type":"string"},"account_id":{"type":"string"},"requesting_client_id":{"type":"string"},"limit":{"type":"number","description":"Clamped server-side (default 12, max 50)."}}},"GetObservedPaymentsDto":{"type":"object","properties":{"account_link_id":{"type":"string"},"requesting_client_id":{"type":"string"},"limit":{"type":"number","description":"Clamped server-side (default 20)."}}},"DiscoveredAccountDto":{"type":"object","properties":{"account_id":{"type":"string"},"portal_ordinal":{"type":"number","description":"Position in the portal list; handler enforces 0..49 + uniqueness."},"account_number":{"type":"string"},"account_name":{"type":"string"},"account_type":{"type":"string"},"balance":{"type":"number"},"currency":{"type":"string"}},"required":["account_id","portal_ordinal","account_number","account_name","account_type","balance","currency"]},"AccountsDiscoveredDto":{"type":"object","properties":{"link_token_id":{"type":"string"},"link_token":{"type":"string","description":"Opaque link token secret. Uncapped."},"biller_id":{"type":"string"},"client_id":{"type":"string"},"source_discovered_at":{"type":"string","description":"ISO timestamp of the discovery snapshot."},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/DiscoveredAccountDto"}},"discovery_run_id":{"type":"string","description":"D11 — producing discovery run id."}}},"EscalateEmailClassificationDto":{"type":"object","properties":{"classification_id":{"type":"string"},"message_id":{"type":"string"},"reason":{"type":"string","description":"Why the classification is being escalated. Uncapped."},"attempt_count":{"type":"number","description":"How many agent attempts preceded the escalation."}}},"AcquireBillerScrapeLockDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"task_id":{"type":"string","description":"Lock holder identity."},"ttl_ms":{"type":"number","description":"Lease duration in ms. Clamped server-side."},"script_kind":{"type":"string","description":"Which script kind holds the lock. Open vocabulary."}}},"ReleaseBillerScrapeLockDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"task_id":{"type":"string"},"script_kind":{"type":"string"}}},"GetScrapingSessionDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"user_hash":{"type":"string","description":"SHA-256(username + \":\" + pepper)."}}},"SaveScrapingSessionDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"user_hash":{"type":"string"},"storage_state_json":{"type":"string","description":"Playwright storage state. Uncapped by design."},"context_id":{"type":"string","description":"Browser context id; sent as '' when absent."},"requires_mfa":{"type":"boolean"},"expires_at":{"type":"string","description":"ISO expiry of the cached session."},"expected_version":{"type":"number","description":"Optimistic-concurrency version for the CAS write."}}},"InvalidateScrapingSessionDto":{"type":"object","properties":{"biller_id":{"type":"string"},"client_id":{"type":"string"},"user_hash":{"type":"string"},"reason":{"type":"string","description":"Why the cached session was dropped. Uncapped."}}},"ReportMfaChallengeRequiredDto":{"type":"object","properties":{"link_token_id":{"type":"string"},"credential_id":{"type":"string"},"biller_id":{"type":"string"},"client_id":{"type":"string"},"storage_state_json":{"type":"string","description":"Paused-browser storage state. Uncapped; never log it."},"current_url":{"type":"string","description":"URL the browser is paused on. Uncapped."},"challenges":{"description":"Challenge descriptors, forwarded verbatim to vault. Intentionally not a nested DTO — see the class doc block (resendSelector).","type":"array","items":{"type":"array"}},"source":{"type":"string","description":"Defaults client-side to 'login_execute'."},"correlation_id":{"type":"string"},"task_generation":{"type":"number"},"lease_id":{"type":"string","description":"Durable lease id (often an SQS ReceiptHandle). Uncapped."},"expected_continuation_id":{"type":"string"},"recording_task_id":{"type":"string"},"recording_script_type":{"type":"string"},"recording_session_id":{"type":"string"}}},"GetPendingMfaForRunnerDto":{"type":"object","properties":{"link_token_id":{"type":"string"}}},"GetMfaSubmissionDto":{"type":"object","properties":{"link_token_id":{"type":"string"},"submission_id":{"type":"string"}}},"MarkMfaSubmissionStatusDto":{"type":"object","properties":{"link_token_id":{"type":"string"},"submission_id":{"type":"string"},"status":{"type":"string","enum":["PROCESSING","ACCEPTED","REJECTED","EXPIRED"]},"rejection_reason":{"type":"string","description":"Sent as '' on non-rejections."},"claim_id":{"type":"string","description":"Sent as '' when the caller holds no claim."},"claim_lease_ms":{"type":"number","description":"Sent as 0 when the caller holds no claim."}}},"ApproveClientApiRecipeReviewDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller the review belongs to."},"expected_revision":{"type":"number","description":"Revision the operator believes is current (CAS guard)."},"constants":{"type":"object","description":"Cleartext constants keyed by query-schema entry name. Each value is SHA-256-checked against the recorded `value_sha256` by the controller."}},"required":["biller_id","expected_revision","constants"]},"StartAgentRunTraceDto":{"type":"object","properties":{"task_id":{"type":"string","description":"Task this run executes."},"task_kind":{"type":"string","description":"Task kind (LOGIN_SCRIPT_RECORDING, RETRIEVE_BILL, …)."},"biller_id":{"type":"string","description":"Biller the run targets."},"product":{"type":"string","enum":["billerapi","billebox"]}},"required":["task_id","task_kind","biller_id","product"]},"UploadAgentRunArtifactDto":{"type":"object","properties":{"artifact_type":{"type":"string","description":"Artifact type; the controller checks it against its allowlist."},"filename_suffix":{"type":"string","description":"Suffix appended to the generated S3 filename."},"content_b64":{"type":"string","description":"Base64 artifact bytes. Up to ~6.7 MB on the wire."}},"required":["artifact_type","content_b64"]},"FinalizeAgentRunTraceDto":{"type":"object","properties":{"outcome":{"type":"string","description":"success | human_review | error."},"outcome_detail":{"type":"string","description":"Free-text outcome detail."},"confidence":{"type":"number","description":"Run confidence, or null when the runner has none."},"uploaded_keys":{"description":"S3 keys the runner claims it uploaded.","type":"array","items":{"type":"string"}}},"required":["outcome","uploaded_keys"]},"PublishScrapingRunOutcomeDto":{"type":"object","properties":{"run_id":{"type":"string"},"agent_type":{"type":"string"},"outcome":{"type":"string","description":"succeeded | login_failed | extraction_empty | timeout | …"},"outcome_detail":{"type":"string","description":"Detail string. Controller caps it at 2048 with its own 400."},"occurred_at":{"type":"string","description":"ISO-8601; the controller defaults to now."},"recording_strategy":{"type":"string","enum":["one_shot","mcp_interactive"]},"mcp_turn_count":{"type":"number"},"mcp_tool_call_count":{"type":"number"},"mcp_max_snapshot_bytes":{"type":"number"},"mcp_navigate_count":{"type":"number"},"claude_run_ms":{"type":"number"},"trace_turns_captured":{"type":"number"},"mcp_turn_limit_exceeded":{"type":"boolean"},"mcp_abandoned":{"type":"boolean"},"failure_reason":{"type":"string","description":"#3564 PR1 — strict login-failure classifier tag. Sent by the runner; accepted here so the publish is not rejected."},"credential_id":{"type":"string","description":"#3564 PR1 — credential the upstream invalidation command keys on. Sent by the runner when a credential bundle was in scope."}},"required":["run_id","agent_type","outcome"]},"WriteAgentImprovementTraceDto":{"type":"object","properties":{"agent_type":{"type":"string"},"run_id":{"type":"string"},"prompt_version_hash":{"type":"string"},"model":{"type":"string"},"model_call_id":{"type":"string","description":"Caller sends `\"\"` when absent."},"client_id":{"type":"string","description":"Caller sends `\"\"` when absent."},"biller_id":{"type":"string"},"inputs_sanitized":{"type":"string","description":"Sanitized model input. Whole prompt turns — no cap."},"output_structured":{"type":"string","description":"Structured model output. Whole model turns — no cap."},"retrieved_brain_entry_ids":{"type":"array","items":{"type":"string"}},"debug_trace_run_id":{"type":"string"},"task_kind":{"type":"string"},"input_tokens":{"type":"number"},"output_tokens":{"type":"number"},"cache_read_tokens":{"type":"number"},"cache_creation_tokens":{"type":"number"}},"required":["agent_type","run_id","prompt_version_hash","model","biller_id"]},"ClaimSupportCaseDto":{"type":"object","properties":{}},"GetSupportCaseEvidenceDto":{"type":"object","properties":{}},"CompleteSupportCaseDto":{"type":"object","properties":{}},"CompleteEmailClassificationDto":{"type":"object","properties":{"classification":{"type":"string","description":"Classification decision; anything but 'BILLER' means NOT_BILLER."},"decision":{"type":"string","description":"Legacy alias for `classification`."},"confidence":{"type":"object","description":"Classifier confidence, 0..1. Defaults to 1."},"reasoning":{"type":"string","description":"Model rationale for the decision."},"notes":{"type":"string","description":"Free-text note. Accepted; not forwarded to email-service."}}},"FailScriptRecordingTaskDto":{"type":"object","properties":{"continuation_id":{"type":"string","description":"Durable continuation id being resumed."},"session_id":{"type":"string","description":"Browser session id backing the continuation."},"challenge_ref":{"type":"string","description":"Opaque reference to the pending challenge."},"challenge_kind":{"type":"string","enum":["OTP","PUSH","SECURITY_QUESTION","REGION","OTHER"]},"challenge_label":{"type":"string","description":"Human-facing label for the challenge prompt."},"continuation_expires_at":{"type":"string","description":"ISO-8601 expiry of the continuation window."},"submit_cap":{"type":"number","description":"Max challenge submissions allowed."},"resend_cap":{"type":"number","description":"Max challenge resends allowed."},"allowed_region_options":{"description":"Region options offered by the biller.","type":"array","items":{"type":"string"}},"biller_id":{"type":"string","description":"Biller this recording belongs to."},"outcome":{"type":"string","enum":["FAILED","ABSTAINED","AWAITING_CREDENTIALS","AWAITING_MFA","HUMAN_REVIEW"]},"reason":{"type":"string","description":"Why the recording failed."},"diagnostics":{"type":"object","description":"Structured failure diagnostics (audit only)."},"generation":{"type":"number","description":"Lifecycle generation of the failing task."},"lease_id":{"type":"string","description":"Durable recording lease id."}}},"CompleteExtractionTaskDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Echo of the calling worker id. Ignored — the gateway uses the authenticated agent key id."},"result_json":{"type":"object","description":"Extracted fields. Either a JSON string or an object; the gateway stringifies objects. `@Allow()` because both shapes are live."},"notes":{"type":"string","description":"Free-text note stored with the extraction."}}},"CompleteBillerOnboardingRequestDto":{"type":"object","properties":{"draft_config_json":{"type":"string","description":"Draft biller config, JSON-stringified."},"confidence":{"type":"number","description":"Agent confidence in the draft, 0..1."},"prompt_version":{"type":"string","description":"Version of the prompt that produced the draft."}},"required":["draft_config_json","confidence","prompt_version"]},"ClaimScriptRecordingTaskDto":{"type":"object","properties":{"continuation_id":{"type":"string","description":"Durable continuation id being resumed."},"session_id":{"type":"string","description":"Browser session id backing the continuation."},"challenge_ref":{"type":"string","description":"Opaque reference to the pending challenge."},"challenge_kind":{"type":"string","enum":["OTP","PUSH","SECURITY_QUESTION","REGION","OTHER"]},"challenge_label":{"type":"string","description":"Human-facing label for the challenge prompt."},"continuation_expires_at":{"type":"string","description":"ISO-8601 expiry of the continuation window."},"submit_cap":{"type":"number","description":"Max challenge submissions allowed."},"resend_cap":{"type":"number","description":"Max challenge resends allowed."},"allowed_region_options":{"description":"Region options offered by the biller.","type":"array","items":{"type":"string"}},"generation":{"type":"number","description":"Lifecycle generation of the task being claimed. Present + mismatched makes a lost claim a 409 instead of a silent success."},"lease_id":{"type":"string","description":"Durable recording lease id."}}},"CompleteScriptRecordingTaskDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller this recording belongs to."},"config_json":{"type":"object","description":"Recorded selector bucket. Either a JSON string or an object; the gateway stringifies objects before the gRPC call."},"confidence":{"type":"object","description":"Recording confidence, 0..1. Defaults to 1."},"reasoning":{"type":"string","description":"Free-text rationale recorded with the selectors."},"discovered_url":{"type":"string","description":"Login/landing URL discovered during recording. Consumed by the LOGIN controller (it updates the biller base_url); accepted and ignored by the other three so one DTO covers all four."},"generation":{"type":"number","description":"Lifecycle generation of the task being completed."},"lease_id":{"type":"string","description":"Durable recording lease id."}},"required":["biller_id"]},"RecordApiRecipeDto":{"type":"object","properties":{}},"RecordApiRawTraceIndexDto":{"type":"object","properties":{}},"CompleteRetrieveBillTaskDto":{"type":"object","properties":{"worker_id":{"type":"string","description":"Echo of the calling worker id. Ignored — the agent key wins."},"result_json":{"type":"object","description":"Retrieved bill payload; JSON string or object."},"bill_data":{"type":"object","description":"Legacy alias the controller falls back to when result_json is absent."},"notes":{"type":"string","description":"Free-text note stored with the retrieval."}}},"FailRetrieveBillTaskDto":{"type":"object","properties":{"continuation_id":{"type":"string","description":"Durable continuation id being resumed."},"session_id":{"type":"string","description":"Browser session id backing the continuation."},"challenge_ref":{"type":"string","description":"Opaque reference to the pending challenge."},"challenge_kind":{"type":"string","enum":["OTP","PUSH","SECURITY_QUESTION","REGION","OTHER"]},"challenge_label":{"type":"string","description":"Human-facing label for the challenge prompt."},"continuation_expires_at":{"type":"string","description":"ISO-8601 expiry of the continuation window."},"submit_cap":{"type":"number","description":"Max challenge submissions allowed."},"resend_cap":{"type":"number","description":"Max challenge resends allowed."},"allowed_region_options":{"description":"Region options offered by the biller.","type":"array","items":{"type":"string"}},"biller_id":{"type":"string","description":"Biller the retrieval was against."},"outcome":{"type":"string","enum":["FAILED","ABSTAINED","AWAITING_CREDENTIALS","AWAITING_MFA","HUMAN_REVIEW"]},"reason":{"type":"string","description":"Why the retrieval failed."},"diagnostics":{"type":"object","description":"Structured failure diagnostics (audit only)."},"generation":{"type":"number","description":"Lifecycle generation of the failing task."},"lease_id":{"type":"string","description":"Durable lease id."}}},"MarkAllNotificationsReadDto":{"type":"object","properties":{"scope":{"type":"string","description":"Scope of the mark-all. The only observed value is `all`."},"category":{"type":"string","description":"Restrict the mark-all to one notification category."}},"required":["scope"]},"NotificationCategoryPreferenceDto":{"type":"object","properties":{"category":{"type":"string","description":"Notification category this row configures."},"portal_enabled":{"type":"boolean","description":"Deliver this category in the portal bell."},"email_enabled":{"type":"boolean","description":"Deliver this category by email."}},"required":["category","portal_enabled","email_enabled"]},"UpdateNotificationPreferencesDto":{"type":"object","properties":{"preferences":{"description":"Full replacement preference matrix.","type":"array","items":{"$ref":"#/components/schemas/NotificationCategoryPreferenceDto"}}}},"ReplayActivityDto":{"type":"object","properties":{"delivery_id":{"type":"string","description":"Delivery id (matches the activity row resource_id for webhook events)"},"replay_reason":{"type":"string","description":"Why the developer is resending (3-280 chars; surfaced on the row)."}},"required":["delivery_id","replay_reason"]},"ReplayWebhookDto":{"type":"object","properties":{"client_id":{"type":"string","description":"Client ID (for ownership validation)","example":"client-123"}},"required":["client_id"]},"ReplayDeliveryDto":{"type":"object","properties":{"replay_reason":{"type":"string","description":"Why the developer is resending (3-280 chars; surfaced on the row as \"last replayed by X: <reason>\")"}},"required":["replay_reason"]},"ResendFailedWebhooksDto":{"type":"object","properties":{"since":{"type":"string","description":"ISO-8601 lower bound — only failed deliveries with exhausted_at >= since are resent","example":"2026-07-06T00:00:00.000Z"},"webhook_url":{"type":"string","description":"Optional endpoint filter — only resend failed deliveries for this webhook URL"},"replay_reason":{"type":"string","description":"Why the developer is resending (3-280 chars; recorded on every replayed delivery)"}},"required":["since","replay_reason"]},"StorePaymentMethodDto":{"type":"object","properties":{"pan":{"type":"string","description":"PAN (digits, 13–19 chars)"},"cvv":{"type":"string","description":"CVV (3–4 digits)"},"expiry_month":{"type":"number","description":"Expiry month (1–12)","minimum":1,"maximum":12},"expiry_year":{"type":"number","description":"Expiry year (4-digit)"},"bucket":{"type":"string","description":"Bucket label (e.g. \"primary\")"},"client_user_id":{"type":"string","description":"Client-scoped end-user id (required for client-credential callers; ignored for JWT/pay_token callers)."}},"required":["pan","expiry_month","expiry_year"]},"InitiatePaymentDto":{"type":"object","properties":{"bill_id":{"type":"string"},"payment_method_id":{"type":"string"},"idempotency_key":{"type":"string","description":"Idempotency key (optional in body, can also come from Idempotency-Key header)"},"amount_minor_units":{"type":"number","description":"Amount in minor units (cents). Defaults to bill amount."},"currency":{"type":"string","description":"3-letter currency code"},"execute_at":{"type":"string","description":"ISO-8601 timestamp to execute the payment at (#5072 scheduled pay). Must be in the future, at most 366 days out. Omit for immediate execution."},"client_user_id":{"type":"string","description":"Client-scoped end-user id (required for client-credential callers; ignored for JWT/pay_token callers)."}},"required":["bill_id","payment_method_id"]},"ResolvePaymentAttemptDto":{"type":"object","properties":{"resolved_to":{"type":"string","enum":["PAID","FAILED"],"description":"Final state the operator chose"},"reason":{"type":"string","description":"Audit reason for the resolution"},"confirmation_number":{"type":"string","description":"Confirmation number (required when resolved_to=PAID)"},"error_code":{"type":"string","description":"Payment error code (optional when resolved_to=FAILED)"}},"required":["resolved_to","reason"]},"PayTokenAmountDto":{"type":"object","properties":{"value":{"type":"number","description":"Amount in minor units."},"currency":{"type":"string","description":"ISO 4217 currency code."}},"required":["value","currency"]},"CreatePayTokenDto":{"type":"object","properties":{"client_user_id":{"type":"string","description":"Your identifier for the end user this token is scoped to."},"bill_id":{"type":"string","description":"Bill this token authorizes paying."},"amount":{"description":"Amount scope (minor units + ISO 4217 currency).","allOf":[{"$ref":"#/components/schemas/PayTokenAmountDto"}]},"payment_method_id":{"type":"string","description":"Pre-selected payment method to scope the token to."},"client_id":{"type":"string","description":"Explicit client id. Validated against the credential; 403 on mismatch."},"metadata_json":{"type":"string","description":"Opaque JSON metadata string echoed back on the token."}},"required":["client_user_id"]},"ValidatePayTokenDto":{"type":"object","properties":{"pay_token":{"type":"string","description":"The `payt_`-prefixed pay token to validate."}},"required":["pay_token"]},"WebAuthnRegisterOptionsDto":{"type":"object","properties":{"device_name":{"type":"string","description":"Friendly device name. Defaults to `Passkey`."}}},"WebAuthnRegisterVerifyDto":{"type":"object","properties":{"response":{"type":"object","description":"The `RegistrationResponseJSON` returned by the browser's `startRegistration()`. Passed through verbatim to client-iam."},"device_name":{"type":"string","description":"Friendly device name. Defaults to `Passkey`."}},"required":["response"]},"WebAuthnAuthenticateVerifyDto":{"type":"object","properties":{"response":{"type":"object","description":"The `AuthenticationResponseJSON` returned by the browser's `startAuthentication()`. Passed through verbatim to client-iam."},"sid":{"type":"string","description":"Per-tab step-up session id."}},"required":["response"]},"StepUpVerifyPasswordDto":{"type":"object","properties":{"password":{"type":"string","description":"The operator password to re-verify against Cognito."},"sid":{"type":"string","description":"Per-tab step-up session id."}},"required":["password"]},"CreateWebhookCaptureSessionDto":{"type":"object","properties":{"env":{"type":"string","enum":["sandbox","production"]},"sid":{"type":"string","description":"Per-tab session id. Controller generates one if absent."}}},"SubmitFeedbackBodyDto":{"type":"object","properties":{"signal":{"type":"string","enum":["succeeded","login_failed","bill_missing","data_incorrect"],"example":"data_incorrect","description":"The signal the client (or the client's end-user) reports about this scraping run. Subset of the implicit signal vocabulary — clients can only report values they can meaningfully observe (success, login fail, missing bill, wrong data). The system-only values (timeout, two_factor_required, extraction_empty) are not in this enum."},"biller_id":{"type":"string","example":"biller_verizon","description":"Biller ID the scraping run targeted. Used for per-biller feedback aggregation."},"by_user_id":{"type":"string","example":"user_42","description":"The end-user identifier within the client's domain who saw the result. Useful for audit and for per-user dedup downstream. Optional — clients without a user concept can omit it."},"notes":{"type":"string","example":"Bill shows $0 but my paper bill says $84.32. Acct ending 1234.","description":"Free-text notes. Never echoed back in metrics; PII-safe storage required by client."}},"required":["signal","biller_id"]},"FeedbackResponseDto":{"type":"object","properties":{"agent_type":{"type":"string","example":"recording_agent"},"run_id":{"type":"string","example":"run_abc123"},"client_id":{"type":"string","example":"client_billebox"},"biller_id":{"type":"string","example":"biller_verizon"},"signal":{"type":"string","enum":["succeeded","login_failed","bill_missing","data_incorrect"],"example":"data_incorrect"},"by_user_id":{"type":"string","example":"user_42"},"notes":{"type":"string","example":"Bill shows $0 ..."},"submitted_at":{"type":"string","example":"2026-05-30T18:00:00Z"},"idempotency_key":{"type":"string","example":"idem_2026-05-30T18:00:00Z_run_abc123","description":"The Idempotency-Key header value the caller supplied."},"already_existed":{"type":"boolean","example":false,"description":"True when this exact submission was already recorded (idempotent replay). False when this submission caused a new row to be written."}},"required":["agent_type","run_id","client_id","biller_id","signal","submitted_at","idempotency_key","already_existed"]},"SubmitGenericFeedbackBodyDto":{"type":"object","properties":{"resource_type":{"type":"string","enum":["bill","account_connection","payment"],"example":"bill","description":"The kind of resource the feedback is about. The gateway resolves the resource to the agent run that produced it before recording feedback."},"resource_id":{"type":"string","example":"bill_abc123","description":"The id of the resource (bill id, account_link/connection id, or payment id). Ownership is enforced tenant-scoped against the calling client."},"signal":{"type":"string","example":"wrong_amount","description":"The client-vocabulary signal. Valid values depend on resource_type. Bill: bill_correct | wrong_amount | wrong_due_date | wrong_status | duplicate_bill | not_my_bill | missing_line_items | stale_data. Account connection: accounts_correct | wrong_account | missing_account | wrong_biller_matched | duplicate_account."},"idempotency_key":{"type":"string","example":"idem_2026-06-22T18:00:00Z_bill_abc123","description":"Stripe-style idempotency key. Required so retries do not double-count. Recommended format: ULID or `idem_<timestamp>_<resource_id>`."},"notes":{"type":"string","example":"Bill shows $0 but my paper bill says $84.32. Acct ending 1234.","description":"Free-text notes. PII-safe storage required; never echoed in metrics."}},"required":["resource_type","resource_id","signal","idempotency_key"]},"GenericFeedbackResponseDto":{"type":"object","properties":{"resource_type":{"type":"string","example":"bill"},"resource_id":{"type":"string","example":"bill_abc123"},"agent_type":{"type":"string","example":"recording_agent"},"signal":{"type":"string","example":"wrong_amount"},"attributable":{"type":"boolean","example":true,"description":"True when the feedback was attributed to a known agent run (run_id present + trace exists). False when the producing run is unknown / aged-out — the feedback is still recorded as observed/unattributable (D11 soft-accept) and returned with 202."},"run_id":{"type":"string","example":"run_abc123","description":"The agent run id the feedback was attributed to. Omitted when attributable=false."},"already_existed":{"type":"boolean","example":false,"description":"True when this exact submission was already recorded (idempotent replay)."}},"required":["resource_type","resource_id","agent_type","signal","attributable","already_existed"]},"ReviewSupportVerdictDto":{"type":"object","properties":{}},"FlipProductionPointerDto":{"type":"object","properties":{"agent_type":{"type":"string","description":"Agent lane whose production pointer moves."},"new_version_hash":{"type":"string","description":"Version hash to promote."},"expected_current_hash":{"type":"string","description":"CAS — the hash the operator believes is current. Empty string asserts no pointer exists yet (initial creation), which admin-portal sends literally, so this must accept `\"\"`."}},"required":["agent_type","new_version_hash"]},"RollbackAgentPointerDto":{"type":"object","properties":{"agent_type":{"type":"string","description":"Agent lane whose production pointer rolls back."},"expected_current_hash":{"type":"string","description":"CAS guard — the hash the operator believes is current."},"note":{"type":"string","description":"Operator note. admin-portal sends `\"\"` when the field is blank."}},"required":["agent_type","expected_current_hash"]},"FreezeAgentDto":{"type":"object","properties":{"agent_type":{"type":"string","description":"Agent lane being frozen/unfrozen."},"note":{"type":"string","description":"Operator note recorded on the audit row."}},"required":["agent_type"]},"CreateRecordingVersionDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller this recording version belongs to."},"agent_type":{"type":"string","description":"Agent lane (e.g. `recording_agent`)."},"content":{"type":"string","description":"Full recording body being versioned."},"parent_hash":{"type":"string","description":"Hash of the version this one derives from."},"description":{"type":"string","description":"Operator-supplied change note."}},"required":["biller_id","agent_type","content"]},"StartCanaryDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller the canary runs against."},"agent_type":{"type":"string","description":"Agent lane the canary applies to."},"candidate_hash":{"type":"string","description":"Recording/prompt hash being canaried."},"traffic_pct":{"type":"number","description":"Traffic share for the candidate. Defaults to 5."},"observe_window_minutes":{"type":"number","description":"Observation window in minutes. Defaults to 60."},"min_baseline_runs":{"type":"number","description":"Baseline runs required before a decision. Defaults to 20."}},"required":["biller_id","agent_type","candidate_hash"]},"DecideCanaryDto":{"type":"object","properties":{"biller_id":{"type":"string","description":"Biller the canary runs against."},"agent_type":{"type":"string","description":"Agent lane the canary applies to."},"decision":{"type":"string","description":"Operator decision, forwarded verbatim to the service."},"reason":{"type":"string","description":"Why the operator decided this way."}},"required":["biller_id","agent_type","decision"]},"UpsertAgentBrainEntryDto":{"type":"object","properties":{"agent_type":{"type":"string","description":"Agent lane the fact belongs to."},"scope":{"type":"string","description":"Scope kind (e.g. `biller`)."},"scope_key":{"type":"string","description":"Scope key. Controller defaults to \"\"."},"fact_type":{"type":"string","description":"Fact classifier (e.g. `pre_login_modal`)."},"fact_payload":{"type":"string","description":"Serialized fact body."},"evidence_run_id":{"type":"string","description":"Run that evidences the fact. Both controllers default to \"\"."}},"required":["agent_type","scope","fact_type","fact_payload"]},"CreateBrainNoteDto":{"type":"object","properties":{}},"BrainEntryKeyDto":{"type":"object","properties":{}},"CreatePromptExperimentDto":{"type":"object","properties":{"agent_type":{"type":"string","description":"Agent lane the experiment runs on (one active per lane)."},"variant_hash":{"type":"string","description":"Registered PromptVersion hash for the variant arm."},"traffic_pct":{"type":"number","description":"Variant traffic share. Controller enforces integer in [1, 100]."},"salt_version":{"type":"string","description":"Bucketing salt version."},"control_hash":{"type":"string","description":"Registered PromptVersion hash for the control arm."}},"required":["agent_type","variant_hash","traffic_pct"]},"RecordPromptEvalScoreDto":{"type":"object","properties":{"agent_type":{"type":"string"},"version_hash":{"type":"string"},"score":{"type":"number"},"fixture_count":{"type":"number"},"pass_count":{"type":"number","description":"Controller defaults to 0."},"exact_match_rate":{"type":"number","description":"Controller defaults to 0."},"evaluated_by":{"type":"string","description":"Controller defaults to `cli:eval-prompt`."},"evaluated_at":{"type":"string","description":"ISO-8601 evaluation timestamp."}},"required":["agent_type","version_hash","score","fixture_count"]},"AttentionSummaryResponseDto":{"type":"object","properties":{"generated_at":{"type":"string","description":"ISO timestamp the summary was computed at"},"unhealthy_script_billers":{"type":"number","nullable":true,"description":"Billers with at least one unhealthy recorded script (red / breakage)"},"manual_capture_billers":{"type":"number","nullable":true,"description":"Billers in the manual-capture lane (amber / review-pending)"},"dead_letter_count":{"type":"number","nullable":true,"description":"Webhook dead letters in status DEAD (red / breakage)"},"pending_human_note_hints":{"type":"number","nullable":true,"description":"Pending human_note brain drafts awaiting admin approval (amber / review-pending)"},"open_human_tasks":{"type":"number","nullable":true,"description":"Open tasks in the HUMAN executor lane (neutral / queue depth)"},"support_verdicts_pending_review":{"type":"number","nullable":true,"example":3}},"required":["generated_at","unhealthy_script_billers","manual_capture_billers","dead_letter_count","pending_human_note_hints","open_human_tasks","support_verdicts_pending_review"]},"AnomalyCardDto":{"type":"object","properties":{"id":{"type":"string","description":"Stable card id: `${rule_id}:${entity}`"},"rule_id":{"type":"string","description":"Rule that produced the card","enum":["unhealthy_scripts","manual_capture","webhook_dead_letters","task_sla_breach","no_recent_bills","cost_spike"]},"severity":{"type":"string","description":"Card severity","enum":["error","warning","info"]},"title":{"type":"string","description":"The anomaly (e.g. \"Eversource: 0 new bills in 7d\")"},"cause":{"type":"string","description":"Attributed cause (e.g. \"RETRIEVE_BILL script unhealthy\")"},"link_href":{"type":"string","description":"Deep link to the admin screen that fixes it"},"link_label":{"type":"string","description":"Link button label"},"entity_id":{"type":"string","nullable":true,"description":"Primary entity id (null for fleet-wide cards)"},"observed_at":{"type":"string","nullable":true,"description":"ISO timestamp anchoring \"since when\""}},"required":["id","rule_id","severity","title","cause","link_href","link_label","entity_id","observed_at"]},"StubbedRuleDto":{"type":"object","properties":{"rule_id":{"type":"string","description":"Registry rule id awaiting an upstream unit"},"marker":{"type":"string","description":"Why it is stubbed (e.g. \"post-A12\")"}},"required":["rule_id","marker"]},"AnomalyFeedResponseDto":{"type":"object","properties":{"generated_at":{"type":"string","description":"ISO timestamp the feed was computed at (60s cache)"},"cards":{"description":"Attention cards sorted by severity (error → warning → info)","type":"array","items":{"$ref":"#/components/schemas/AnomalyCardDto"}},"sources_unavailable":{"description":"Source slots whose fetch failed this round (their rules were skipped)","type":"array","items":{"type":"string"}},"stubbed_rules":{"description":"Registry rules waiting on an upstream unit (e.g. cost_spike → post-A12)","type":"array","items":{"$ref":"#/components/schemas/StubbedRuleDto"}},"all_clear":{"type":"boolean","description":"True when there are no cards and every source was reachable"}},"required":["generated_at","cards","sources_unavailable","stubbed_rules","all_clear"]},"VerifyOpsStepUpPasswordDto":{"type":"object","properties":{"password":{"type":"string","description":"The ops password being re-verified."},"action_id":{"type":"string","description":"Action the step-up token authorizes. Controller regex-checks the format."},"resource_id":{"type":"string","description":"Resource the step-up token is scoped to."},"environment":{"type":"string","description":"Deployment environment the caller believes it is in. The controller 403s on a mismatch with `STEP_UP_ENVIRONMENT_MISMATCH`."}},"required":["password"]},"CreateDurableRecordingTaskDto":{"type":"object","properties":{}},"RecordingRetryReleaseDto":{"type":"object","properties":{}},"PayBillRecordingClaimDto":{"type":"object","properties":{}},"PayBillRecordingTerminalDto":{"type":"object","properties":{}},"RecordingContinuationMutationDto":{"type":"object","properties":{}},"SaveLoginScriptDto":{"type":"object","properties":{}},"SaveAccountDiscoveryScriptDto":{"type":"object","properties":{}},"SaveRetrieveBillScriptDto":{"type":"object","properties":{}},"SaveRetrieveObservedPaymentScriptDto":{"type":"object","properties":{}},"SavePayBillScriptDto":{"type":"object","properties":{}},"ReportDrillFailureDto":{"type":"object","properties":{}},"ParkAwaitingCredentialsDto":{"type":"object","properties":{}},"ReportSelfHealEventDto":{"type":"object","properties":{}},"RecordRouteOutcomeDto":{"type":"object","properties":{}},"ClaimCapabilityProbeDto":{"type":"object","properties":{}},"ClaimCapabilityExecutionDto":{"type":"object","properties":{}},"RecordProviderSignalsDto":{"type":"object","properties":{}},"RecordVerifyOutcomeDto":{"type":"object","properties":{}},"RecordingArtifactAddressDto":{"type":"object","properties":{"biller_id":{"type":"string"},"script_type":{"type":"string","enum":["LOGIN","ACCOUNT_DISCOVERY","RETRIEVE_BILL","RETRIEVE_OBSERVED_PAYMENT","PAY_BILL"]},"artifact_version":{"type":"number"},"artifact_digest":{"type":"string"}},"required":["biller_id","script_type","artifact_version","artifact_digest"]},"ClaimRecordingVerificationDto":{"type":"object","properties":{"task_id":{"type":"string"},"artifact":{"$ref":"#/components/schemas/RecordingArtifactAddressDto"},"generation":{"type":"number"},"lease_id":{"type":"string","description":"Durable verification lease id."},"lease_owner":{"type":"string","description":"Runner instance holding the lease."},"lease_ms":{"type":"number","description":"Requested lease duration in ms."}},"required":["task_id","artifact","generation","lease_id","lease_owner"]},"GetRecordingVerificationArtifactDto":{"type":"object","properties":{"task_id":{"type":"string"},"artifact":{"$ref":"#/components/schemas/RecordingArtifactAddressDto"}},"required":["task_id","artifact"]},"RecordingVerificationEvidenceDto":{"type":"object","properties":{"replay_id":{"type":"string"},"fresh_session":{"type":"boolean"},"artifact_digest":{"type":"string"},"started_at":{"type":"string"},"completed_at":{"type":"string"},"final_url":{"type":"string"},"final_origin":{"type":"string"},"navigation_steps_replayed":{"type":"number"},"selectors_asserted":{"type":"array","items":{"type":"string"}},"success_assertions":{"type":"array","items":{"type":"string"}},"popup_observed":{"type":"boolean"},"metadata":{"type":"object","description":"Free-form replay metadata. Keys are runner-chosen, so this stays an open map."}},"required":["replay_id","fresh_session","artifact_digest","started_at","completed_at","navigation_steps_replayed","selectors_asserted","success_assertions"]},"CompleteRecordingVerificationDto":{"type":"object","properties":{"task_id":{"type":"string"},"artifact":{"$ref":"#/components/schemas/RecordingArtifactAddressDto"},"generation":{"type":"number"},"lease_id":{"type":"string","description":"Durable verification lease id."},"outcome_id":{"type":"string","description":"Idempotency key for this verification outcome."},"state":{"type":"string","enum":["PASSED","FAILED","HUMAN_REVIEW"]},"evidence":{"$ref":"#/components/schemas/RecordingVerificationEvidenceDto"},"failure_code":{"type":"string","enum":["VERIFICATION_DISPATCH_FAILED","VERIFICATION_PERSISTENCE_FAILED","VERIFICATION_REPLAY_TIMEOUT","VERIFICATION_REPLAY_FAILED","VERIFICATION_ARTIFACT_STALE","VERIFICATION_EVIDENCE_INVALID","VERIFICATION_POPUP_REQUIRES_HUMAN_REVIEW","VERIFICATION_UNSUPPORTED_FLOW"]},"failure_reason":{"type":"string","description":"Human-readable failure detail."},"completed_at":{"type":"string","description":"ISO-8601 completion timestamp."}},"required":["task_id","artifact","generation","lease_id","outcome_id","state","evidence","completed_at"]},"SubmitDocsFeedbackDto":{"type":"object","properties":{}},"MintTicketDto":{"type":"object","properties":{}},"BillerMessageReadResponseDto":{"type":"object","properties":{"id":{"type":"string"},"read_at":{"type":"string"}},"required":["id","read_at"]},"BillerMessageReportResponseDto":{"type":"object","properties":{"message_id":{"type":"string"},"recorded_at":{"type":"string"}},"required":["message_id","recorded_at"]},"BillerMessageResourceDto":{"type":"object","properties":{"id":{"type":"string"},"client_user_id":{"type":"string"},"biller_id":{"type":"string"},"biller_name":{"type":"string"},"account_link_id":{"type":"string"},"account_id":{"type":"string"},"category":{"type":"string","enum":["marketing","account_update"]},"subject":{"type":"string"},"body":{"type":"string"},"created_at":{"type":"string"},"received_at":{"type":"string"},"read_at":{"type":"string"},"reported_at":{"type":"string"},"consent_basis":{"type":"string","description":"Consent source recorded when the message was accepted."},"delivery_status":{"type":"string"}},"required":["id","client_user_id","biller_id","biller_name","account_link_id","category","subject","body","created_at","received_at","consent_basis","delivery_status"]},"BillerMessagesPageDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BillerMessageResourceDto"}},"next_cursor":{"type":"string"}},"required":["data"]},"DecideElementsEmbedApprovalDto":{"type":"object","properties":{"decision":{"type":"string","enum":["APPROVE","DENY","REVOKE"]},"reason":{"type":"string","maxLength":500},"expected_version":{"type":"number","minimum":0}},"required":["decision","reason","expected_version"]},"ReportBillerMessageDto":{"type":"object","properties":{"reason":{"type":"string","enum":["spam","misleading","never_signed_up","other"]},"note":{"type":"string","maxLength":280}},"required":["reason"]},"RequestElementsEmbedApprovalDto":{"type":"object","properties":{}},"SendBillerPortalMessageDto":{"type":"object","properties":{}}}},"externalDocs":{"description":"Developer Portal","url":"https://docs.billerapi.com"}}