{"openapi":"3.1.0","info":{"title":"OpenGiving API","version":"0.1.0"},"paths":{"/health":{"get":{"summary":"Health Check","description":"Whether the API is up, and how each part it leans on is.\n\nOpen to anyone, so it says \"ok\" or \"down\" per part and nothing else. It\nused to send the cache's hit counts and, when Redis failed, the\nexception's text. That goes to the log now.\n\nAlways a 200 while the API answers. The Dockerfile's HEALTHCHECK is\n`curl -f`, which fails on anything else, and Redis is optional (the app\nstarts and serves without it), so a Redis outage is \"degraded\", not down.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}}}}},"/admin/cache/metrics":{"get":{"summary":"Get Cache Metrics","description":"Get cache performance metrics","operationId":"get_cache_metrics_admin_cache_metrics_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/cache/health":{"get":{"summary":"Get Cache Health","description":"Get detailed cache health information","operationId":"get_cache_health_admin_cache_health_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/me":{"get":{"tags":["users"],"summary":"Read Current User","description":"Return the authenticated user, provisioning their account on first login.\n\nDeclared before /{id_user} so \"me\" is not parsed as a UUID. Hitting this with\na Supabase bearer token creates the app user row if it doesn't exist yet\n(see core.security create-on-first-login).","operationId":"read_current_user_api_v1_users_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/{id_user}":{"get":{"tags":["users"],"summary":"Read User","description":"Returns the public profile of the user with a given id (contact PII stripped).","operationId":"read_user_api_v1_users__id_user__get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["users"],"summary":"Delete User","description":"Deletes a user. Admin-only.\n\nUsers delete their own account through POST /users/me/deletion-request,\nwhich holds the deletion for review — an organizer who has raised money\nshould not be able to erase the trail on their own say-so. Letting them\ncall this directly would be a one-line bypass of that review.\n\nRuns the same anonymising wipe as an approved request rather than the bare\nsoft delete this used to do. The old path left the dead row holding the\naccount's unique email, phone_number and supabase_id, which made the next\nsign-in unable to either match the row or insert a new one — the account\nbecame permanently unusable instead of deleted.","operationId":"delete_user_api_v1_users__id_user__delete","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/":{"get":{"tags":["users"],"summary":"Read Users","description":"Returns a list of all users (public profiles, contact PII stripped). Authenticated callers only.","operationId":"read_users_api_v1_users__get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserPublic"},"title":"Response Read Users Api V1 Users  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["users"],"summary":"Update User","description":"Updates the information of a user. Users can only update their own record (admins may update anyone).\n\nWrites the profile fields: name, picture, location, bio, language. Not\n`email` or `phone_number`. The email follows the verified sign-in\nidentity, so a new address is changed and confirmed there; nothing edits\nthe phone. Sending either back as stored, or leaving it out, is fine. A\ndifferent value is a 400 that reads the same whether or not another\naccount holds it.","operationId":"update_user_api_v1_users__patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Input"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/me/preferred-locale":{"patch":{"tags":["users"],"summary":"Update Preferred Locale","description":"Set only the caller's language preference.\n\nExists so clients never do a read-modify-write of the whole user for one\nfield; the schema enforces the platform's locale allow-list.","operationId":"update_preferred_locale_api_v1_users_me_preferred_locale_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferredLocaleUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/me/name":{"patch":{"tags":["users"],"summary":"Update My Name","description":"Set the caller's own first and last name.\n\nThe one thing a person provisioned as \"User\" could not do: some identity\nproviders send no name (Sign in with Apple sends it once, to the app, and\nnever again), and until now nothing let them type it. Clients show a\nprompt while `needs_name` is true and keep this reachable from settings.","operationId":"update_my_name_api_v1_users_me_name_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NameUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/{user_id}/location":{"patch":{"tags":["users"],"summary":"Update User Location","description":"Update user's preferred location. Users can only update their own location.","operationId":"update_user_location_api_v1_users__user_id__location_patch","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLocationUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/{id_user}/restore":{"post":{"tags":["users"],"summary":"Restore User","description":"Restores a deleted user. Admin-only endpoint.","operationId":"restore_user_api_v1_users__id_user__restore_post","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/{id_user}/verification":{"patch":{"tags":["users"],"summary":"Update User Verification","description":"Updates the verification status of a user. Admin-only endpoint.","operationId":"update_user_verification_api_v1_users__id_user__verification_patch","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserVerificationUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/":{"options":{"tags":["campaigns"],"summary":"Options Campaigns","operationId":"options_campaigns_api_v1_campaigns__options","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}}}},"get":{"tags":["campaigns"],"summary":"Read Campaigns","description":"Get all campaigns with category details.\n\nThis is the unfiltered list: the Campaigns tab and the home page's featured\nrail both arrive here. Someone who has just opened the app has asked for\nnothing in particular, which is when \"causes near you\" is the most useful\nthing an ordering can mean -- so it ranks by distance when it can place the\ncaller, and exactly as it always did when it cannot.","operationId":"read_campaigns_api_v1_campaigns__get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"created_at, goal, raised, or distance. Omitted means 'no preference', which lets the endpoint rank near the caller when it can place them.","title":"Sort By"},"description":"created_at, goal, raised, or distance. Omitted means 'no preference', which lets the endpoint rank near the caller when it can place them."},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","description":"Sort order: asc, desc","default":"desc","title":"Sort Order"},"description":"Sort order: asc, desc"},{"name":"near_latitude","in":"query","required":false,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Caller's latitude, for sort_by=distance","title":"Near Latitude"},"description":"Caller's latitude, for sort_by=distance"},{"name":"near_longitude","in":"query","required":false,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Caller's longitude, for sort_by=distance","title":"Near Longitude"},"description":"Caller's longitude, for sort_by=distance"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/CampaignWithDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_CampaignWithDetails_"}],"title":"Response Read Campaigns Api V1 Campaigns  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["campaigns"],"summary":"Create Campaign","description":"Create campaign. The organizer is always the authenticated caller.","operationId":"create_campaign_api_v1_campaigns__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["campaigns"],"summary":"Update Campaign","description":"Updates the information of a campaign. Only campaign organizers (or admins on mirror campaigns) can update.","operationId":"update_campaign_api_v1_campaigns__patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/search":{"get":{"tags":["campaigns"],"summary":"Search Campaigns","description":"Search campaigns with category details. Supports multiple category IDs.\n\nFuzzy search (enabled by default) allows for typo-tolerant searches.\nFor example, searching \"campain\" will match campaigns with \"campaign\" in the title.\nSet fuzzy=false to use exact substring matching only.\n\nSorting options:\n- sort_by: created_at (default), goal, raised\n- sort_order: desc (default), asc","operationId":"search_campaigns_api_v1_campaigns_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","minLength":1,"title":"Q"}},{"name":"category_id","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","format":"uuid"},"title":"Category Id"}},{"name":"location","in":"query","required":false,"schema":{"type":"string","title":"Location"}},{"name":"near_latitude","in":"query","required":false,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Caller's latitude, for sort_by=distance","title":"Near Latitude"},"description":"Caller's latitude, for sort_by=distance"},{"name":"near_longitude","in":"query","required":false,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Caller's longitude, for sort_by=distance","title":"Near Longitude"},"description":"Caller's longitude, for sort_by=distance"},{"name":"min_goal","in":"query","required":false,"schema":{"type":"number","minimum":0,"title":"Min Goal"}},{"name":"max_goal","in":"query","required":false,"schema":{"type":"number","minimum":0,"title":"Max Goal"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","title":"Status"}},{"name":"just_started","in":"query","required":false,"schema":{"type":"boolean","title":"Just Started"}},{"name":"urgent_needs","in":"query","required":false,"schema":{"type":"boolean","title":"Urgent Needs"}},{"name":"almost_funded","in":"query","required":false,"schema":{"type":"boolean","title":"Almost Funded"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Field to sort by: created_at, goal, raised, distance","title":"Sort By"},"description":"Field to sort by: created_at, goal, raised, distance"},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","description":"Sort order: asc, desc","default":"desc","title":"Sort Order"},"description":"Sort order: asc, desc"},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","description":"Enable fuzzy/typo-tolerant search (default: true)","default":true,"title":"Fuzzy"},"description":"Enable fuzzy/typo-tolerant search (default: true)"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/CampaignWithDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_CampaignWithDetails_"}],"title":"Response Search Campaigns Api V1 Campaigns Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/my-campaigns":{"get":{"tags":["campaigns"],"summary":"Get My Campaigns","description":"Get current user's campaigns with details.","operationId":"get_my_campaigns_api_v1_campaigns_my_campaigns_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/CampaignWithDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_CampaignWithDetails_"}],"title":"Response Get My Campaigns Api V1 Campaigns My Campaigns Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/my-campaigns/search":{"get":{"tags":["campaigns"],"summary":"Search My Campaigns","description":"Search current user's campaigns with fuzzy matching.\n\nSearches across campaign title, description, and location.\nSupports typo-tolerant fuzzy search (e.g., \"campain\" matches \"campaign\").","operationId":"search_my_campaigns_api_v1_campaigns_my_campaigns_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Search query","title":"Q"},"description":"Search query"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status (active, paused, completed, cancelled)","title":"Status"},"description":"Filter by status (active, paused, completed, cancelled)"},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","description":"Enable fuzzy/typo-tolerant search (default: true)","default":true,"title":"Fuzzy"},"description":"Enable fuzzy/typo-tolerant search (default: true)"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_CampaignWithDetails_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/stats":{"get":{"tags":["campaigns"],"summary":"Read Campaign Stats","description":"Platform-wide campaign totals.\n\nReplaces the clients' fetch-every-campaign-and-add loop, which asks for\n`?limit={total}` against a route capped at 100.","operationId":"read_campaign_stats_api_v1_campaigns_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignStats"}}}}}}},"/api/v1/campaigns/{id_campaign}":{"get":{"tags":["campaigns"],"summary":"Read Campaign","description":"Get campaign by ID.","operationId":"read_campaign_api_v1_campaigns__id_campaign__get","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["campaigns"],"summary":"Delete Campaign","description":"Deletes a campaign. Only campaign organizers (or admins on mirror campaigns) can delete.","operationId":"delete_campaign_api_v1_campaigns__id_campaign__delete","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/donors":{"get":{"tags":["campaigns"],"summary":"Read Campaign Donors","description":"The people who put money into a campaign: its donations and its sales.\n\n`q`, `type` and `sort` are applied by the database over the whole list.\nThey used to be applied in the browser over whatever had loaded, so a\nsearch for somebody on the third page found nothing.\n\nA bare list by default, which is what all three clients read. `paginate`\nadds the envelope with `meta.total`, for the screen that prints how many\nthere are -- that number was the count of rows loaded so far.","operationId":"read_campaign_donors_api_v1_campaigns__id_campaign__donors_get","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Alias for offset: page N starts at (N-1)*limit.","title":"Page"},"description":"Alias for offset: page N starts at (N-1)*limit."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search the names this list shows.","title":"Q"},"description":"Search the names this list shows."},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Narrow to one kind: direct or purchase. Omit for both.","title":"Type"},"description":"Narrow to one kind: direct or purchase. Omit for both."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","description":"recent or amount.","default":"recent","title":"Sort"},"description":"recent or amount."},{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","description":"Answer with data + meta, so a caller can show a total.","default":false,"title":"Paginate"},"description":"Answer with data + meta, so a caller can show a total."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/Donor"}},{"$ref":"#/components/schemas/PaginatedResponse_Donor_"}],"title":"Response Read Campaign Donors Api V1 Campaigns  Id Campaign  Donors Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/with-organizer":{"get":{"tags":["campaigns"],"summary":"Read Campaign With Organizer","description":"Returns the campaign with organizer details.","operationId":"read_campaign_with_organizer_api_v1_campaigns__id_campaign__with_organizer_get","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignWithOrganizer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/with-details":{"get":{"tags":["campaigns"],"summary":"Read Campaign With Details","description":"Get campaign with category and organizer details.","operationId":"read_campaign_with_details_api_v1_campaigns__id_campaign__with_details_get","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/status/{status_campaign}":{"get":{"tags":["campaigns"],"summary":"Read Status Campaigns","description":"Returns a list of all campaigns registered in OpenGiving with a given status.","operationId":"read_status_campaigns_api_v1_campaigns_status__status_campaign__get","parameters":[{"name":"status_campaign","in":"path","required":true,"schema":{"type":"string","title":"Status Campaign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"},"title":"Response Read Status Campaigns Api V1 Campaigns Status  Status Campaign  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/user/{id_user}":{"get":{"tags":["campaigns"],"summary":"Read Campaigns User","description":"Returns a list of all campaigns registered for a given user.","operationId":"read_campaigns_user_api_v1_campaigns_user__id_user__get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"},"title":"Response Read Campaigns User Api V1 Campaigns User  Id User  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/user/{id_user}/with-details":{"get":{"tags":["campaigns"],"summary":"Read Campaigns User With Details","description":"Returns a list of all campaigns registered for a given user with category and image details.","operationId":"read_campaigns_user_with_details_api_v1_campaigns_user__id_user__with_details_get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CampaignWithDetails"},"title":"Response Read Campaigns User With Details Api V1 Campaigns User  Id User  With Details Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/owner/{id_user}":{"put":{"tags":["campaigns"],"summary":"Update Campaign Owner","description":"Transfers ownership of a campaign. Only the current organizer (or an admin on mirror campaigns) can transfer.","operationId":"update_campaign_owner_api_v1_campaigns__id_campaign__owner__id_user__put","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/status/{status_campaign}":{"put":{"tags":["campaigns"],"summary":"Update Campaign Status","description":"Updates the status of a campaign. Only campaign organizers can update status.","operationId":"update_campaign_status_api_v1_campaigns__id_campaign__status__status_campaign__put","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"status_campaign","in":"path","required":true,"schema":{"type":"string","title":"Status Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/deactivation-impact":{"get":{"tags":["campaigns"],"summary":"Get Campaign Deactivation Impact","description":"Get impact summary of what will happen if campaign is deactivated.","operationId":"get_campaign_deactivation_impact_api_v1_campaigns__id_campaign__deactivation_impact_get","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeactivationImpactSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/deactivate":{"post":{"tags":["campaigns"],"summary":"Deactivate Campaign","description":"Deactivate/cancel a campaign. Only campaign organizers can deactivate their campaigns.\nThis action will:\n- Change campaign status to 'cancelled'\n- Optionally notify all donors\n- Handle refunds based on the specified policy\n- Update linked marketplace products","operationId":"deactivate_campaign_api_v1_campaigns__id_campaign__deactivate_post","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignDeactivationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignDeactivationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/restore":{"post":{"tags":["campaigns"],"summary":"Restore Campaign","description":"Restore a soft-deleted campaign. Admin-only endpoint.","operationId":"restore_campaign_api_v1_campaigns__id_campaign__restore_post","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/reactivate":{"post":{"tags":["campaigns"],"summary":"Reactivate Campaign","description":"Reactivate a deactivated campaign. Only campaign organizers can reactivate their campaigns.","operationId":"reactivate_campaign_api_v1_campaigns__id_campaign__reactivate_post","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{id_campaign}/test-creation-notification":{"post":{"tags":["campaigns"],"summary":"Test Campaign Creation Notification","description":"Test endpoint to trigger campaign creation notification (DEV ONLY)","operationId":"test_campaign_creation_notification_api_v1_campaigns__id_campaign__test_creation_notification_post","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignNotificationTest"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/gofundme":{"post":{"tags":["campaign-import"],"summary":"Preview Gofundme Import","description":"Preview GoFundMe campaign data for import.\n\nScrapes the provided GoFundMe URL and returns extracted campaign data\nfor user review before creating the campaign.\n\nRequires authentication.\n\nArgs:\n    request: GoFundMeImportRequest containing the GoFundMe campaign URL\n    current_user: Authenticated user from JWT token\n    db: Database connection\n\nReturns:\n    GoFundMeImportPreview with scraped campaign data, suggested category,\n    confidence score, and any warnings\n\nRaises:\n    HTTPException 400: If URL is invalid or campaign not found\n    HTTPException 401: If user is not authenticated\n    HTTPException 500: If scraping fails","operationId":"preview_gofundme_import_api_v1_campaigns_import_gofundme_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeImportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeImportPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/gofundme/preview":{"post":{"tags":["campaign-import"],"summary":"Preview Gofundme Import Public","description":"Preview GoFundMe campaign data for import (public, no auth required).\n\nScrapes the provided GoFundMe URL and returns extracted campaign data\nfor user review before migrating the campaign.\n\nThis endpoint is used by new users who don't have an account yet.\n\nArgs:\n    request: GoFundMeImportRequest containing the GoFundMe campaign URL\n    db: Database connection\n\nReturns:\n    GoFundMeImportPreview with scraped campaign data, suggested category,\n    confidence score, and any warnings\n\nRaises:\n    HTTPException 400: If URL is invalid or campaign not found\n    HTTPException 500: If scraping fails","operationId":"preview_gofundme_import_public_api_v1_campaigns_import_gofundme_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeImportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeImportPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/gofundme/migrate":{"post":{"tags":["campaign-import"],"summary":"Migrate Gofundme Campaign","description":"Migrate a GoFundMe campaign to OpenGiving with user consent.\n\nThis endpoint handles the complete migration flow:\n1. Resolves the organizer from the authenticated session\n2. Creates the campaign with the provided data\n3. Sends a welcome/notification email\n\nRequires authentication. The campaign is created under the signed-in user's\naccount, so the importer is always the owner — we never infer an identity\nfrom the scraped page or from a body-supplied email address.\n\nArgs:\n    request: Migration request with campaign data, email, and consent\n\nReturns:\n    GoFundMeMigrationResponse with campaign and user details\n\nRaises:\n    HTTPException 400: If validation fails or consent not given\n    HTTPException 500: If migration fails","operationId":"migrate_gofundme_campaign_api_v1_campaigns_import_gofundme_migrate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeMigrationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeMigrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/gofundme/admin-migrate":{"post":{"tags":["campaign-import"],"summary":"Admin Migrate Gofundme Campaign","description":"Admin endpoint to migrate a GoFundMe campaign (with optional email).\n\nThis endpoint handles admin-managed migrations:\n1. If email is provided: Creates user account (if needed) and assigns campaign\n2. If no email: Creates a \"mirror\" campaign owned by the admin\n\nMirror campaigns display the original organizer's name from GoFundMe\nbut are managed by the admin until claimed by the actual organizer.\n\nRequires admin authentication.\n\nArgs:\n    request: Admin migration request with campaign data and optional email\n    current_user: Authenticated admin user\n\nReturns:\n    AdminMirrorMigrationResponse with campaign details\n\nRaises:\n    HTTPException 401: If user is not an admin\n    HTTPException 400: If validation fails\n    HTTPException 500: If migration fails","operationId":"admin_migrate_gofundme_campaign_api_v1_campaigns_import_gofundme_admin_migrate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminMirrorMigrationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminMirrorMigrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/gofundme/refresh/{campaign_id}":{"post":{"tags":["campaign-import"],"summary":"Refresh Gofundme Data","description":"Refresh/update GoFundMe data for an existing campaign.\n\nThis endpoint allows campaign owners and admins to:\n1. Add GoFundMe tracking data to campaigns that were manually created\n2. Refresh the raised amount for campaigns that were previously imported\n3. Update the source_url if it wasn't set\n\nCampaign owners can link their own campaigns to GoFundMe.\nAdmins can link any campaign (including mirror campaigns).\n\nArgs:\n    campaign_id: The campaign ID to update\n    request: Contains the GoFundMe URL to scrape\n    current_user: Authenticated user (owner or admin)\n\nReturns:\n    GoFundMeRefreshResponse with updated data\n\nRaises:\n    HTTPException 403: If user is not authorized to modify this campaign\n    HTTPException 404: If campaign not found\n    HTTPException 400: If URL is invalid\n    HTTPException 500: If scraping fails","operationId":"refresh_gofundme_data_api_v1_campaigns_import_gofundme_refresh__campaign_id__post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeRefreshRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoFundMeRefreshResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/givengain":{"post":{"tags":["campaign-import"],"summary":"Preview Givengain Import","description":"Preview GivenGain campaign data for import.\n\nScrapes the provided GivenGain URL and returns extracted campaign data\nfor user review before creating the campaign.\n\nRequires authentication.\n\nArgs:\n    request: GivenGainImportRequest containing the GivenGain campaign URL\n    current_user: Authenticated user from JWT token\n    db: Database connection\n\nReturns:\n    GivenGainImportPreview with scraped campaign data, suggested category,\n    confidence score, and any warnings\n\nRaises:\n    HTTPException 400: If URL is invalid or campaign not found\n    HTTPException 401: If user is not authenticated\n    HTTPException 500: If scraping fails","operationId":"preview_givengain_import_api_v1_campaigns_import_givengain_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainImportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainImportPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/givengain/preview":{"post":{"tags":["campaign-import"],"summary":"Preview Givengain Import Public","description":"Preview GivenGain campaign data for import (public, no auth required).\n\nScrapes the provided GivenGain URL and returns extracted campaign data\nfor user review before migrating the campaign.\n\nThis endpoint is used by new users who don't have an account yet.\n\nArgs:\n    request: GivenGainImportRequest containing the GivenGain campaign URL\n    db: Database connection\n\nReturns:\n    GivenGainImportPreview with scraped campaign data, suggested category,\n    confidence score, and any warnings\n\nRaises:\n    HTTPException 400: If URL is invalid or campaign not found\n    HTTPException 500: If scraping fails","operationId":"preview_givengain_import_public_api_v1_campaigns_import_givengain_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainImportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainImportPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/givengain/migrate":{"post":{"tags":["campaign-import"],"summary":"Migrate Givengain Campaign","description":"Migrate a GivenGain campaign to OpenGiving with user consent.\n\nThis endpoint handles the complete migration flow:\n1. Resolves the organizer from the authenticated session\n2. Creates the campaign with the provided data\n3. Sends a welcome/notification email\n\nRequires authentication. The campaign is created under the signed-in user's\naccount, so the importer is always the owner — we never infer an identity\nfrom the scraped page or from a body-supplied email address.\n\nArgs:\n    request: Migration request with campaign data, email, and consent\n\nReturns:\n    GivenGainMigrationResponse with campaign and user details\n\nRaises:\n    HTTPException 400: If validation fails or consent not given\n    HTTPException 500: If migration fails","operationId":"migrate_givengain_campaign_api_v1_campaigns_import_givengain_migrate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainMigrationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainMigrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/givengain/admin-migrate":{"post":{"tags":["campaign-import"],"summary":"Admin Migrate Givengain Campaign","description":"Admin endpoint to migrate a GivenGain campaign (with optional email).\n\nThis endpoint handles admin-managed migrations:\n1. If email is provided: Creates user account (if needed) and assigns campaign\n2. If no email: Creates a \"mirror\" campaign owned by the admin\n\nMirror campaigns display the original organizer's name from GivenGain\nbut are managed by the admin until claimed by the actual organizer.\n\nRequires admin authentication.\n\nArgs:\n    request: Admin migration request with campaign data and optional email\n    current_user: Authenticated admin user\n\nReturns:\n    AdminGivenGainMigrationResponse with campaign details\n\nRaises:\n    HTTPException 401: If user is not an admin\n    HTTPException 400: If validation fails\n    HTTPException 500: If migration fails","operationId":"admin_migrate_givengain_campaign_api_v1_campaigns_import_givengain_admin_migrate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGivenGainMigrationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGivenGainMigrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/import/givengain/refresh/{campaign_id}":{"post":{"tags":["campaign-import"],"summary":"Refresh Givengain Data","description":"Refresh/update GivenGain data for an existing campaign.\n\nThis endpoint allows campaign owners and admins to:\n1. Add GivenGain tracking data to campaigns that were manually created\n2. Refresh the raised amount for campaigns that were previously imported\n3. Update the source_url if it wasn't set\n\nCampaign owners can link their own campaigns to GivenGain.\nAdmins can link any campaign (including mirror campaigns).\n\nArgs:\n    campaign_id: The campaign ID to update\n    request: Contains the GivenGain URL to scrape\n    current_user: Authenticated user (owner or admin)\n\nReturns:\n    GivenGainRefreshResponse with updated data\n\nRaises:\n    HTTPException 403: If user is not authorized to modify this campaign\n    HTTPException 404: If campaign not found\n    HTTPException 400: If URL is invalid\n    HTTPException 500: If scraping fails","operationId":"refresh_givengain_data_api_v1_campaigns_import_givengain_refresh__campaign_id__post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainRefreshRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivenGainRefreshResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{campaign_id}/claim-token":{"post":{"tags":["campaign-claims"],"summary":"Generate Claim Token","description":"Generate a claim token for a mirror campaign (Admin only).\nThis creates a unique link that can be shared with the original organizer.","operationId":"generate_claim_token_api_v1_campaigns__campaign_id__claim_token_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimTokenCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimTokenCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["campaign-claims"],"summary":"Get Campaign Claim Token","description":"Get the active claim token for a campaign (Admin only).\nReturns None if no active token exists.","operationId":"get_campaign_claim_token_api_v1_campaigns__campaign_id__claim_token_get","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ClaimTokenWithCampaign"},{"type":"null"}],"title":"Response Get Campaign Claim Token Api V1 Campaigns  Campaign Id  Claim Token Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/claim-tokens/{token_id}/resend":{"post":{"tags":["campaign-claims"],"summary":"Resend Claim Email","description":"Email a pending claim link again (Admin only).\n\nFor a link whose email never arrived. The token stays the same, so a\nlink the organizer already has keeps working; generating a new one would\nrevoke it. The address is named in the request, because the token never\nstored the one first typed. Answers whether the email went, the same way\ncreating the token does.","operationId":"resend_claim_email_api_v1_campaigns_claim_tokens__token_id__resend_post","parameters":[{"name":"token_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Token Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimEmailResend"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimEmailResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{campaign_id}/claim-token/{token_id}":{"delete":{"tags":["campaign-claims"],"summary":"Revoke Claim Token","description":"Revoke a claim token (Admin only).","operationId":"revoke_claim_token_api_v1_campaigns__campaign_id__claim_token__token_id__delete","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"token_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Token Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/claim/{token}":{"get":{"tags":["campaign-claims"],"summary":"Get Claim Info","description":"Get public information about a claim token (Public endpoint).\nUsed to display the claim page to the user.","operationId":"get_claim_info_api_v1_campaigns_claim__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimPublicInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/claim/{token}/initiate":{"post":{"tags":["campaign-claims"],"summary":"Initiate Claim","description":"Initiate a claim by providing claimant information (Public endpoint).\nThis records the claim attempt and triggers verification.","operationId":"initiate_claim_api_v1_campaigns_claim__token__initiate_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimInitiateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimInitiateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/claim/{token}/complete":{"post":{"tags":["campaign-claims"],"summary":"Complete Claim","description":"Complete the claim and transfer ownership (Authenticated endpoint).\nThe user must be signed in to complete the claim.","operationId":"complete_claim_api_v1_campaigns_claim__token__complete_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimCompleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/claim-tokens/{token_id}/transfer-funds":{"post":{"tags":["campaign-claims"],"summary":"Transfer Claimed Campaign Funds","description":"Move a claimed campaign's money to its claimant, by hand (Admin only).\n\nFor campaigns claimed before transfers existed, or when the automatic\ntransfer at claim time failed. Dry run by default: it reports what would\nmove and writes nothing. `from_user_id` names the previous organizer when\nthe token cannot say (it records only who claimed); it defaults to the\nplatform account that owns migrated campaigns.","operationId":"transfer_claimed_campaign_funds_api_v1_campaigns_claim_tokens__token_id__transfer_funds_post","parameters":[{"name":"token_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Token Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}},{"name":"from_user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"From User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimFundsTransferResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/price-stats":{"get":{"tags":["products"],"summary":"Get Price Stats","description":"Get price statistics for active products.\n\nReturns min/max prices and a histogram of price distribution (20 buckets).\nUses efficient SQL aggregate functions - single query, no pagination needed.\n\nThis endpoint is optimized for the price range slider with histogram visualization.","operationId":"get_price_stats_api_v1_products_price_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductPriceStats"}}}}}}},"/api/v1/products/search":{"get":{"tags":["products"],"summary":"Search Products","description":"Search products with campaign and category details.\n\nFuzzy search (enabled by default) allows for typo-tolerant searches.\nFor example, searching \"coffe maker\" will match \"coffee maker\".\nSet fuzzy=false to use exact substring matching only.\n\nHierarchical category support:\n- include_subcategories: When true (default), selecting a parent category\n  will also include products from all its subcategories.\n\nCampaign category filter:\n- campaign_category_id: Filter products by what type of campaign/cause\n  they support (e.g., Education, Health, Environment).\n\nDonation percentage filter:\n- min_donation_percent/max_donation_percent: Filter by how much of the\n  sale price goes to the campaign (0-100%).\n\nSorting options:\n- sort_by: created_at (default), price\n- sort_order: desc (default), asc","operationId":"search_products_api_v1_products_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","minLength":1,"title":"Q"}},{"name":"category_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","format":"uuid"},"title":"Category Ids"}},{"name":"include_subcategories","in":"query","required":false,"schema":{"type":"boolean","description":"When filtering by category, include products in subcategories (default: true)","default":true,"title":"Include Subcategories"},"description":"When filtering by category, include products in subcategories (default: true)"},{"name":"campaign_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"campaign_category_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Filter products by the campaign's category (cause type)","title":"Campaign Category Id"},"description":"Filter products by the campaign's category (cause type)"},{"name":"location","in":"query","required":false,"schema":{"type":"string","title":"Location"}},{"name":"min_price","in":"query","required":false,"schema":{"type":"number","minimum":0,"title":"Min Price"}},{"name":"max_price","in":"query","required":false,"schema":{"type":"number","minimum":0,"title":"Max Price"}},{"name":"min_donation_percent","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":0,"description":"Minimum donation percentage (0-100)","title":"Min Donation Percent"},"description":"Minimum donation percentage (0-100)"},{"name":"max_donation_percent","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":0,"description":"Maximum donation percentage (0-100)","title":"Max Donation Percent"},"description":"Maximum donation percentage (0-100)"},{"name":"condition","in":"query","required":false,"schema":{"type":"string","title":"Condition"}},{"name":"product_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(physical|digital|service)$","description":"Filter by product kind","title":"Product Type"},"description":"Filter by product kind"},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Field to sort by: created_at, price, distance. Omitted means 'no preference', which lets the endpoint rank near the caller when it can place them.","title":"Sort By"},"description":"Field to sort by: created_at, price, distance. Omitted means 'no preference', which lets the endpoint rank near the caller when it can place them."},{"name":"near_latitude","in":"query","required":false,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Caller's latitude, for sort_by=distance","title":"Near Latitude"},"description":"Caller's latitude, for sort_by=distance"},{"name":"near_longitude","in":"query","required":false,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Caller's longitude, for sort_by=distance","title":"Near Longitude"},"description":"Caller's longitude, for sort_by=distance"},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","description":"Sort order: asc, desc","default":"desc","title":"Sort Order"},"description":"Sort order: asc, desc"},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","description":"Enable fuzzy/typo-tolerant search (default: true)","default":true,"title":"Fuzzy"},"description":"Enable fuzzy/typo-tolerant search (default: true)"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_ProductWithCampaignDetails_"}],"title":"Response Search Products Api V1 Products Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/my-products/search":{"get":{"tags":["products"],"summary":"Search My Products","description":"Search user's own products (items) with fuzzy matching.\n\nSearches across: title, description, campaign title.\nFuzzy search is enabled by default for typo tolerance.","operationId":"search_my_products_api_v1_products_my_products_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Search query","title":"Q"},"description":"Search query"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status (active, sold, inactive)","title":"Status"},"description":"Filter by status (active, sold, inactive)"},{"name":"condition","in":"query","required":false,"schema":{"type":"string","description":"Filter by condition","title":"Condition"},"description":"Filter by condition"},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","description":"Enable fuzzy/typo-tolerant search","default":true,"title":"Fuzzy"},"description":"Enable fuzzy/typo-tolerant search"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ProductWithCampaignDetails_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/my-products":{"get":{"tags":["products"],"summary":"Get My Products","description":"Get current user's products with campaign details.\n\nArgs:\n    page: Page number for pagination\n    limit: Number of items per page\n    status: Optional status filter (active, inactive, sold)","operationId":"get_my_products_api_v1_products_my_products_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status (active, inactive, sold)","title":"Status"},"description":"Filter by status (active, inactive, sold)"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_ProductWithCampaignDetails_"}],"title":"Response Get My Products Api V1 Products My Products Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/with-campaign-details":{"get":{"tags":["products"],"summary":"Read Products With Campaign Details","description":"Get all products with campaign and category details.","operationId":"read_products_with_campaign_details_api_v1_products_with_campaign_details_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_ProductWithCampaignDetails_"}],"title":"Response Read Products With Campaign Details Api V1 Products With Campaign Details Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}":{"get":{"tags":["products"],"summary":"Read Product","description":"Get product by ID.","operationId":"read_product_api_v1_products__id_product__get","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["products"],"summary":"Delete Product","description":"Deletes a product. Only the seller (or an admin) can delete.","operationId":"delete_product_api_v1_products__id_product__delete","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/with-campaign-details":{"get":{"tags":["products"],"summary":"Read Product With Campaign Details","description":"Get product with category and campaign details.\n\nDEPRECATED: Use /products/{id}/with-details instead for consistency with campaigns.\nThis endpoint will be removed in a future version.","operationId":"read_product_with_campaign_details_api_v1_products__id_product__with_campaign_details_get","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductWithCampaignDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/with-details":{"get":{"tags":["products"],"summary":"Read Product With Details","description":"Get product with category, campaign, and image details (consistent naming with campaigns).","operationId":"read_product_with_details_api_v1_products__id_product__with_details_get","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductWithCampaignDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/":{"get":{"tags":["products"],"summary":"Read Products","description":"Get all products with campaign, category, and image details.\n\nThis is the endpoint an unfiltered browse hits -- iOS falls back to it when\nno filter is set, and it is the only list route the Android client binds. It\nhad no ordering controls at all, so \"nearest first\" was unreachable from the\nscreen most likely to want it, however well /products/search ranked.","operationId":"read_products_api_v1_products__get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"title":"Limit"}},{"name":"product_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(physical|digital|service)$","title":"Product Type"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Field to sort by: created_at, price, distance. Omitted means 'no preference', which lets the endpoint rank near the caller when it can place them.","title":"Sort By"},"description":"Field to sort by: created_at, price, distance. Omitted means 'no preference', which lets the endpoint rank near the caller when it can place them."},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","description":"Sort order: asc, desc","default":"desc","title":"Sort Order"},"description":"Sort order: asc, desc"},{"name":"near_latitude","in":"query","required":false,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Caller's latitude, for sort_by=distance","title":"Near Latitude"},"description":"Caller's latitude, for sort_by=distance"},{"name":"near_longitude","in":"query","required":false,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Caller's longitude, for sort_by=distance","title":"Near Longitude"},"description":"Caller's longitude, for sort_by=distance"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"}},{"$ref":"#/components/schemas/PaginatedResponse_ProductWithCampaignDetails_"}],"title":"Response Read Products Api V1 Products  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["products"],"summary":"Create Product","description":"Create product. Seller is always the authenticated caller.","operationId":"create_product_api_v1_products__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["products"],"summary":"Update Product","description":"Updates the information of a product. Only the seller (or an admin) can update.","operationId":"update_product_api_v1_products__patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/status/{status_product}":{"get":{"tags":["products"],"summary":"Read Status Products","description":"Returns a list of all products registered in OpenGiving with a given status.","operationId":"read_status_products_api_v1_products_status__status_product__get","parameters":[{"name":"status_product","in":"path","required":true,"schema":{"type":"string","title":"Status Product"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Product"},"title":"Response Read Status Products Api V1 Products Status  Status Product  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/user/{id_user}":{"get":{"tags":["products"],"summary":"Read Products User","description":"Returns a list of all products registered for a given user.","operationId":"read_products_user_api_v1_products_user__id_user__get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Product"},"title":"Response Read Products User Api V1 Products User  Id User  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/user/{id_user}/with-details":{"get":{"tags":["products"],"summary":"Read Products User With Details","description":"Returns a list of all products registered for a given user with campaign and category details.","operationId":"read_products_user_with_details_api_v1_products_user__id_user__with_details_get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"},"title":"Response Read Products User With Details Api V1 Products User  Id User  With Details Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/campaign/{id_campaign}":{"get":{"tags":["products"],"summary":"Read Products Campaign","description":"Returns a list of all products registered for a given campaign with campaign and category details.","operationId":"read_products_campaign_api_v1_products_campaign__id_campaign__get","parameters":[{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"},"title":"Response Read Products Campaign Api V1 Products Campaign  Id Campaign  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/user/{id_user}/campaign/{id_campaign}":{"get":{"tags":["products"],"summary":"Read Products User Campaign","description":"Returns a list of all products registered for a given user and campaign.","operationId":"read_products_user_campaign_api_v1_products_user__id_user__campaign__id_campaign__get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}},{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Product"},"title":"Response Read Products User Campaign Api V1 Products User  Id User  Campaign  Id Campaign  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/user/{id_user}/campaign/{id_campaign}/status/{status_product}":{"get":{"tags":["products"],"summary":"Read Products User Campaign Status","description":"Returns a list of all products registered for a given user and campaign with a given status.","operationId":"read_products_user_campaign_status_api_v1_products_user__id_user__campaign__id_campaign__status__status_product__get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}},{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"status_product","in":"path","required":true,"schema":{"type":"string","title":"Status Product"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Product"},"title":"Response Read Products User Campaign Status Api V1 Products User  Id User  Campaign  Id Campaign  Status  Status Product  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/campaign/{id_campaign}":{"put":{"tags":["products"],"summary":"Update Product Campaign","description":"Updates the campaign a product supports. Only the seller (or an admin) can update.","operationId":"update_product_campaign_api_v1_products__id_product__campaign__id_campaign__put","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"id_campaign","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Campaign"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/donation_pct/{donation_pct}":{"put":{"tags":["products"],"summary":"Update Product Donation Pct","description":"Updates the donation percentage of a product. Only the seller (or an admin) can update.","operationId":"update_product_donation_pct_api_v1_products__id_product__donation_pct__donation_pct__put","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"donation_pct","in":"path","required":true,"schema":{"type":"integer","title":"Donation Pct"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/price/{price}":{"put":{"tags":["products"],"summary":"Update Product Price","description":"Updates the price of a product. Only the seller (or an admin) can update.\n\nThe floor is enforced here as well as on the create schema. This route takes\nthe price as a path parameter, so it never passed through ProductBase at\nall: a seller could list at the minimum and then edit the price to a cent,\nwhich made the create-time floor advisory rather than a rule.","operationId":"update_product_price_api_v1_products__id_product__price__price__put","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"price","in":"path","required":true,"schema":{"type":"number","title":"Price"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/status/{status_product}":{"put":{"tags":["products"],"summary":"Update Product Status","description":"Updates the status of a product. Only the seller (or an admin) can update.","operationId":"update_product_status_api_v1_products__id_product__status__status_product__put","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"status_product","in":"path","required":true,"schema":{"type":"string","title":"Status Product"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/deactivation-impact":{"get":{"tags":["products"],"summary":"Get Product Deactivation Impact","description":"Get impact summary of what will happen if product is deactivated.","operationId":"get_product_deactivation_impact_api_v1_products__id_product__deactivation_impact_get","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductDeactivationImpactSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/deactivate":{"post":{"tags":["products"],"summary":"Deactivate Product","description":"Deactivate/cancel a product listing. Only product sellers can deactivate their products.\nThis action will:\n- Change product status to 'inactive'\n- Optionally notify all buyers with pending transactions\n- Handle refunds based on the specified policy\n- Cancel pending transactions","operationId":"deactivate_product_api_v1_products__id_product__deactivate_post","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductDeactivationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductDeactivationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/reactivate":{"post":{"tags":["products"],"summary":"Reactivate Product","description":"Reactivate a deactivated product listing. Only product sellers can reactivate their products.\nThis action will change product status from 'inactive' back to 'active'.","operationId":"reactivate_product_api_v1_products__id_product__reactivate_post","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{id_product}/restore":{"post":{"tags":["products"],"summary":"Restore Product","description":"Restores a deleted product. Admin-only endpoint.","operationId":"restore_product_api_v1_products__id_product__restore_post","parameters":[{"name":"id_product","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Product"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{product_id}/digital-assets/presign":{"post":{"tags":["digital"],"summary":"Presign Digital Asset Upload","description":"Start a file upload for a digital product (seller only).","operationId":"presign_digital_asset_upload_api_v1_products__product_id__digital_assets_presign_post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigitalAssetPresignRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigitalAssetPresignResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{product_id}/digital-assets/{asset_id}/confirm":{"post":{"tags":["digital"],"summary":"Confirm Digital Asset Upload","description":"Activate an uploaded file after verifying it landed in S3 (seller only).","operationId":"confirm_digital_asset_upload_api_v1_products__product_id__digital_assets__asset_id__confirm_post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigitalAsset"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{product_id}/digital-assets":{"get":{"tags":["digital"],"summary":"List Digital Assets","description":"List a digital product's files (metadata only — names and sizes).","operationId":"list_digital_assets_api_v1_products__product_id__digital_assets_get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DigitalAsset"},"title":"Response List Digital Assets Api V1 Products  Product Id  Digital Assets Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{product_id}/digital-assets/{asset_id}":{"delete":{"tags":["digital"],"summary":"Remove Digital Asset","description":"Deactivate a file (seller only). Existing buyers keep their entitlements.","operationId":"remove_digital_asset_api_v1_products__product_id__digital_assets__asset_id__delete","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigitalAsset"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/products/{product_id}/offers":{"post":{"tags":["offers"],"summary":"Make An Offer","description":"Propose a price for a listing.\n\nThe listing is loaded with its campaign because that is what decides\nwhether it can be sold at all (services/campaign_listings.py).","operationId":"make_an_offer_api_v1_products__product_id__offers_post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Offer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["offers"],"summary":"Offers On A Listing","description":"The seller's inbox for one listing.\n\nThe seller's only: every offer on a listing is a price somebody else was\nwilling to pay, and showing that to other buyers would tell them what to\nbid. A buyer reads their own through GET /offers.","operationId":"offers_on_a_listing_api_v1_products__product_id__offers_get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/search":{"get":{"tags":["transactions"],"summary":"Search My Purchases","description":"Search purchases (transactions) with fuzzy matching.\n\nSearches across: product title, campaign title, seller name, transaction ID.\nFuzzy search is enabled by default for typo tolerance.","operationId":"search_my_purchases_api_v1_transactions_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Search query","title":"Q"},"description":"Search query"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Page Size"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"description":"Alias for page_size, for clients that speak limit.","title":"Limit"},"description":"Alias for page_size, for clients that speak limit."},{"name":"status_filter","in":"query","required":false,"schema":{"type":"string","description":"Filter by status: all, active, awaiting_shipping, shipped, delivered, cancelled_failed, refunded","title":"Status Filter"},"description":"Filter by status: all, active, awaiting_shipping, shipped, delivered, cancelled_failed, refunded"},{"name":"status_group","in":"query","required":false,"schema":{"type":"string","description":"Filter by status group: active, completed","title":"Status Group"},"description":"Filter by status group: active, completed"},{"name":"payment_status","in":"query","required":false,"schema":{"type":"string","description":"Filter by payment status","title":"Payment Status"},"description":"Filter by payment status"},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","description":"Enable fuzzy/typo-tolerant search","default":true,"title":"Fuzzy"},"description":"Enable fuzzy/typo-tolerant search"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_TransactionWithDetails_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/":{"get":{"tags":["transactions"],"summary":"Get Transactions","description":"Get paginated transactions for current user with details","operationId":"get_transactions_api_v1_transactions__get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Page Size"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"description":"Alias for page_size, for clients that speak limit.","title":"Limit"},"description":"Alias for page_size, for clients that speak limit."},{"name":"status_filter","in":"query","required":false,"schema":{"type":"string","description":"Filter by status: all, active, awaiting_shipping, shipped, delivered, cancelled_failed, refunded","title":"Status Filter"},"description":"Filter by status: all, active, awaiting_shipping, shipped, delivered, cancelled_failed, refunded"},{"name":"status_group","in":"query","required":false,"schema":{"type":"string","description":"Filter by status group: active, completed","title":"Status Group"},"description":"Filter by status group: active, completed"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_TransactionWithDetails_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["transactions"],"summary":"Create Transaction","description":"Create a new transaction","operationId":"create_transaction_api_v1_transactions__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transaction"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}":{"get":{"tags":["transactions"],"summary":"Get Transaction By Id","description":"Get a single transaction by id for buyer or seller.","operationId":"get_transaction_by_id_api_v1_transactions__id_transaction__get","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/seller/current":{"get":{"tags":["transactions"],"summary":"Get Seller Transactions","description":"Get transactions for current user as seller","operationId":"get_seller_transactions_api_v1_transactions_seller_current_get","parameters":[{"name":"delivery_status","in":"query","required":false,"schema":{"type":"string","title":"Delivery Status"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TransactionWithDetails"},"title":"Response Get Seller Transactions Api V1 Transactions Seller Current Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/sync-status":{"post":{"tags":["transactions"],"summary":"Sync Transaction Status","description":"Sync a purchase's payment status with Stripe, for the buyer.\n\nMoves an open payment forward only; a paid or refunded one is answered as\nstored. A purchase with no Stripe intent (PayPal, or unpaid) and one\nStripe can't be asked about answer the stored status too.\n\nWhen Stripe says the payment succeeded, this settles it through\nsettle_payment, the same call the webhook makes. iOS and Android call\nthis the moment the payment sheet closes, which is when Stripe sends the\nwebhook, so the two race on every card purchase; whichever gets there\nfirst settles it, and the other changes nothing.","operationId":"sync_transaction_status_api_v1_transactions__id_transaction__sync_status_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionSyncStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/product/{product_id}":{"get":{"tags":["transactions"],"summary":"Get Transactions By Product","description":"Get transactions for a specific product (seller only)","operationId":"get_transactions_by_product_api_v1_transactions_product__product_id__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TransactionWithDetails"},"title":"Response Get Transactions By Product Api V1 Transactions Product  Product Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/payment-status":{"get":{"tags":["transactions"],"summary":"Get Payment Status","description":"A purchase's payment status, for its buyer or seller: what Stripe\nsays about its intent, else what is stored.","operationId":"get_payment_status_api_v1_transactions__id_transaction__payment_status_get","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredPaymentStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/mark-shipped":{"post":{"tags":["transactions"],"summary":"Mark Transaction As Shipped","description":"Mark a transaction as shipped, or ready for pickup (seller only).\n\nSent again once the order is on its way, it fixes the tracking number\nand notes and leaves the rest alone; see services/order_handover.py.\nOf two sent together, one ships the order and tells the buyer; the other\nfinds it shipped and fixes the tracking.","operationId":"mark_transaction_as_shipped_api_v1_transactions__id_transaction__mark_shipped_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/mark-delivered":{"post":{"tags":["transactions"],"summary":"Mark Transaction As Delivered","description":"Mark a transaction as delivered, or picked up (seller only).\n\nThat doesn't complete the sale: the buyer's delivery code does. Of two\nsent together, one delivers the order and tells the buyer; the other is\nrefused as already delivered, as a second tap is.","operationId":"mark_transaction_as_delivered_api_v1_transactions__id_transaction__mark_delivered_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/generate-delivery-code":{"post":{"tags":["transactions"],"summary":"Generate Delivery Code","description":"Generate a delivery confirmation code (buyer only)","operationId":"generate_delivery_code_api_v1_transactions__id_transaction__generate_delivery_code_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryCodeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/regenerate-delivery-code":{"post":{"tags":["transactions"],"summary":"Regenerate Delivery Code","description":"Regenerate a delivery confirmation code (buyer only)","operationId":"regenerate_delivery_code_api_v1_transactions__id_transaction__regenerate_delivery_code_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryCodeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/delivery-code":{"get":{"tags":["transactions"],"summary":"Get Delivery Code Info","description":"Get delivery code information (buyer or seller)","operationId":"get_delivery_code_info_api_v1_transactions__id_transaction__delivery_code_get","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryCodeInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/confirm-delivery":{"post":{"tags":["transactions"],"summary":"Confirm Delivery Received","description":"Verify delivery confirmation code (seller only).\n\n`escrow_released` used to be a constant True. Confirming releases\nnothing: escrow is released 7 days later (services/escrow_release.py),\nor by the seller or an admin, so the key now says what the transaction\nsays. No client reads its value; iOS decodes it as a required Bool, so it\nstays and stays a boolean.","operationId":"confirm_delivery_received_api_v1_transactions__id_transaction__confirm_delivery_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"code","in":"query","required":true,"schema":{"type":"string","description":"4-digit delivery confirmation code","title":"Code"},"description":"4-digit delivery confirmation code"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryConfirmation"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{id_transaction}/receipt":{"get":{"tags":["transactions"],"summary":"Download Transaction Receipt","description":"Download a PDF receipt for a transaction (buyer only)","operationId":"download_transaction_receipt_api_v1_transactions__id_transaction__receipt_get","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"The receipt, as a PDF","content":{"application/pdf":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{transaction_id}/digital-entitlements":{"get":{"tags":["digital"],"summary":"List Digital Entitlements","description":"The buyer's download entitlements for a purchase.","operationId":"list_digital_entitlements_api_v1_transactions__transaction_id__digital_entitlements_get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DigitalEntitlement"},"title":"Response List Digital Entitlements Api V1 Transactions  Transaction Id  Digital Entitlements Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transactions/{transaction_id}/download":{"get":{"tags":["digital"],"summary":"Download Digital Purchase","description":"Short-lived download link for an entitled buyer. When the purchase has a\nsingle file, asset_id may be omitted.","operationId":"download_digital_purchase_api_v1_transactions__transaction_id__download_get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"asset_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigitalDownloadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/mine":{"get":{"tags":["service-orders"],"summary":"My Service Orders","description":"The caller's service orders, as buyer (purchases) or seller (gigs).","operationId":"my_service_orders_api_v1_service_orders_mine_get","parameters":[{"name":"role","in":"query","required":false,"schema":{"type":"string","pattern":"^(buyer|seller)$","default":"buyer","title":"Role"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceOrderWithContext"},"title":"Response My Service Orders Api V1 Service Orders Mine Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/admin/disputes":{"get":{"tags":["service-orders"],"summary":"List Disputes","description":"All disputed service orders (admin), newest dispute first.","operationId":"list_disputes_api_v1_service_orders_admin_disputes_get","parameters":[{"name":"include_resolved","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Resolved"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminDisputeItem"},"title":"Response List Disputes Api V1 Service Orders Admin Disputes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}/resolve":{"post":{"tags":["service-orders"],"summary":"Resolve Dispute","description":"Admin settles a dispute. 'release' force-accepts the order: the\ntransaction flips to 'confirmed' and the sale is released to the seller\nthere and then. 'refund' refunds the buyer through the EXISTING refunds\nflow (admin-approved, processed via Stripe) and records the decision —\nno new money code.","operationId":"resolve_dispute_api_v1_service_orders__transaction_id__resolve_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisputeResolveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrder"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}":{"get":{"tags":["service-orders"],"summary":"Get Service Order","operationId":"get_service_order_api_v1_service_orders__transaction_id__get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrderWithContext"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}/brief":{"patch":{"tags":["service-orders"],"summary":"Update Brief","description":"Buyer describes (or refines) what they need — before delivery.","operationId":"update_brief_api_v1_service_orders__transaction_id__brief_patch","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBriefUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrder"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}/start":{"post":{"tags":["service-orders"],"summary":"Start Order","description":"Seller starts working the order.","operationId":"start_order_api_v1_service_orders__transaction_id__start_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrder"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}/deliver":{"post":{"tags":["service-orders"],"summary":"Deliver Order","description":"Seller marks the work delivered; the buyer's acceptance window starts.","operationId":"deliver_order_api_v1_service_orders__transaction_id__deliver_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceDeliverRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrder"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}/accept":{"post":{"tags":["service-orders"],"summary":"Accept Order","description":"Buyer accepts the delivered work. The transaction flips to 'confirmed'\nand the sale is released to the seller there and then.","operationId":"accept_order_api_v1_service_orders__transaction_id__accept_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrder"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/service-orders/{transaction_id}/dispute":{"post":{"tags":["service-orders"],"summary":"Dispute Order","description":"Buyer disputes the delivered work; surfaces in the admin/refund tooling.","operationId":"dispute_order_api_v1_service_orders__transaction_id__dispute_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceDisputeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrder"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/offers":{"get":{"tags":["offers"],"summary":"My Offers","description":"The caller's own offers, on whichever side of them they stand.","operationId":"my_offers_api_v1_offers_get","parameters":[{"name":"role","in":"query","required":false,"schema":{"type":"string","pattern":"^(buyer|seller)$","description":"Offers this user made, or offers made to them","default":"buyer","title":"Role"},"description":"Offers this user made, or offers made to them"},{"name":"live_only","in":"query","required":false,"schema":{"type":"boolean","description":"Only offers a sale can still come of","default":false,"title":"Live Only"},"description":"Only offers a sale can still come of"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/offers/{offer_id}":{"get":{"tags":["offers"],"summary":"Read An Offer","operationId":"read_an_offer_api_v1_offers__offer_id__get","parameters":[{"name":"offer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Offer Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferWithContext"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/offers/{offer_id}/accept":{"post":{"tags":["offers"],"summary":"Accept An Offer","description":"Take the price.\n\nThis agrees a price, not a sale. The listing stays on sale to everyone\nelse until somebody pays for it, and the accepted offer carries a clock\nof its own.","operationId":"accept_an_offer_api_v1_offers__offer_id__accept_post","parameters":[{"name":"offer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Offer Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Offer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/offers/{offer_id}/decline":{"post":{"tags":["offers"],"summary":"Decline An Offer","operationId":"decline_an_offer_api_v1_offers__offer_id__decline_post","parameters":[{"name":"offer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Offer Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Offer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/offers/{offer_id}/withdraw":{"post":{"tags":["offers"],"summary":"Withdraw An Offer","description":"Take back an offer you made. Only the side that proposed it can.","operationId":"withdraw_an_offer_api_v1_offers__offer_id__withdraw_post","parameters":[{"name":"offer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Offer Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Offer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/offers/{offer_id}/counter":{"post":{"tags":["offers"],"summary":"Counter An Offer","description":"Answer with a different price.\n\n201: the answer is a new offer, and it is the one the other side now has\nto deal with. The offer it answers becomes `countered`.","operationId":"counter_an_offer_api_v1_offers__offer_id__counter_post","parameters":[{"name":"offer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Offer Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferCounter"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Offer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/":{"get":{"tags":["direct_contributions"],"summary":"Get Direct Contributions","description":"Get paginated direct contributions for current user","operationId":"get_direct_contributions_api_v1_direct_contributions__get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Page Size"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"description":"Alias for page_size, for clients that speak limit.","title":"Limit"},"description":"Alias for page_size, for clients that speak limit."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_DirectContribution_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["direct_contributions"],"summary":"Create Direct Contribution","description":"Create a new direct contribution","operationId":"create_direct_contribution_api_v1_direct_contributions__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectContributionCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectContribution"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/my-donations/search":{"get":{"tags":["direct_contributions"],"summary":"Search My Donations","description":"Search donations with fuzzy matching.\n\nSearches across: campaign title, donation message, donation ID.\nFuzzy search is enabled by default for typo tolerance.","operationId":"search_my_donations_api_v1_direct_contributions_my_donations_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Search query","title":"Q"},"description":"Search query"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Page Size"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"description":"Alias for page_size, for clients that speak limit.","title":"Limit"},"description":"Alias for page_size, for clients that speak limit."},{"name":"payment_status","in":"query","required":false,"schema":{"type":"string","description":"Filter by payment status","title":"Payment Status"},"description":"Filter by payment status"},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","description":"Enable fuzzy/typo-tolerant search","default":true,"title":"Fuzzy"},"description":"Enable fuzzy/typo-tolerant search"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_MyDonation_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/my-donations":{"get":{"tags":["direct_contributions"],"summary":"Get My Donations","description":"Get paginated donations made by current user","operationId":"get_my_donations_api_v1_direct_contributions_my_donations_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Page Size"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"description":"Alias for page_size, for clients that speak limit.","title":"Limit"},"description":"Alias for page_size, for clients that speak limit."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_MyDonation_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/{id_contribution}/payment-status":{"get":{"tags":["direct_contributions"],"summary":"Get Payment Status","description":"A donation's payment status, for its donor: what Stripe says about its\nintent, else what is stored.","operationId":"get_payment_status_api_v1_direct_contributions__id_contribution__payment_status_get","parameters":[{"name":"id_contribution","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Contribution"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredPaymentStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/{id_contribution}/sync-status":{"post":{"tags":["direct_contributions"],"summary":"Sync Contribution Status","description":"Sync a donation's payment status with Stripe, for its donor.\n\nMoves an open payment forward only; a paid or refunded one is answered as\nstored. A donation with no Stripe intent (PayPal, or unpaid) and one\nStripe can't be asked about answer the stored status too.\n\nWhen Stripe says the payment succeeded, this settles it through\nsettle_payment, the same call the webhook makes, so the organizer is\ncredited once whichever of the two gets there first. It used to settle the\ndonation itself: it credited the organizer with the card fee taken out\n(the payer covers that fee), left paid_at and the rail unset, skipped the\ndonor's profile, and then the webhook found the donation completed and\nskipped the rest. Run at the same moment as the webhook, it credited the\norganizer twice.","operationId":"sync_contribution_status_api_v1_direct_contributions__id_contribution__sync_status_post","parameters":[{"name":"id_contribution","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Contribution"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContributionSyncStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/recalculate-campaign/{campaign_id}":{"post":{"tags":["direct_contributions"],"summary":"Recalculate Campaign Raised","description":"Recalculate campaign raised amount from all completed contributions","operationId":"recalculate_campaign_raised_api_v1_direct_contributions_recalculate_campaign__campaign_id__post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignRaisedRecalculation"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/{id_contribution}/receipt":{"get":{"tags":["direct_contributions"],"summary":"Download Donation Receipt","description":"Download a PDF receipt for a direct donation (donor only)","operationId":"download_donation_receipt_api_v1_direct_contributions__id_contribution__receipt_get","parameters":[{"name":"id_contribution","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Contribution"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"The receipt, as a PDF","content":{"application/pdf":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/direct_contributions/purchase-donation/{transaction_id}/receipt":{"get":{"tags":["direct_contributions"],"summary":"Download Purchase Donation Receipt","description":"Download a PDF receipt for a purchase donation (buyer only)","operationId":"download_purchase_donation_receipt_api_v1_direct_contributions_purchase_donation__transaction_id__receipt_get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"The receipt, as a PDF","content":{"application/pdf":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/paypal/available":{"get":{"tags":["paypal"],"summary":"Paypal Available","description":"Lets the client decide whether to offer PayPal, and hands it the client id.\n\nThe client id is public by design — it goes in the PayPal SDK URL. Serving it\nfrom here rather than a separate frontend env var means the browser always\nloads the SDK for whichever environment the backend is actually using, so\nflipping PAYPAL_ENV to live cannot leave the two out of step.","operationId":"paypal_available_api_v1_paypal_available_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayPalAvailability"}}}}}}},"/api/v1/paypal/create-order":{"post":{"tags":["paypal"],"summary":"Create Order","description":"Open a PayPal order for one of the caller's own pending contributions.","operationId":"create_order_api_v1_paypal_create_order_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/paypal/marketplace-order":{"post":{"tags":["paypal"],"summary":"Create Marketplace Order","description":"Open a PayPal order for one of the caller's own pending transactions.\n\nThe amount comes from the transaction row, never from the client.","operationId":"create_marketplace_order_api_v1_paypal_marketplace_order_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/paypal/cart-order":{"post":{"tags":["paypal"],"summary":"Create Cart Order","description":"Validate the cart, open its checkout session, and open a PayPal order\nfor the session total. Session prep is shared with the Stripe endpoint,\nso both rails price a cart identically.","operationId":"create_cart_order_api_v1_paypal_cart_order_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CartOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CartOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/paypal/capture-order":{"post":{"tags":["paypal"],"summary":"Capture Order","description":"Capture an approved order, then fulfill whatever the order paid for.\n\nRouting is by the intent row's payment_type: direct_contribution,\nmarketplace_transaction, or cart_checkout. All three share the same\nserver-side amount verification before anything is credited.","operationId":"capture_order_api_v1_paypal_capture_order_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/paypal/webhook":{"post":{"tags":["paypal"],"summary":"Paypal Webhook","description":"Receive PayPal events, verified against PayPal's signature API.\n\nThe synchronous capture endpoint is still the happy path; this exists so\nthat state PayPal knows about always reaches us — a capture whose client\nvanished, a refund issued from the PayPal dashboard.","operationId":"paypal_webhook_api_v1_paypal_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayPalWebhookReceipt"}}}}}}},"/api/v1/giving_profiles/directory":{"get":{"tags":["giving_profiles"],"summary":"Giving Profile Directory","description":"Public directory of GivingProfiles, most impact first.\n\nContact PII never appears here: the user half of each entry is the\nUserPublic shape.","operationId":"giving_profile_directory_api_v1_giving_profiles_directory_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DirectoryEntry"},"title":"Response Giving Profile Directory Api V1 Giving Profiles Directory Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/{id_giving_profile}":{"get":{"tags":["giving_profiles"],"summary":"Read Giving Profile","description":"Get a giving profile by ID.","operationId":"read_giving_profile_api_v1_giving_profiles__id_giving_profile__get","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["giving_profiles"],"summary":"Delete Giving Profile","description":"Delete a giving profile. Admin-only (internal stat mutation).","operationId":"delete_giving_profile_api_v1_giving_profiles__id_giving_profile__delete","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/user/{id_user}":{"get":{"tags":["giving_profiles"],"summary":"Get Giving Profile By User","description":"Get a giving profile by user ID.","operationId":"get_giving_profile_by_user_api_v1_giving_profiles_user__id_user__get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/":{"post":{"tags":["giving_profiles"],"summary":"Create Giving Profile","description":"Create a new giving profile.","operationId":"create_giving_profile_api_v1_giving_profiles__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfileCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["giving_profiles"],"summary":"Update Giving Profile","description":"Update a giving profile. Admin-only (internal stat mutation).","operationId":"update_giving_profile_api_v1_giving_profiles__patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/{id_giving_profile}/total-donated":{"put":{"tags":["giving_profiles"],"summary":"Recompute Total Donated","description":"Recompute a profile's total donated from the payments behind it. Admin-only.\n\nThis took an `amount` and added it to the column, which is how one profile\ncame to read $860 against $10 of real contributions and another $25 against\nno payment at all: a stat mutation with no money behind it, indistinguishable\nfrom a real total once written. `total_donated` is derived from\n`money_received` now, so the only sound repair is a recompute — and any\nfigure typed in here would be overwritten by that donor's next payment\nregardless. An `amount` query parameter is still accepted and ignored, so\nexisting callers do not break.","operationId":"recompute_total_donated_api_v1_giving_profiles__id_giving_profile__total_donated_put","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/{id_giving_profile}/campaigns-supported":{"put":{"tags":["giving_profiles"],"summary":"Update Campaigns Supported","description":"Update a giving profile's total campaigns supported. Admin-only (internal stat mutation).","operationId":"update_campaigns_supported_api_v1_giving_profiles__id_giving_profile__campaigns_supported_put","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}},{"name":"count","in":"query","required":true,"schema":{"type":"integer","title":"Count"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/{id_giving_profile}/donation-streak":{"put":{"tags":["giving_profiles"],"summary":"Update Donation Streak","description":"Update a giving profile's donation streak. Admin-only (internal stat mutation).","operationId":"update_donation_streak_api_v1_giving_profiles__id_giving_profile__donation_streak_put","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}},{"name":"streak","in":"query","required":true,"schema":{"type":"integer","title":"Streak"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/{id_giving_profile}/badges":{"put":{"tags":["giving_profiles"],"summary":"Update Badges","description":"Update a giving profile's badges. Admin-only (internal stat mutation).","operationId":"update_badges_api_v1_giving_profiles__id_giving_profile__badges_put","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Badges"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/{id_giving_profile}/restore":{"post":{"tags":["giving_profiles"],"summary":"Restore Giving Profile","description":"Restore a deleted giving profile. Admin-only (internal stat mutation).","operationId":"restore_giving_profile_api_v1_giving_profiles__id_giving_profile__restore_post","parameters":[{"name":"id_giving_profile","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Giving Profile"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/giving_profiles/user/{id_user}/enhanced":{"get":{"tags":["giving_profiles"],"summary":"Get Enhanced Profile","description":"Get an enhanced giving profile with all computed metrics.\nIncludes: impact metrics, items sold, streak stats, and pinned campaigns.","operationId":"get_enhanced_profile_api_v1_giving_profiles_user__id_user__enhanced_get","parameters":[{"name":"id_user","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingProfileEnhanced"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/user/{user_id}":{"get":{"tags":["pinned-campaigns"],"summary":"Get User Pinned Campaigns","description":"Get all pinned campaigns for a user.","operationId":"get_user_pinned_campaigns_api_v1_pinned_campaigns_user__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedCampaignsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/me":{"get":{"tags":["pinned-campaigns"],"summary":"Get My Pinned Campaigns","description":"Get current user's pinned campaigns.","operationId":"get_my_pinned_campaigns_api_v1_pinned_campaigns_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedCampaignsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/":{"post":{"tags":["pinned-campaigns"],"summary":"Pin Campaign","description":"Pin a campaign to your profile.","operationId":"pin_campaign_api_v1_pinned_campaigns__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedCampaignCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedCampaignWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/campaign/{campaign_id}":{"delete":{"tags":["pinned-campaigns"],"summary":"Unpin Campaign By Campaign Id","description":"Unpin a campaign from your profile by campaign ID.","operationId":"unpin_campaign_by_campaign_id_api_v1_pinned_campaigns_campaign__campaign_id__delete","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/{pinned_campaign_id}":{"delete":{"tags":["pinned-campaigns"],"summary":"Unpin Campaign","description":"Unpin a campaign from your profile by pinned campaign ID.","operationId":"unpin_campaign_api_v1_pinned_campaigns__pinned_campaign_id__delete","parameters":[{"name":"pinned_campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pinned Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/reorder":{"patch":{"tags":["pinned-campaigns"],"summary":"Reorder Pinned Campaigns","description":"Reorder pinned campaigns.","operationId":"reorder_pinned_campaigns_api_v1_pinned_campaigns_reorder_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedCampaignReorder"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedCampaignsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/pinned-campaigns/check/{campaign_id}":{"get":{"tags":["pinned-campaigns"],"summary":"Check Campaign Pinned","description":"Check if a campaign is pinned by the current user.","operationId":"check_campaign_pinned_api_v1_pinned_campaigns_check__campaign_id__get","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinCheck"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/definitions":{"get":{"tags":["badges"],"summary":"Get Badge Definitions","description":"Get all badge definitions.\nOptionally filter by category and active status.","operationId":"get_badge_definitions_api_v1_badges_definitions_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by category (milestone, category, streak, special)","title":"Category"},"description":"Filter by category (milestone, category, streak, special)"},{"name":"is_active","in":"query","required":false,"schema":{"type":"boolean","description":"Filter by active status","default":true,"title":"Is Active"},"description":"Filter by active status"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeDefinition"},"title":"Response Get Badge Definitions Api V1 Badges Definitions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/definitions/{badge_id}":{"get":{"tags":["badges"],"summary":"Get Badge Definition","description":"Get a specific badge definition by ID","operationId":"get_badge_definition_api_v1_badges_definitions__badge_id__get","parameters":[{"name":"badge_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Badge Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadgeDefinition"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/check/{user_id}":{"post":{"tags":["badges"],"summary":"Check User Badges","description":"Check all badge eligibility for a user and award any newly earned badges.\nReturns newly earned badges with XP rewards.\n\nThis endpoint should be called after significant user actions:\n- After making a donation\n- After creating a campaign\n- After making a marketplace purchase\n- Daily cron job to check streaks","operationId":"check_user_badges_api_v1_badges_check__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadgeCheckResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/progress/{user_id}":{"get":{"tags":["badges"],"summary":"Get Badge Progress","description":"Get badge progress for a user.\nShows current progress towards earning each badge.\n\nIf badge_id is provided, returns progress for that badge only.\nOtherwise, returns progress for all badges.","operationId":"get_badge_progress_api_v1_badges_progress__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"badge_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Specific badge ID to check progress for","title":"Badge Id"},"description":"Specific badge ID to check progress for"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeProgress"},"title":"Response Get Badge Progress Api V1 Badges Progress  User Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/award/{user_id}/{badge_id}":{"post":{"tags":["badges"],"summary":"Award Badge Manually","description":"Manually award a badge to a user (admin function).\nThis bypasses eligibility checks.","operationId":"award_badge_manually_api_v1_badges_award__user_id___badge_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"badge_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Badge Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/user/{user_id}/earned":{"get":{"tags":["badges"],"summary":"Get User Earned Badges","description":"Get all badges earned by a specific user with full badge definition details.","operationId":"get_user_earned_badges_api_v1_badges_user__user_id__earned_get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeDefinition"},"title":"Response Get User Earned Badges Api V1 Badges User  User Id  Earned Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/badges/categories":{"get":{"tags":["badges"],"summary":"Get Badge Categories","description":"Get list of all unique badge categories","operationId":"get_badge_categories_api_v1_badges_categories_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Response Get Badge Categories Api V1 Badges Categories Get"}}}}}}},"/api/v1/xp/level/{user_id}":{"get":{"tags":["xp"],"summary":"Get User Level Info","description":"Get detailed level information for a user.\nIncludes current level, XP, tier, and progress to next level.","operationId":"get_user_level_info_api_v1_xp_level__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LevelInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/{user_id}":{"post":{"tags":["xp"],"summary":"Award Xp To User","description":"Manually award XP to a user (admin function or system trigger).\nAutomatically handles level-ups.\n\nConstraints:\n- xp_amount must be between 1 and 1000\n- reason is required for tracking","operationId":"award_xp_to_user_api_v1_xp_award__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"xp_amount","in":"query","required":true,"schema":{"type":"integer","maximum":1000,"exclusiveMinimum":0,"description":"Amount of XP to award","title":"Xp Amount"},"description":"Amount of XP to award"},{"name":"reason","in":"query","required":true,"schema":{"type":"string","description":"Reason for awarding XP","title":"Reason"},"description":"Reason for awarding XP"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/donation/{user_id}":{"post":{"tags":["xp"],"summary":"Award Donation Xp","description":"Award XP for a donation.\nAwards 10 XP per $10 donated, capped at 100 XP per donation.\n\nThis endpoint should be called automatically after a successful donation.","operationId":"award_donation_xp_api_v1_xp_award_donation__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"amount","in":"query","required":true,"schema":{"type":"number","exclusiveMinimum":0,"description":"Donation amount in dollars","title":"Amount"},"description":"Donation amount in dollars"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/streak/{user_id}":{"post":{"tags":["xp"],"summary":"Award Streak Xp","description":"Award XP for maintaining daily donation streak.\nAwards 5 XP.\n\nThis endpoint should be called by the daily cron job.","operationId":"award_streak_xp_api_v1_xp_award_streak__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/bio-completion/{user_id}":{"post":{"tags":["xp"],"summary":"Award Bio Completion Xp","description":"Award one-time XP for completing profile bio.\nAwards 25 XP.","operationId":"award_bio_completion_xp_api_v1_xp_award_bio_completion__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/campaign-support/{user_id}":{"post":{"tags":["xp"],"summary":"Award Campaign Support Xp","description":"Award XP for supporting a campaign.\nAwards 15 XP.","operationId":"award_campaign_support_xp_api_v1_xp_award_campaign_support__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/campaign-creation/{user_id}":{"post":{"tags":["xp"],"summary":"Award Campaign Creation Xp","description":"Award XP for creating a campaign.\nAwards 50 XP.","operationId":"award_campaign_creation_xp_api_v1_xp_award_campaign_creation__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/award/marketplace-purchase/{user_id}":{"post":{"tags":["xp"],"summary":"Award Marketplace Purchase Xp","description":"Award XP for making a marketplace purchase.\nAwards 15 XP.","operationId":"award_marketplace_purchase_xp_api_v1_xp_award_marketplace_purchase__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPAwardResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/leaderboard":{"get":{"tags":["xp"],"summary":"Get Level Leaderboard","description":"Get the top users by level and XP.\nReturns a leaderboard sorted by level (descending) and XP (descending).","operationId":"get_level_leaderboard_api_v1_xp_leaderboard_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of top users to return","default":10,"title":"Limit"},"description":"Number of top users to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/schemas__xp__LeaderboardEntry"},"title":"Response Get Level Leaderboard Api V1 Xp Leaderboard Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/calculate/donation":{"get":{"tags":["xp"],"summary":"Calculate Donation Xp","description":"Calculate how much XP would be earned from a donation (preview).\nDoes not actually award the XP.","operationId":"calculate_donation_xp_api_v1_xp_calculate_donation_get","parameters":[{"name":"amount","in":"query","required":true,"schema":{"type":"number","exclusiveMinimum":0,"description":"Donation amount in dollars","title":"Amount"},"description":"Donation amount in dollars"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPCalculation"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/xp/rewards":{"get":{"tags":["xp"],"summary":"Get Xp Rewards","description":"Get the XP reward values for all actions.\nUseful for displaying to users what they can earn.","operationId":"get_xp_rewards_api_v1_xp_rewards_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XPRewards"}}}}}}},"/api/v1/xp/next-level-xp/{level}":{"get":{"tags":["xp"],"summary":"Get Xp For Next Level","description":"Calculate XP required to reach the next level from a given level.","operationId":"get_xp_for_next_level_api_v1_xp_next_level_xp__level__get","parameters":[{"name":"level","in":"path","required":true,"schema":{"type":"integer","maximum":999,"minimum":1,"description":"Current level","title":"Level"},"description":"Current level"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NextLevelXP"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaign_updates/{id_update}":{"get":{"tags":["campaign_updates"],"summary":"Read Update","description":"Get a specific campaign update.","operationId":"read_update_api_v1_campaign_updates__id_update__get","parameters":[{"name":"id_update","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Update"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["campaign_updates"],"summary":"Update Update","description":"Update a campaign update. Only campaign owners can update.","operationId":"update_update_api_v1_campaign_updates__id_update__patch","parameters":[{"name":"id_update","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Update"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["campaign_updates"],"summary":"Delete Update","description":"Delete a campaign update. Only campaign owners can delete.","operationId":"delete_update_api_v1_campaign_updates__id_update__delete","parameters":[{"name":"id_update","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Update"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaign_updates/campaign/{campaign_id}":{"get":{"tags":["campaign_updates"],"summary":"Read Campaign Updates","description":"A campaign's updates, newest first.\n\nThis used to take no arguments and hand back `crud.get_all_by_campaign`'s\nfirst return value, discarding the second. The crud has always paged and has\nalways counted; the route threw both away. So it answered with the first\nfifty updates and nothing to say there were more -- a campaign's fifty-first\nupdate was unreachable, and no caller could tell.\n\nA bare list by default, which is what the campaign page reads. `paginate`\nadds the envelope with `meta.total`, for a screen that prints how many there\nare.","operationId":"read_campaign_updates_api_v1_campaign_updates_campaign__campaign_id__get","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Alias for offset: page N starts at (N-1)*limit.","title":"Page"},"description":"Alias for offset: page N starts at (N-1)*limit."},{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","description":"Answer with data + meta, so a caller can show a total.","default":false,"title":"Paginate"},"description":"Answer with data + meta, so a caller can show a total."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/CampaignUpdate"}},{"$ref":"#/components/schemas/PaginatedResponse_CampaignUpdate_"}],"title":"Response Read Campaign Updates Api V1 Campaign Updates Campaign  Campaign Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaign_updates/":{"post":{"tags":["campaign_updates"],"summary":"Create Update","description":"Create a new campaign update. Only campaign owners can create updates.","operationId":"create_update_api_v1_campaign_updates__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaign_updates/{id_update}/restore":{"post":{"tags":["campaign_updates"],"summary":"Restore Update","description":"Restore a deleted campaign update.","operationId":"restore_update_api_v1_campaign_updates__id_update__restore_post","parameters":[{"name":"id_update","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Update"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/upload/campaign/{campaign_id}":{"post":{"tags":["images"],"summary":"Upload Campaign Image","description":"Upload a campaign image to S3 and return the CloudFront URL.","operationId":"upload_campaign_image_api_v1_images_upload_campaign__campaign_id__post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}},{"name":"is_cover","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Is Cover"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_campaign_image_api_v1_images_upload_campaign__campaign_id__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadedCampaignImage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/upload/profile-picture":{"post":{"tags":["images"],"summary":"Upload Profile Picture","description":"Upload the caller's profile picture. The single mechanism for all clients.\n\nAlways writes users.image_url, which every client reads — so an upload\nreplaces whatever was there, including the Google avatar captured at\nsignup. Nothing ever re-syncs from the OAuth provider afterwards (see\ncrud.user.set_profile_picture), which is what makes 'uploaded beats\nGoogle, permanently' hold.","operationId":"upload_profile_picture_api_v1_images_upload_profile_picture_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_profile_picture_api_v1_images_upload_profile_picture_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadedProfilePicture"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/upload/product/{product_id}":{"post":{"tags":["images"],"summary":"Upload Product Image","description":"Upload a product image to S3 and return the CloudFront URL.","operationId":"upload_product_image_api_v1_images_upload_product__product_id__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"is_main","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Is Main"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_product_image_api_v1_images_upload_product__product_id__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadedProductImage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/delete/campaign/{campaign_id}":{"delete":{"tags":["images"],"summary":"Delete Campaign Image","description":"Delete a campaign's primary image from S3 and from campaign_images.","operationId":"delete_campaign_image_api_v1_images_delete_campaign__campaign_id__delete","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MainCampaignImageDeleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/delete/product/{product_id}":{"delete":{"tags":["images"],"summary":"Delete Product Image","description":"Delete a product's primary image from S3 and from product_images.","operationId":"delete_product_image_api_v1_images_delete_product__product_id__delete","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MainProductImageDeleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign/{campaign_id}/images":{"get":{"tags":["images"],"summary":"Get Campaign Images","description":"Get all images for a campaign.","operationId":"get_campaign_images_api_v1_images_campaign__campaign_id__images_get","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagesListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["images"],"summary":"Upload Campaign Multi Image","description":"Upload a new image to a campaign's image collection.","operationId":"upload_campaign_multi_image_api_v1_images_campaign__campaign_id__images_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_campaign_multi_image_api_v1_images_campaign__campaign_id__images_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/product/{product_id}/images":{"get":{"tags":["images"],"summary":"Get Product Images","description":"Get all images for a product.","operationId":"get_product_images_api_v1_images_product__product_id__images_get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagesListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["images"],"summary":"Upload Product Multi Image","description":"Upload a new image to a product's image collection.","operationId":"upload_product_multi_image_api_v1_images_product__product_id__images_post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_product_multi_image_api_v1_images_product__product_id__images_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign/{campaign_id}/images/{image_id}":{"delete":{"tags":["images"],"summary":"Delete Campaign Multi Image","description":"Delete a specific image from a campaign.","operationId":"delete_campaign_multi_image_api_v1_images_campaign__campaign_id__images__image_id__delete","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string","title":"Image Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/product/{product_id}/images/{image_id}":{"delete":{"tags":["images"],"summary":"Delete Product Multi Image","description":"Delete a specific image from a product.","operationId":"delete_product_multi_image_api_v1_images_product__product_id__images__image_id__delete","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string","title":"Image Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign/{campaign_id}/images/reorder":{"post":{"tags":["images"],"summary":"Reorder Campaign Images","description":"Reorder campaign images.","operationId":"reorder_campaign_images_api_v1_images_campaign__campaign_id__images_reorder_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageReorderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageReorderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/product/{product_id}/images/reorder":{"post":{"tags":["images"],"summary":"Reorder Product Images","description":"Reorder product images.","operationId":"reorder_product_images_api_v1_images_product__product_id__images_reorder_post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageReorderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageReorderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign/{campaign_id}/images/set-primary":{"post":{"tags":["images"],"summary":"Set Campaign Primary Image","description":"Set a campaign image as primary.","operationId":"set_campaign_primary_image_api_v1_images_campaign__campaign_id__images_set_primary_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPrimaryImageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPrimaryImageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/product/{product_id}/images/set-primary":{"post":{"tags":["images"],"summary":"Set Product Primary Image","description":"Set a product image as primary.","operationId":"set_product_primary_image_api_v1_images_product__product_id__images_set_primary_post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPrimaryImageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPrimaryImageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign_update/{update_id}/images":{"get":{"tags":["images"],"summary":"Get Campaign Update Images","description":"Get all images for a campaign update.","operationId":"get_campaign_update_images_api_v1_images_campaign_update__update_id__images_get","parameters":[{"name":"update_id","in":"path","required":true,"schema":{"type":"string","title":"Update Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateImageList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["images"],"summary":"Upload Campaign Update Image","description":"Upload a new image to a campaign update's image collection.","operationId":"upload_campaign_update_image_api_v1_images_campaign_update__update_id__images_post","parameters":[{"name":"update_id","in":"path","required":true,"schema":{"type":"string","title":"Update Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_campaign_update_image_api_v1_images_campaign_update__update_id__images_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateImageUploaded"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign_update/{update_id}/images/{image_id}":{"delete":{"tags":["images"],"summary":"Delete Campaign Update Image","description":"Delete an image from a campaign update.","operationId":"delete_campaign_update_image_api_v1_images_campaign_update__update_id__images__image_id__delete","parameters":[{"name":"update_id","in":"path","required":true,"schema":{"type":"string","title":"Update Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string","title":"Image Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateImageDeleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign_update/{update_id}/images/reorder":{"post":{"tags":["images"],"summary":"Reorder Campaign Update Images","description":"Reorder campaign update images.","operationId":"reorder_campaign_update_images_api_v1_images_campaign_update__update_id__images_reorder_post","parameters":[{"name":"update_id","in":"path","required":true,"schema":{"type":"string","title":"Update Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageReorderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdateImagesReordered"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/images/campaign_update/{update_id}/images/set-primary":{"post":{"tags":["images"],"summary":"Set Campaign Update Primary Image","description":"Set a specific image as the primary image for a campaign update.","operationId":"set_campaign_update_primary_image_api_v1_images_campaign_update__update_id__images_set_primary_post","parameters":[{"name":"update_id","in":"path","required":true,"schema":{"type":"string","title":"Update Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPrimaryImageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignUpdatePrimaryImage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/campaigns":{"get":{"tags":["categories"],"summary":"Get Campaign Categories","description":"Get all campaign categories.","operationId":"get_campaign_categories_api_v1_categories_campaigns_get","parameters":[{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Active Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CampaignCategory"},"title":"Response Get Campaign Categories Api V1 Categories Campaigns Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["categories"],"summary":"Create Campaign Category","description":"Create campaign category. Admin only.","operationId":"create_campaign_category_api_v1_categories_campaigns_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCategoryCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCategory"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/campaigns/{category_id}":{"get":{"tags":["categories"],"summary":"Get Campaign Category","description":"Get campaign category by ID.","operationId":"get_campaign_category_api_v1_categories_campaigns__category_id__get","parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Category Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCategory"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/products/tree":{"get":{"tags":["categories"],"summary":"Get Product Categories Tree","description":"Get product categories as a nested tree structure.\nReturns only root categories with children nested recursively.\nOptional `scope` narrows the tree to one product type's taxonomy.","operationId":"get_product_categories_tree_api_v1_categories_products_tree_get","parameters":[{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Active Only"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","pattern":"^(physical|digital|service)$","title":"Scope"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductCategoryWithChildren"},"title":"Response Get Product Categories Tree Api V1 Categories Products Tree Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/products/flat":{"get":{"tags":["categories"],"summary":"Get Product Categories Flat","description":"Get all product categories as flat list with parent names.\nIncludes parent_name field for breadcrumb display.","operationId":"get_product_categories_flat_api_v1_categories_products_flat_get","parameters":[{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Active Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductCategoryFlat"},"title":"Response Get Product Categories Flat Api V1 Categories Products Flat Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/products":{"get":{"tags":["categories"],"summary":"Get Product Categories","description":"Get all product categories (flat list without parent names).","operationId":"get_product_categories_api_v1_categories_products_get","parameters":[{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Active Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductCategory"},"title":"Response Get Product Categories Api V1 Categories Products Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["categories"],"summary":"Create Product Category","description":"Create product category with optional parent_id. Admin only.","operationId":"create_product_category_api_v1_categories_products_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCategoryCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCategory"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/products/{category_id}":{"get":{"tags":["categories"],"summary":"Get Product Category","description":"Get product category by ID.","operationId":"get_product_category_api_v1_categories_products__category_id__get","parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Category Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCategory"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/categories/products/{category_id}/children":{"get":{"tags":["categories"],"summary":"Get Product Category Children","description":"Get direct children of a product category.","operationId":"get_product_category_children_api_v1_categories_products__category_id__children_get","parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Category Id"}},{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Active Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductCategory"},"title":"Response Get Product Category Children Api V1 Categories Products  Category Id  Children Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/category-suggestions/":{"post":{"tags":["category-suggestions"],"summary":"Create Suggestion","description":"Suggest a new category.","operationId":"create_suggestion_api_v1_category_suggestions__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorySuggestionCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorySuggestion"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["category-suggestions"],"summary":"Get Suggestions","description":"Every suggestion for an admin; everyone else sees their own, without\nthe admin's notes or who reviewed it (crud.for_the_suggester).","operationId":"get_suggestions_api_v1_category_suggestions__get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/SuggestionStatus"},{"type":"null"}],"description":"Filter by status","title":"Status"},"description":"Filter by status"},{"name":"suggestion_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by type (campaign/product)","title":"Suggestion Type"},"description":"Filter by type (campaign/product)"},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategorySuggestion"},"title":"Response Get Suggestions Api V1 Category Suggestions  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/category-suggestions/my-suggestions":{"get":{"tags":["category-suggestions"],"summary":"Get My Suggestions","description":"The suggestions the current user made, without the admin's notes or\nwho reviewed them (crud.for_the_suggester), whoever is asking.","operationId":"get_my_suggestions_api_v1_category_suggestions_my_suggestions_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategorySuggestion"},"title":"Response Get My Suggestions Api V1 Category Suggestions My Suggestions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/category-suggestions/{id_suggestion}":{"get":{"tags":["category-suggestions"],"summary":"Get Suggestion","description":"One suggestion, for an admin, or for the person who made it without\nthe admin's notes or who reviewed it (crud.for_the_suggester).","operationId":"get_suggestion_api_v1_category_suggestions__id_suggestion__get","parameters":[{"name":"id_suggestion","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Suggestion"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorySuggestion"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["category-suggestions"],"summary":"Update Suggestion","description":"Approve or reject a pending suggestion. Admin only.","operationId":"update_suggestion_api_v1_category_suggestions__id_suggestion__patch","parameters":[{"name":"id_suggestion","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Suggestion"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorySuggestionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorySuggestion"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/category-suggestions/{id_suggestion}/implement":{"post":{"tags":["category-suggestions"],"summary":"Implement Suggestion","description":"Create the category an approved suggestion asks for. Admin only.","operationId":"implement_suggestion_api_v1_category_suggestions__id_suggestion__implement_post","parameters":[{"name":"id_suggestion","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Suggestion"}},{"name":"display_order","in":"query","required":true,"schema":{"type":"integer","description":"Display order for the new category","title":"Display Order"},"description":"Display order for the new category"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/release-escrow/{transaction_id}":{"post":{"tags":["payments"],"summary":"Release escrowed funds (any provider)","description":"Release escrowed funds after delivery confirmation.\n\nA refusal answers {\"detail\", \"code\"}; see release_refused. Every amount\nin the answer is in dollars.","operationId":"release_escrow_funds_api_v1_payments_release_escrow__transaction_id__post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseEscrowRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseEscrowResponse"}}}},"400":{"description":"Not released: `code` says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseRefusal"}}}},"403":{"description":"Not the sale's seller (code not_seller)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseRefusal"}}}},"404":{"description":"No such sale (code not_found)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseRefusal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/availability":{"get":{"tags":["payments"],"summary":"Get Payments Availability","description":"Availability of each payment rail, merged across providers.\n\nReplaces the split probes (stripe/config's card_payments_enabled +\n/paypal/available) with a single source the web, iOS, and Android\ncheckouts can all consult. Fail closed: an unconfigured provider is\nsimply absent, never an error.\n\nAnswers for the *caller* when there is one. The card pause exempts demo\nusers — they charge the test platform account, which the live account's\nreview has no bearing on — but this probe reported the global flag to\neveryone, so clients hid the card form from the very accounts the\nexemption exists for. An App Store reviewer signed into the demo account\nwas left with a live PayPal button as the only way to pay.\n\nStays public: anonymous callers get the global answer, exactly as before.\n\nWith product_ids it also answers for the listings, yes or no per listing.\nFrom 2026-09-14 that was no for a seller with no Stripe account that\ncould be paid. Since 2026-09-17 every listing that exists can be paid by\ncard, whoever sells it (services/card_sellers.py), so it's no only for an\nid that isn't a listing, or for all of them while cards are off.","operationId":"get_payments_availability_api_v1_payments_availability_get","parameters":[{"name":"product_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"null"}],"description":"Listings about to be paid for (repeat the parameter for a cart). card_payments then answers for them, and card_payments_by_product says which can be paid by card","title":"Product Ids"},"description":"Listings about to be paid for (repeat the parameter for a cart). card_payments then answers for them, and card_payments_by_product says which can be paid by card"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentsAvailability"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/purchase-quote":{"post":{"tags":["payments"],"summary":"Quote Purchase","description":"What a cart or a Buy Now costs the buyer, and where each item's money goes.\n\nSent what the cart checkout is sent, and resolved the same way: the\nserver reads each listing's price, share and kind, and the chosen\npostage, from its own records. The rows come ready to draw\n(services.purchase_breakdown), so web, iOS and Android show the same\nbreakdown instead of each building its own.\n\nPublic, like /availability. A signed-in caller's rails are its own: demo\naccounts can pay by card while cards are paused.","operationId":"quote_purchase_api_v1_payments_purchase_quote_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseQuoteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseQuote"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/donation-quote":{"post":{"tags":["payments"],"summary":"Quote Donation","description":"What a donation costs the donor on each rail, and what the campaign receives.\n\nThe purchase quote's rows, for Donate Now (services.purchase_breakdown\n.donation_breakdown), so web, iOS and Android draw a donation the way they\ndraw a checkout. Public, like /purchase-quote, and with the same rails:\na signed-in caller's are its own.","operationId":"quote_donation_api_v1_payments_donation_quote_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DonationQuoteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DonationQuote"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/orders/contribution":{"post":{"tags":["payments"],"summary":"Open a contribution checkout on any rail","operationId":"open_contribution_order_api_v1_payments_orders_contribution_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeutralContributionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/orders/marketplace":{"post":{"tags":["payments"],"summary":"Open a marketplace checkout on any rail","operationId":"open_marketplace_order_api_v1_payments_orders_marketplace_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeutralMarketplaceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/orders/cart":{"post":{"tags":["payments"],"summary":"Open a cart checkout on any rail","operationId":"open_cart_order_api_v1_payments_orders_cart_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeutralCartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentOrderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/calculate-fees":{"post":{"tags":["payments"],"summary":"Calculate Fees","description":"Break an amount down into processing fee, platform fee and net.\n\nOne schedule is applied whatever rail ends up taking the payment, so the\nnumbers here are the numbers the splits are actually written with.","operationId":"calculate_fees_api_v1_payments_calculate_fees_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeeCalculationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeeCalculationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/health":{"get":{"tags":["payments"],"summary":"Payment Health Check","description":"Whether money can move, on any rail.\n\nThis answered for Stripe alone: it reported \"Stripe Connect\" and called\nthe service unhealthy when Stripe keys were missing. In production that\nis backwards — cards are paused and every payment runs through PayPal, so\nthe old check would have called a working payment system broken.","operationId":"payment_health_check_api_v1_payments_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentHealth"}}}}}}},"/api/v1/stripe/config":{"get":{"tags":["stripe-payments"],"summary":"Get Payment Config","description":"Get public Stripe configuration for frontend","operationId":"get_payment_config_api_v1_stripe_config_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeConfig"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/create-payment-intent":{"post":{"tags":["stripe-payments"],"summary":"Create Payment Intent","description":"Open a Stripe PaymentIntent for one of the caller's own sales or donations.\n\nThe web's single-item card checkout still comes here. It used to charge\nwhatever `amount` the request carried and record the intent against\nwhatever `reference_id` it named, with no check that the row existed,\nbelonged to the caller, or cost that much -- and settlement then marked\nthe row paid in full. So once cards were on, a $1,000 pending donation\npaid off with a $0.50 intent credited the organizer $1,000, and a sale\npaid the same way was released to its seller at full price. The amount\nis now the row's, as on /marketplace-checkout, and the row has to be the\ncaller's and still unpaid.","operationId":"create_payment_intent_api_v1_stripe_create_payment_intent_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentIntentRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/marketplace-checkout":{"post":{"tags":["stripe-payments"],"summary":"Create Marketplace Checkout","description":"Open a Stripe checkout for one of the caller's own pending transactions.\n\nEverything that decides who is charged, how much, and who gets paid comes\nfrom the transaction row. None of it comes from the request.\n\nIt used to be the other way round. The endpoint never loaded the\ntransaction at all: it took `amount`, `seller_id`, `campaign_id` and\n`donation_percentage` straight off the payload, opened a PaymentIntent for\nthem and wrote them into the metadata fulfilment later reads. So any\nsigned-in caller could open a checkout against a stranger's transaction --\nan e2e run had the campaign organizer do exactly that and got a 200 back --\nand the buyer chose their own price, because `amount: 0.01` on a hundred\ndollar item was simply believed. The PayPal endpoint has priced from the\nrow since it was written; this is the same rule on the other rail.","operationId":"create_marketplace_checkout_api_v1_stripe_marketplace_checkout_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceCheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceCheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/checkout-session":{"post":{"tags":["stripe-payments"],"summary":"Create Checkout Session","description":"Create a consolidated checkout session for multiple cart items.\n\nThis creates a SINGLE PaymentIntent for all items, saving on Stripe fees.\nInstead of 3 items = 3x $0.30, you pay just 1x $0.30.\n\nFlow:\n1. Validate all products exist and are available\n2. Calculate combined fees with proportional splits\n3. Create checkout session record\n4. Create single PaymentIntent\n5. Return client_secret for frontend payment form\n\nOn payment success (via webhook):\n- Individual transaction records are created\n- Products are marked as sold\n- Escrow flow continues per-transaction","operationId":"create_checkout_session_api_v1_stripe_checkout_session_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/direct-contribution":{"post":{"tags":["stripe-payments"],"summary":"Create Direct Contribution","description":"Create a direct donation/contribution to a campaign","operationId":"create_direct_contribution_api_v1_stripe_direct_contribution_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectContributionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectContributionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/payment-status/{payment_intent_id}":{"get":{"tags":["stripe-payments"],"summary":"Get Payment Status","description":"Stripe's status for one of the caller's own PaymentIntents.\n\nOnly the payer's: it used to answer any signed-in caller about any intent\nid, with its amount and receipt link. Asked on the Stripe account the\nintent was made on, which the row records, rather than the caller's.","operationId":"get_payment_status_api_v1_stripe_payment_status__payment_intent_id__get","parameters":[{"name":"payment_intent_id","in":"path","required":true,"schema":{"type":"string","title":"Payment Intent Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/calculate-fees":{"post":{"tags":["stripe-payments"],"summary":"Calculate Fees","description":"Break an amount down into processing fee, platform fee and net.\n\nShares its arithmetic with /payments/calculate-fees rather than keeping a\nsecond copy: shipped clients quote from this URL, and two formulas that\nare meant to agree eventually stop agreeing.","operationId":"calculate_fees_api_v1_stripe_calculate_fees_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeeCalculationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeeCalculationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/webhook":{"post":{"tags":["stripe-payments"],"summary":"Handle Stripe Webhook","description":"Handle Stripe webhook events","operationId":"handle_stripe_webhook_api_v1_stripe_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeWebhookReceipt"}}}}}}},"/api/v1/stripe/connect/create-account":{"post":{"tags":["stripe-connect"],"summary":"Create Connect Account","description":"Create a Stripe Express connected account for the current user.\nThis is the first step in the onboarding process.\n\nAnswers with the account the caller already has when it is on this\nplatform, and replaces one that isn't.\n\nOnly a seller in one of CONNECT_COUNTRIES may connect: any other\ncountry answers 422 before anything is made at Stripe. The country is\nthe request's, else the one the seller stated before, else the US for\napp builds that send neither (country_to_connect).","operationId":"create_connect_account_api_v1_stripe_connect_create_account_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConnectAccountRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectAccountResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/connect/onboarding-link":{"post":{"tags":["stripe-connect"],"summary":"Get Onboarding Link","description":"Get a Stripe-hosted onboarding link for the user to complete account setup.\nThe user will be redirected to Stripe to enter their identity, bank account, etc.\n\nMakes the connected account first when the caller has none this platform\ncan reach, so this one call is enough to start or restart onboarding.\nIt used to answer 400 for both: \"create an account first\" with no row,\nand Stripe's \"No such account\" with a row made on the closed platform.\nThe web wallet's \"continue setup\" button calls this route directly, so\na seller with an old row had no way to start again.\n\nOnly a seller in one of CONNECT_COUNTRIES may connect: any other\ncountry answers 422 before anything is made at Stripe. The country is\nthe request's, else the one the seller stated before, else the US for\napp builds that send neither (country_to_connect).","operationId":"get_onboarding_link_api_v1_stripe_connect_onboarding_link_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/connect/account-status":{"get":{"tags":["stripe-connect"],"summary":"Get Account Status","description":"Get the current status of the user's Stripe Connect account.\nUseful after onboarding to check if verification is complete.","operationId":"get_account_status_api_v1_stripe_connect_account_status_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/connect/dashboard-link":{"get":{"tags":["stripe-connect"],"summary":"Get Dashboard Link","description":"Get a login link to the Stripe Express Dashboard.\nUsers can view their payouts, transactions, and manage their bank account here.","operationId":"get_dashboard_link_api_v1_stripe_connect_dashboard_link_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/connect/has-account":{"get":{"tags":["stripe-connect"],"summary":"Check Has Account","description":"Where the caller's card payouts stand: their Stripe account, if any, the\ncountry they said they're paid in, and card_payouts, the one answer\nevery client shows the \"Connect Stripe\" row from.\n\nRead from the database only, no Stripe call. The account's flags follow\nStripe through the account.updated webhook and through account-status,\nwhich a client calls when a seller comes back from onboarding.","operationId":"check_has_account_api_v1_stripe_connect_has_account_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeAccountCheck"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/connect/payout-country":{"put":{"tags":["stripe-connect"],"summary":"Set Payout Country","description":"Record the country the caller is paid in, and answer as has-account does.\n\nAny assigned ISO 3166-1 alpha-2 code, including ones outside\nsupported_countries: this is how a seller in Brazil says so, and the\nanswer then reads paypal_only. Nothing is made at Stripe. A seller whose\naccount can already be paid stays connected whatever they say here.","operationId":"set_payout_country_api_v1_stripe_connect_payout_country_put","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutCountryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeAccountCheck"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stripe/connect/disconnect":{"delete":{"tags":["stripe-connect"],"summary":"Disconnect Account","description":"Disconnect the user's Stripe Connect account from the platform.\nNote: This doesn't delete the Stripe account, just removes the connection.","operationId":"disconnect_account_api_v1_stripe_connect_disconnect_delete","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/geography/states":{"get":{"tags":["geography"],"summary":"Get States","description":"Get list of US states from Census API.","operationId":"get_states_api_v1_geography_states_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateList"}}}}}}},"/api/v1/geography/cities":{"get":{"tags":["geography"],"summary":"Get Cities","description":"Get cities for a specific state from Census API.","operationId":"get_cities_api_v1_geography_cities_get","parameters":[{"name":"state_code","in":"query","required":true,"schema":{"type":"string","description":"Two-letter state code","title":"State Code"},"description":"Two-letter state code"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/geography/zip-lookup":{"get":{"tags":["geography"],"summary":"Lookup Zip Code","description":"Lookup city and state for a ZIP code using Census Geocoding API.","operationId":"lookup_zip_code_api_v1_geography_zip_lookup_get","parameters":[{"name":"zip_code","in":"query","required":true,"schema":{"type":"string","description":"5-digit ZIP code","title":"Zip Code"},"description":"5-digit ZIP code"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZipCodePlace"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/":{"get":{"tags":["notifications"],"summary":"Get Notifications","description":"Get user's notifications with filtering options, in the reader's language.","operationId":"get_notifications_api_v1_notifications__get","parameters":[{"name":"is_read","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by read status","title":"Is Read"},"description":"Filter by read status"},{"name":"is_archived","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by archive status","default":false,"title":"Is Archived"},"description":"Filter by archive status"},{"name":"notification_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by notification type","title":"Notification Type"},"description":"Filter by notification type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of notifications to return","default":50,"title":"Limit"},"description":"Number of notifications to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of notifications to skip","default":0,"title":"Offset"},"description":"Number of notifications to skip"},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Alias for offset: page N starts at (N-1)*limit.","title":"Page"},"description":"Alias for offset: page N starts at (N-1)*limit."},{"name":"locale","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored.","title":"Locale"},"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"},"title":"Response Get Notifications Api V1 Notifications  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["notifications"],"summary":"Create Notification","description":"Create a notification for any user. Admins only.\n\nThe recipient, title and text all come from the body. Any signed-in user\ncould call this, so anyone could put any text in anyone's inbox, and\nservices/push_dispatch sends every inbox row to the recipient's phones as\na push. No client calls it; the backend's own notifications are written\nby services/notification_service, not through here.","operationId":"create_notification_api_v1_notifications__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/stats":{"get":{"tags":["notifications"],"summary":"Get Notification Stats","description":"Get notification statistics for the current user.","operationId":"get_notification_stats_api_v1_notifications_stats_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/unread-count":{"get":{"tags":["notifications"],"summary":"Get Unread Count","description":"Get count of unread notifications.","operationId":"get_unread_count_api_v1_notifications_unread_count_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"integer","title":"Response Get Unread Count Api V1 Notifications Unread Count Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/preferences":{"get":{"tags":["notifications"],"summary":"Get Preferences","description":"Get user's notification preferences.","operationId":"get_preferences_api_v1_notifications_preferences_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferences"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["notifications"],"summary":"Update Preferences","description":"Update user's notification preferences.","operationId":"update_preferences_api_v1_notifications_preferences_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferences"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/{notification_id}":{"get":{"tags":["notifications"],"summary":"Get Notification","description":"Get a specific notification, in the reader's language.","operationId":"get_notification_api_v1_notifications__notification_id__get","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}},{"name":"locale","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored.","title":"Locale"},"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["notifications"],"summary":"Delete Notification","description":"Delete a notification.","operationId":"delete_notification_api_v1_notifications__notification_id__delete","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/mark-all-read":{"patch":{"tags":["notifications"],"summary":"Mark All As Read","description":"Mark all notifications as read.","operationId":"mark_all_as_read_api_v1_notifications_mark_all_read_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/{notification_id}/read":{"patch":{"tags":["notifications"],"summary":"Mark As Read","description":"Mark notification as read; the row comes back in the reader's language, as GET shows it.","operationId":"mark_as_read_api_v1_notifications__notification_id__read_patch","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}},{"name":"locale","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored.","title":"Locale"},"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/notifications/{notification_id}/archive":{"patch":{"tags":["notifications"],"summary":"Archive Notification","description":"Archive a notification; the row comes back in the reader's language, as GET shows it.","operationId":"archive_notification_api_v1_notifications__notification_id__archive_patch","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}},{"name":"locale","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored.","title":"Locale"},"description":"The language the reader is viewing, e.g. pt-BR. Wins over the account's saved language when supported; anything else is ignored."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/unsubscribe/":{"post":{"tags":["unsubscribe"],"summary":"Unsubscribe One Click","description":"One-click unsubscribe. Never fails in a way a mail client can see.","operationId":"unsubscribe_one_click_api_v1_unsubscribe__post","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_unsubscribe_one_click_api_v1_unsubscribe__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["unsubscribe"],"summary":"Unsubscribe Landing","description":"Hand off to the confirmation page without changing anything.\n\nActing on a GET would let any scanner that follows links in mail silently\nunsubscribe the recipient.","operationId":"unsubscribe_landing_api_v1_unsubscribe__get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"303":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/unsubscribe":{"post":{"tags":["unsubscribe"],"summary":"Unsubscribe One Click","description":"One-click unsubscribe. Never fails in a way a mail client can see.","operationId":"unsubscribe_one_click_api_v1_unsubscribe_post","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_unsubscribe_one_click_api_v1_unsubscribe_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["unsubscribe"],"summary":"Unsubscribe Landing","description":"Hand off to the confirmation page without changing anything.\n\nActing on a GET would let any scanner that follows links in mail silently\nunsubscribe the recipient.","operationId":"unsubscribe_landing_api_v1_unsubscribe_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"303":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/unsubscribe/confirm":{"post":{"tags":["unsubscribe"],"summary":"Unsubscribe Confirm","description":"What the confirmation page calls once a human has clicked.","operationId":"unsubscribe_confirm_api_v1_unsubscribe_confirm_post","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_unsubscribe_confirm_api_v1_unsubscribe_confirm_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/newsletter/subscribe":{"post":{"tags":["newsletter"],"summary":"Email a newsletter confirmation link","description":"The same answer whether or not the address is already subscribed, so\nthis can't be used to find out who is.","operationId":"subscribe_api_v1_newsletter_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterSubscribe"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"502":{"description":"The email couldn't be sent (code send_failed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterRefusal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/newsletter/confirm":{"post":{"tags":["newsletter"],"summary":"Join the newsletter with a confirmation link's token","operationId":"confirm_api_v1_newsletter_confirm_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterConfirm"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"400":{"description":"Not a newsletter link of ours (code invalid_link)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterRefusal"}}}},"502":{"description":"The mailing list refused (code subscribe_failed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterRefusal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/wallet/":{"get":{"tags":["wallet"],"summary":"Get Wallet","description":"Get current user's wallet","operationId":"get_wallet_api_v1_wallet__get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/wallet/summary":{"get":{"tags":["wallet"],"summary":"Get Wallet Summary","description":"Get enhanced wallet summary with balance tracking","operationId":"get_wallet_summary_api_v1_wallet_summary_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/wallet/transactions":{"get":{"tags":["wallet"],"summary":"Get Wallet Transactions","description":"Get wallet transaction history","operationId":"get_wallet_transactions_api_v1_wallet_transactions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Alias for offset: page N starts at (N-1)*limit.","title":"Page"},"description":"Alias for offset: page N starts at (N-1)*limit."},{"name":"transaction_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transaction Type"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WalletTransactionResponse"},"title":"Response Get Wallet Transactions Api V1 Wallet Transactions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/wallet/withdraw":{"post":{"tags":["wallet"],"summary":"Request Withdrawal","description":"Queue a withdrawal against the caller's wallet balance.\n\nOpen to anyone the ledger owes — sellers with sale proceeds and campaign\norganisers with contributions alike; the wallet does not care which side\nthe money came from.\n\nNo provider call happens here: the request lands with the balance already\ndeducted, and the payout sweep sends it (or an admin does, from the payout\nqueue). A payout PayPal hands back restores the balance automatically.","operationId":"request_withdrawal_api_v1_wallet_withdraw_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"Accept-Language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WithdrawalRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WithdrawalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/wallet/merchant-account":{"get":{"tags":["wallet"],"summary":"Get Merchant Account Status","description":"Get Stripe Connect account status for payouts","operationId":"get_merchant_account_status_api_v1_wallet_merchant_account_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantAccountResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/wallet/create-merchant-account":{"post":{"tags":["wallet"],"summary":"Create Merchant Account","description":"Create a payment account for the user via Stripe Connect.\n\nNote: This endpoint is deprecated. Use the Stripe Connect endpoints instead:\n- POST /api/v1/stripe/connect/create-account\n- POST /api/v1/stripe/connect/onboarding-link\n\nFor backwards compatibility, this creates a Stripe Express account.","operationId":"create_merchant_account_api_v1_wallet_create_merchant_account_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantAccountCreateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantAccountCreateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/transactions/{id_transaction}/request-refund":{"post":{"tags":["refunds"],"summary":"Request Transaction Refund","description":"Buyer requests a refund for a transaction","operationId":"request_transaction_refund_api_v1_refunds_transactions__id_transaction__request_refund_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuyerRefundRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refund"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/my-requests":{"get":{"tags":["refunds"],"summary":"Get My Refund Requests","description":"The refunds the current user asked for, as the buyer or donor.\n\nEach says how it was decided and the reason they were given\n(refund_history.for_the_payer). It used to send admin_notes -- a\nprovider's error text, the note an admin parked it with, an approver's\nnotes -- and the reviewer's id and name, which could be an admin's.\nThose keys stay, null, for clients that decode them.","operationId":"get_my_refund_requests_api_v1_refunds_refunds_my_requests_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status","title":"Status"},"description":"Filter by status"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyRefundRequest"},"title":"Response Get My Refund Requests Api V1 Refunds Refunds My Requests Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/seller/pending":{"get":{"tags":["refunds"],"summary":"Get Seller Pending Refunds","description":"Get pending refund requests for transactions where current user is the seller","operationId":"get_seller_pending_refunds_api_v1_refunds_refunds_seller_pending_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RefundWithDetails"},"title":"Response Get Seller Pending Refunds Api V1 Refunds Refunds Seller Pending Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/{id_refund}/approve":{"post":{"tags":["refunds"],"summary":"Approve Refund","description":"Approve a refund request and process it.\n\nA sale's refund is the seller's to approve; a donation's is the campaign\norganizer's or an admin's. Notes sent with it are kept as the refund's\nadmin_notes, where a decline's reason goes. The route read no body, so\nthe notes the admin refunds page asks for were dropped.","operationId":"approve_refund_api_v1_refunds_refunds__id_refund__approve_post","parameters":[{"name":"id_refund","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Refund"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RefundApproval"},{"type":"null"}],"title":"Approval"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundProcessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/{id_refund}/deny":{"post":{"tags":["refunds"],"summary":"Deny Refund","description":"Deny a refund request: the seller's call for a sale, the organizer's or\nan admin's for a donation.","operationId":"deny_refund_api_v1_refunds_refunds__id_refund__deny_post","parameters":[{"name":"id_refund","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Refund"}},{"name":"reason","in":"query","required":true,"schema":{"type":"string","description":"Reason for denying refund","title":"Reason"},"description":"Reason for denying refund"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundDenial"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/transactions/{id_transaction}/refund-status":{"get":{"tags":["refunds"],"summary":"Get Transaction Refund Status","description":"Get refund status for a transaction","operationId":"get_transaction_refund_status_api_v1_refunds_transactions__id_transaction__refund_status_get","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionRefundStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/contributions/{id_contribution}/request-refund":{"post":{"tags":["refunds"],"summary":"Request Donation Refund","description":"A donor asks for their donation back. The organizer or an admin decides.\n\nNo route used to open a refund for a donation at all: the one request\nroute looked every id up in `transactions`.","operationId":"request_donation_refund_api_v1_refunds_contributions__id_contribution__request_refund_post","parameters":[{"name":"id_contribution","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Contribution"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuyerRefundRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refund"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/organizer/pending":{"get":{"tags":["refunds"],"summary":"Get Organizer Pending Refunds","description":"Donation refunds waiting on the current user as a campaign's organizer.\n\nKept apart from seller/pending on purpose: the shipped Android app shows\nApprove and Deny with buyer wording on every row of that list.","operationId":"get_organizer_pending_refunds_api_v1_refunds_refunds_organizer_pending_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RefundQueueItem"},"title":"Response Get Organizer Pending Refunds Api V1 Refunds Refunds Organizer Pending Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/seller/history":{"get":{"tags":["refunds"],"summary":"Get Seller Refund History","description":"Refunds on the current user's sales that are no longer waiting on them:\napproved, declined, refunded, failed, or waiting on OpenGiving. Each\nseller sees only their own sales.","operationId":"get_seller_refund_history_api_v1_refunds_refunds_seller_history_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SaleRefundHistoryItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/organizer/history":{"get":{"tags":["refunds"],"summary":"Get Organizer Refund History","description":"Donation refunds on the current user's campaigns that are no longer\nwaiting on them. An anonymous donor is masked as on the pending list.","operationId":"get_organizer_refund_history_api_v1_refunds_refunds_organizer_history_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_DonationRefundHistoryItem_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/admin/pending":{"get":{"tags":["refunds"],"summary":"Get Admin Pending Refunds","description":"Every donation refund waiting on a decision. An admin can approve or\ndeny any of them through the same routes the organizer uses.","operationId":"get_admin_pending_refunds_api_v1_refunds_refunds_admin_pending_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RefundQueueItem"},"title":"Response Get Admin Pending Refunds Api V1 Refunds Refunds Admin Pending Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/admin/attention":{"get":{"tags":["refunds"],"summary":"Get Refunds Needing Attention","description":"Refunds parked for an admin, and refunds that failed.\n\nDonations come with what the organizer was credited and holds now, which\nis what the decision turns on. Sales are listed too: theirs are resolved\nthrough the same action.","operationId":"get_refunds_needing_attention_api_v1_refunds_refunds_admin_attention_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RefundQueueItem"},"title":"Response Get Refunds Needing Attention Api V1 Refunds Refunds Admin Attention Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/admin/transactions/{id_transaction}/refund":{"post":{"tags":["refunds"],"summary":"Admin Refund Sale","description":"Refund a sale on OpenGiving's decision, after the buyer's own window.\n\nA buyer may ask for a refund until they confirm delivery, because\nconfirming pays the seller. After that they are told to write to support,\nand the Terms say support will look at it — so support needs a way to act.\nThis is it, and it is the only one for a confirmed sale: the seller's\napprove route only ever decides a request the buyer made.\n\nRecorded as OpenGiving's decision, the way a settled service dispute is,\nand processed through the same refund path as every other refund: it\nreverses transfers, takes back what the sale paid out unless the admin\nsays not to, and refuses a sale that is already refunded.","operationId":"admin_refund_sale_api_v1_refunds_admin_transactions__id_transaction__refund_post","parameters":[{"name":"id_transaction","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Transaction"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSaleRefund"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refund"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/refunds/refunds/{id_refund}/resolve":{"post":{"tags":["refunds"],"summary":"Resolve Parked Refund","description":"An admin decides a refund parked for them.\n\nrefund_without_clawback: refund the payer and leave what the payment paid\nout where it is -- the organizer's credit, a seller's transfer or wallet\nshare. refunded_by_hand: the admin has paid the payer another way (a\nprovider that will not refund a months-old payment, say), so the payment\nis closed here without anything being taken back. acknowledge: a refund\nalready made at Stripe, recorded here and needing nothing but taking off\nthe queue. deny: turn the request down -- but a sale whose payouts were\nalready partly taken back cannot simply be denied, because that money\nwould sit with the platform, owed to nobody.","operationId":"resolve_parked_refund_api_v1_refunds_refunds__id_refund__resolve_post","parameters":[{"name":"id_refund","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Id Refund"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundResolution"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundResolved"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/feedback/":{"post":{"tags":["feedback"],"summary":"Create Feedback","description":"Create feedback for a transaction","operationId":"create_feedback_api_v1_feedback__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feedback"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/feedback/transaction/{transaction_id}":{"get":{"tags":["feedback"],"summary":"Get Feedback By Transaction","description":"Get feedback for a specific transaction","operationId":"get_feedback_by_transaction_api_v1_feedback_transaction__transaction_id__get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feedback"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/feedback/seller/{seller_id}/summary":{"get":{"tags":["feedback"],"summary":"Get Seller Ratings Summary","description":"Get seller ratings summary (public endpoint)","operationId":"get_seller_ratings_summary_api_v1_feedback_seller__seller_id__summary_get","parameters":[{"name":"seller_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Seller Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SellerRatingsSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/feedback/seller/{seller_id}":{"get":{"tags":["feedback"],"summary":"Get Seller Feedback","description":"Get all feedback for a seller with buyer information (public endpoint)","operationId":"get_seller_feedback_api_v1_feedback_seller__seller_id__get","parameters":[{"name":"seller_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Seller Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FeedbackWithBuyerInfo"},"title":"Response Get Seller Feedback Api V1 Feedback Seller  Seller Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/feedback/can-leave/{transaction_id}":{"get":{"tags":["feedback"],"summary":"Can Leave Feedback Endpoint","description":"Check if current user can leave feedback for a transaction","operationId":"can_leave_feedback_endpoint_api_v1_feedback_can_leave__transaction_id__get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanLeaveFeedbackResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/locations/validate-address":{"post":{"tags":["locations","locations"],"summary":"Validate Address External","description":"Validate an address. Kept at this path for the shipped web client.\n\nThe response shape is unchanged so nothing has to be updated the day this\ndeploys. What changed is underneath: it now asks Google's Address\nValidation API instead of the Geocoding API, and an address that cannot be\nchecked reports confidence \"unknown\" rather than \"high\".\n\nThat is a visible change on the money path. Addresses that showed a green\ntick yesterday may now say \"could not verify\", because the previous\nfallback returned verified=true for any well-formed input. Support should\nknow before this ships.\n\nMoves to /addresses/validate once the web client is pointed at it.","operationId":"validate_address_external_api_v1_locations_validate_address_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Address Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyAddressCheck"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/addresses/":{"get":{"tags":["addresses","addresses"],"summary":"List Addresses","description":"Every address this user has saved, default first.","operationId":"list_addresses_api_v1_addresses__get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["addresses","addresses"],"summary":"Create Address","description":"Save an address. The first one saved becomes the default.","operationId":"create_address_api_v1_addresses__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Address"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/addresses/{address_id}":{"get":{"tags":["addresses","addresses"],"summary":"Get Address","operationId":"get_address_api_v1_addresses__address_id__get","parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Address Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Address"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["addresses","addresses"],"summary":"Update Address","description":"Edit an address. This never changes a past order.\n\nOrders keep their own snapshot and never join back here, so fixing a typo\ncannot rewrite where something was delivered.","operationId":"update_address_api_v1_addresses__address_id__patch","parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Address Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Address"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["addresses","addresses"],"summary":"Delete Address","description":"Remove an address. If it was the default, another is promoted.","operationId":"delete_address_api_v1_addresses__address_id__delete","parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Address Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressRemoved"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/addresses/{address_id}/default":{"post":{"tags":["addresses","addresses"],"summary":"Set Default Address","description":"Promote an address to default, clearing the previous one atomically.\n\nIts own route rather than a field on PATCH: the swap has to clear the old\ndefault in the same transaction, which a partial field update cannot\nexpress.","operationId":"set_default_address_api_v1_addresses__address_id__default_post","parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Address Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Address"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/addresses/validate":{"post":{"tags":["addresses","addresses"],"summary":"Validate Address","description":"Check an address before it is saved. Advisory, never blocking.\n\nRate limited more tightly than the write routes because every call costs\nmoney once a key is configured.\n\nThe caller decides what to do with the verdict: ACCEPT proceeds silently,\nCONFIRM shows the standardized address beside what was typed, FIX\nhighlights fields. UNAVAILABLE means we could not ask, and the address\nshould be accepted as typed with no badge either way.","operationId":"validate_address_api_v1_addresses_validate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressVerdict"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/addresses/suggestions":{"post":{"tags":["addresses","addresses"],"summary":"Suggest Addresses","description":"Addresses that begin with what somebody has typed.\n\nSigned in, because this spends money per request and an open version of\nit is somebody else's free geocoder.\n\nNever an error. A missing key, a refusal, a quota, a timeout: all of them\nare an empty list with `available` false, and the person carries on typing\ninto fields that work. The reason is logged rather than returned -- a\nclient can do nothing with \"http_403\" except show it to somebody who can\ndo nothing with it either.","operationId":"suggest_addresses_api_v1_addresses_suggestions_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressSuggestionQuery"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressSuggestions"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/addresses/suggestions/{place_id}":{"post":{"tags":["addresses","addresses"],"summary":"Resolve Suggestion","description":"One picked suggestion, as an address in our own field names.\n\nThe place id is pattern-matched here as well as in the service, because\nit is interpolated into the URL of the outbound call and a path parameter\nis the one value on this route that a person never chose from a list.\n\nA client sends the session token back so the session ends on the same one\nit started with, which is what Google charges the session rate for.","operationId":"resolve_suggestion_api_v1_addresses_suggestions__place_id__post","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z0-9_-]+$","title":"Place Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressSuggestionPick"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedSuggestion"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/places/cities":{"post":{"tags":["places"],"summary":"Suggest Cities","description":"Towns and cities beginning with what somebody has typed.\n\nThe same list shape as an address suggestion, because a client draws it\nthe same way: two lines and something to resolve. \"Providence\" answers\nwith every Providence and the state each one is in, and typing the state\nas well moves the one they mean to the top.\n\nSigned in, and never an error, for the reasons the address route gives:\nthis spends money per request, and nobody waits on Google while they type.","operationId":"suggest_cities_api_v1_places_cities_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressSuggestionQuery"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressSuggestions"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/places/cities/{place_id}":{"post":{"tags":["places"],"summary":"Resolve City","description":"One picked city, as its parts and as the line that names it.\n\nThe token is sent on to Google here, which is what makes the session\ncheap: a session billed at the session rate is one that ends in a details\ncall carrying the token its keystrokes were made under.","operationId":"resolve_city_api_v1_places_cities__place_id__post","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z0-9_-]+$","title":"Place Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressSuggestionPick"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedCity"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/token":{"get":{"tags":["chat"],"summary":"Get Chat Token","description":"Generate a Stream Chat token for the current user","operationId":"get_chat_token_api_v1_chat_token_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatTokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/channels/product-inquiry":{"post":{"tags":["chat"],"summary":"Create Product Inquiry Channel","description":"Create or get a channel for product inquiries","operationId":"create_product_inquiry_channel_api_v1_chat_channels_product_inquiry_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/channels/delivery":{"post":{"tags":["chat"],"summary":"Create Delivery Channel","description":"Create or get a channel for delivery coordination","operationId":"create_delivery_channel_api_v1_chat_channels_delivery_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryChannelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/channels/campaign-inquiry":{"post":{"tags":["chat"],"summary":"Create Campaign Inquiry Channel","description":"Create or get a channel for campaign inquiries between user and organizer.","operationId":"create_campaign_inquiry_channel_api_v1_chat_channels_campaign_inquiry_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignInquiryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/channels":{"get":{"tags":["chat"],"summary":"Get User Channels","description":"Get all chat channels for the current user","operationId":"get_user_channels_api_v1_chat_channels_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/channels/{channel_id}/archive":{"patch":{"tags":["chat"],"summary":"Archive Channel","description":"Archive or unarchive a channel","operationId":"archive_channel_api_v1_chat_channels__channel_id__archive_patch","parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveChannelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelArchived"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/channels/{channel_id}/pin":{"patch":{"tags":["chat"],"summary":"Pin Channel","description":"Pin or unpin a channel for the current user","operationId":"pin_channel_api_v1_chat_channels__channel_id__pin_patch","parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinChannelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelPinned"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/pinned-channels":{"get":{"tags":["chat"],"summary":"Get Pinned Channels","description":"Get all pinned channels for the current user","operationId":"get_pinned_channels_api_v1_chat_pinned_channels_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedChannelList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/subscribe":{"post":{"tags":["push-notifications"],"summary":"Subscribe To Push Notifications","description":"Subscribe a user to push notifications.\n\nCreates or updates a push subscription for the authenticated user. An\nendpoint already on file under another account moves to this one, as a\ndevice token does in crud.device_token.register_device_token: one browser\nsigned out of one account and into another has one endpoint, and it\nshould notify whoever is signed in now. The endpoint is a URL only that\nbrowser's push service hands out, so presenting it is holding the browser.","operationId":"subscribe_to_push_notifications_api_v1_push_subscribe_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscriptionCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/unsubscribe":{"post":{"tags":["push-notifications"],"summary":"Unsubscribe From Push Notifications","description":"Unsubscribe from push notifications.\n\nRemoves the caller's own subscription for the given endpoint, and only\nthat. The same answer whether a row was removed or there was none for\nthis account: an endpoint someone else owns is left alone and reads the\nsame as one nobody has, and unsubscribing twice isn't an error.\n\nIt used to delete any account's row and 404 an endpoint it didn't know.\nThe web client unsubscribes the browser only after this succeeds, so the\n404 left a browser whose row was already gone subscribed for good.","operationId":"unsubscribe_from_push_notifications_api_v1_push_unsubscribe_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscriptionUnsubscribe"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/verify":{"post":{"tags":["push-notifications"],"summary":"Verify Push Subscription","description":"Verify that the caller has an active subscription for this endpoint.\n\nOnly the caller's own rows count. Another account's subscription for the\nsame endpoint answers \"does not exist\", as an unknown one does: saying\notherwise told a browser that had changed hands it was subscribed while\nits pushes went to the previous account, and told anyone whether an\nendpoint was on file.","operationId":"verify_push_subscription_api_v1_push_verify_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscriptionVerify"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscriptionCheck"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/subscriptions":{"get":{"tags":["push-notifications"],"summary":"Get User Push Subscriptions","description":"Get all push subscriptions for the current user.","operationId":"get_user_push_subscriptions_api_v1_push_subscriptions_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushSubscriptionResponse"},"title":"Response Get User Push Subscriptions Api V1 Push Subscriptions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/test":{"post":{"tags":["push-notifications"],"summary":"Send Test Notification","description":"Send a test push notification to the current user.\n\nUseful for testing that push notifications are working properly.","operationId":"send_test_notification_api_v1_push_test_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestNotificationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/send":{"post":{"tags":["push-notifications"],"summary":"Send Push Notification","description":"Send a push notification to a specific user or the current user. Admin-only endpoint.","operationId":"send_push_notification_api_v1_push_send_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/bulk-send":{"post":{"tags":["push-notifications"],"summary":"Send Bulk Push Notification","description":"Send push notifications to multiple users. Admin-only endpoint.","operationId":"send_bulk_push_notification_api_v1_push_bulk_send_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkPushNotificationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/track-click":{"post":{"tags":["push-notifications"],"summary":"Track Notification Click","description":"Track when a user clicks on a push notification.\n\nMeant for the service worker when a notification is clicked. A worker has\nno session, so this takes no auth and the notification id is the only\ncredential. The answer is the same whether the id matched a row or not;\nit used to say which, which confirmed that a guessed id was real.","operationId":"track_notification_click_api_v1_push_track_click_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationClickTrack"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/stats":{"get":{"tags":["push-notifications"],"summary":"Get Notification Stats","description":"Get push notification statistics for the current user.","operationId":"get_notification_stats_api_v1_push_stats_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","description":"Number of days to include in statistics","default":30,"title":"Days"},"description":"Number of days to include in statistics"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationStatsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/push/service-info":{"get":{"tags":["push-notifications"],"summary":"Get Push Service Info","description":"Get information about the push notification service configuration.\n\nReturns public information that the frontend needs to set up push notifications.","operationId":"get_push_service_info_api_v1_push_service_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushServiceInfo"}}}}}}},"/api/v1/push/templates":{"get":{"tags":["push-notifications"],"summary":"Get Notification Templates","description":"Get available notification templates.\n\nReturns the list of notification templates that can be used.","operationId":"get_notification_templates_api_v1_push_templates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationTemplates"}}}}}}},"/api/v1/push/devices":{"post":{"tags":["push-notifications"],"summary":"Register Device","description":"Register this device for push.\n\nSafe to call on every launch, which is what both apps should do: the OS\ncan rotate a token at any time and only tells the app, so the server finds\nout when the app says so.\n\nA note on the limit, since core/rate_limit.py's `_client_key` keys on IP\nby design (auth runs after the limiter): 30/minute is generous for one\nperson and still bounds a script, but it is shared by everyone behind a\nNAT. It is set high enough that a busy office cannot trip it during normal\nlaunches, and this endpoint is cheap and idempotent, so the cost of an\nover-generous limit here is far lower than the cost of blocking a real\ndevice from ever registering.","operationId":"register_device_api_v1_push_devices_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenRegister"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["push-notifications"],"summary":"Unregister Device","description":"Stop pushing to this device. Called on sign-out.\n\nScoped to the caller, so a request carrying someone else's token cannot\nsilence their phone. The dispatcher has its own unscoped path for tokens\nthe platform reports as dead.","operationId":"unregister_device_api_v1_push_devices_delete","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenRegister"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai/magic-listing":{"post":{"tags":["ai"],"summary":"Create Magic Listing","description":"Generate product listing details using AI from images.\n\nThis endpoint uses GPT-4o-mini to analyze product images (1-5) and optional description\nto automatically generate:\n- Product title\n- Detailed description\n- Category suggestion\n- Condition assessment\n- Confidence score\n- Relevant keywords\n\nThe user must provide the price separately.\n\nArgs:\n    request: MagicListingRequest containing base64 image and optional description\n    current_user: Authenticated user from JWT token\n    db: Database connection\n\nReturns:\n    MagicListingResponse with AI-generated listing details\n\nRaises:\n    HTTPException: If AI processing fails or user is not authenticated","operationId":"create_magic_listing_api_v1_ai_magic_listing_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MagicListingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MagicListingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai/magic-campaign":{"post":{"tags":["ai"],"summary":"Create Magic Campaign","description":"Generate campaign details using AI from images.\n\nThis endpoint uses GPT-4o-mini to analyze campaign images (1-5) and optional description\nto automatically generate:\n- Campaign title\n- Detailed description\n- Category suggestion\n- Suggested fundraising goal\n- Confidence score\n- Relevant keywords\n\nThe user can adjust the goal and other details before creating the campaign.\n\nArgs:\n    request: MagicCampaignRequest containing base64 image and optional description\n    current_user: Authenticated user from JWT token\n    db: Database connection\n\nReturns:\n    MagicCampaignResponse with AI-generated campaign details\n\nRaises:\n    HTTPException: If AI processing fails or user is not authenticated","operationId":"create_magic_campaign_api_v1_ai_magic_campaign_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MagicCampaignRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MagicCampaignResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai/magic-listing-bulk":{"post":{"tags":["ai"],"summary":"Create Bulk Magic Listing","description":"Generate multiple product listings using AI from up to 20 images.\n\nThis endpoint uses GPT-4o-mini Vision to:\n1. Analyze all images and identify distinct items\n2. Group images by detected item\n3. Generate listing details for each item group\n\nArgs:\n    request: BulkMagicListingRequest containing up to 20 base64 images and optional context\n    current_user: Authenticated user from JWT token\n    db: Database connection\n\nReturns:\n    BulkMagicListingResponse with detected items, groupings, and listing details\n\nRaises:\n    HTTPException: If AI processing fails or user is not authenticated","operationId":"create_bulk_magic_listing_api_v1_ai_magic_listing_bulk_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkMagicListingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkMagicListingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/app/config":{"get":{"tags":["app-config"],"summary":"Get App Config","description":"Get application configuration for mobile/web clients.\n\nThis endpoint should be called at app launch to determine:\n- Environment (production, local, etc.)\n- Stripe mode (test vs live)\n- Feature flags\n- Maintenance status\n\nFor App Store review:\nDemo users (configured via DEMO_USER_IDS) will use Stripe test mode.\nProvide Apple reviewers with Stripe test card numbers in App Store Connect.","operationId":"get_app_config_api_v1_app_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}}}}},"/api/v1/shipping/validate-address":{"post":{"tags":["shipping"],"summary":"Validate Address","description":"Validate a shipping address with Shippo.\n\nReturns validation status and suggestions for corrections if needed.","operationId":"validate_address_api_v1_shipping_validate_address_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressValidationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressValidationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/shipping/rates/{product_id}":{"post":{"tags":["shipping"],"summary":"Get Shipping Rates","description":"Get shipping rates for a product.\n\nUses the product's parcel dimensions and seller's location as origin.\nReturns available carrier options sorted by price.","operationId":"get_shipping_rates_api_v1_shipping_rates__product_id__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Product Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingRateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShippingRatesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/shipping/purchase-label/{transaction_id}":{"post":{"tags":["shipping"],"summary":"Purchase Shipping Label","description":"Purchase a shipping label for a transaction.\n\nOnly the seller can purchase labels for their sold items.\nLabel cost is absorbed by the platform.","operationId":"purchase_shipping_label_api_v1_shipping_purchase_label__transaction_id__post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseLabelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseLabelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/shipping/track/{transaction_id}":{"get":{"tags":["shipping"],"summary":"Get Tracking","description":"Get tracking information for a shipped transaction.\n\nBoth buyer and seller can view tracking information.","operationId":"get_tracking_api_v1_shipping_track__transaction_id__get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/shipping/store-rate/{transaction_id}":{"post":{"tags":["shipping"],"summary":"Store Selected Rate","description":"Store the selected shipping rate on a transaction.\n\nCalled during checkout after the buyer picks one of the rates this server\noffered. The rate is identified, not described: carrier, service and price\ncome from what was quoted, never from the caller.\n\nThey used to be query parameters. `price_cents` was an unbounded int that\nlands on `shipping_rate_cents`, which both payment rails add to the amount\nthey collect -- so the buyer chose what their own postage cost. Zero was\nfree shipping the seller still paid for; a negative was a discount on the\nrest of the order.","operationId":"store_selected_rate_api_v1_shipping_store_rate__transaction_id__post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Transaction Id"}},{"name":"rate_id","in":"query","required":true,"schema":{"type":"string","title":"Rate Id"}},{"name":"shipment_id","in":"query","required":true,"schema":{"type":"string","title":"Shipment Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredShippingRate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/campaigns/{campaign_id}/report":{"post":{"tags":["campaign-reports"],"summary":"Report Campaign","description":"Submit a report for a campaign.\n\nUsers can report campaigns they suspect of:\n- Fraud\n- Inappropriate content\n- Misleading information\n- Spam\n- Other violations","operationId":"report_campaign_api_v1_campaigns__campaign_id__report_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Campaign Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignReportCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignReportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/campaign-reports":{"get":{"tags":["campaign-reports"],"summary":"Get All Reports","description":"Get all campaign reports (admin only).\n\nSupports filtering by status and pagination.","operationId":"get_all_reports_api_v1_admin_campaign_reports_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status: pending, under_review, resolved, dismissed","title":"Status"},"description":"Filter by status: pending, under_review, resolved, dismissed"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Items per page","default":20,"title":"Limit"},"description":"Items per page"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignReportListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/campaign-reports/stats":{"get":{"tags":["campaign-reports"],"summary":"Get Report Stats","description":"Get campaign report statistics for admin dashboard.\n\nReturns counts for total, pending, under review, resolved, and dismissed reports.","operationId":"get_report_stats_api_v1_admin_campaign_reports_stats_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignReportStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/campaign-reports/{report_id}":{"get":{"tags":["campaign-reports"],"summary":"Get Report Details","description":"Get detailed information about a specific report (admin only).\n\nIncludes campaign details, reporter info, and reviewer info if reviewed.","operationId":"get_report_details_api_v1_admin_campaign_reports__report_id__get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignReportWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["campaign-reports"],"summary":"Delete Report","description":"Delete a campaign report (admin only).\n\nThis is a destructive action and should be used sparingly.","operationId":"delete_report_api_v1_admin_campaign_reports__report_id__delete","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/campaign-reports/{report_id}/review":{"patch":{"tags":["campaign-reports"],"summary":"Review Report","description":"Review a campaign report (admin only).\n\nAllows admins to:\n- Change status (pending, under_review, resolved, dismissed)\n- Add admin notes\n- Set resolution (warning_issued, campaign_removed, no_action, under_investigation)","operationId":"review_report_api_v1_admin_campaign_reports__report_id__review_patch","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignReportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/me/deletion-request":{"post":{"tags":["account-deletion"],"summary":"Request Account Deletion","description":"Ask for your account to be deleted.\n\nIdempotent: asking twice returns the request you already have rather than\nopening a second one.","operationId":"request_account_deletion_api_v1_users_me_deletion_request_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionRequestCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["account-deletion"],"summary":"Get My Deletion Request","description":"Whether a deletion request is open, so the app can show its state.\n\nWith nothing open, a request an admin declined comes back as `request`\nwhen it's the latest one, so the app can say it was declined and why.\n`has_pending_request` stays false for it.","operationId":"get_my_deletion_request_api_v1_users_me_deletion_request_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["account-deletion"],"summary":"Cancel Account Deletion","description":"Change your mind while the request is still waiting to be reviewed.","operationId":"cancel_account_deletion_api_v1_users_me_deletion_request_delete","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"accept-language","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept-Language"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/deletion-requests":{"get":{"tags":["account-deletion"],"summary":"List Deletion Requests","description":"The review queue, each entry carrying what the account still holds.","operationId":"list_deletion_requests_api_v1_admin_deletion_requests_get","parameters":[{"name":"request_status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status: pending, approved, rejected, cancelled","title":"Request Status"},"description":"Filter by status: pending, approved, rejected, cancelled"},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionRequestList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/deletion-requests/{request_id}":{"get":{"tags":["account-deletion"],"summary":"Get Deletion Request","description":"One request, with the account's campaigns, escrow and listings.","operationId":"get_deletion_request_api_v1_admin_deletion_requests__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Request Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionRequestWithDetails"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/deletion-requests/{request_id}/review":{"patch":{"tags":["account-deletion"],"summary":"Review Deletion Request","description":"Approve or decline. Approving wipes the account's personal data.\n\nOnly a pending request can be reviewed — re-approving an already-approved\nrequest would run the wipe a second time against an account that no longer\nhas anything to wipe.","operationId":"review_deletion_request_api_v1_admin_deletion_requests__request_id__review_patch","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Request Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminDeletionReview"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeletionRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/analytics/tips":{"get":{"tags":["admin-analytics"],"summary":"Get Tip Analytics","description":"Get platform tip analytics for admin dashboard","operationId":"get_tip_analytics_api_v1_admin_analytics_tips_get","parameters":[{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Start Date"}},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"End Date"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TipAnalytics"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/analytics/tips/summary":{"get":{"tags":["admin-analytics"],"summary":"Get Tip Summary","description":"Get quick tip summary for admin dashboard","operationId":"get_tip_summary_api_v1_admin_analytics_tips_summary_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TipSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/cleanup/cleanup/transactions":{"post":{"tags":["admin-cleanup"],"summary":"Cleanup Incomplete Transactions","description":"Clean up incomplete transactions older than the threshold. Admin-only endpoint.\n\nThis endpoint helps maintain database hygiene by removing failed/abandoned transactions.\nDefault is dry_run=True for safety.","operationId":"cleanup_incomplete_transactions_api_v1_admin_cleanup_cleanup_transactions_post","parameters":[{"name":"hours_threshold","in":"query","required":false,"schema":{"type":"integer","description":"Hours after which to clean up incomplete transactions","default":24,"title":"Hours Threshold"},"description":"Hours after which to clean up incomplete transactions"},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, only show what would be cleaned up without deleting","default":true,"title":"Dry Run"},"description":"If true, only show what would be cleaned up without deleting"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupRun"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/cleanup/cleanup/candidates":{"get":{"tags":["admin-cleanup"],"summary":"Get Cleanup Candidates","description":"Get a preview of transactions that would be cleaned up. Admin-only: it\nlists other people's abandoned purchases.","operationId":"get_cleanup_candidates_api_v1_admin_cleanup_cleanup_candidates_get","parameters":[{"name":"hours_threshold","in":"query","required":false,"schema":{"type":"integer","description":"Hours after which transactions would be cleaned up","default":24,"title":"Hours Threshold"},"description":"Hours after which transactions would be cleaned up"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupCandidates"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/cleanup/cleanup/product/{product_id}":{"post":{"tags":["admin-cleanup"],"summary":"Cleanup Product Transactions","description":"Clean up incomplete transactions for a specific product. Admin-only endpoint.\nUseful when a product has many failed purchase attempts.\n\nDeletes only attempts where no money moved, and only when that is true of\nevery transaction the product has. Otherwise 409, naming each transaction\nand why, with nothing deleted.","operationId":"cleanup_product_transactions_api_v1_admin_cleanup_cleanup_product__product_id__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","title":"Product Id"}},{"name":"keep_latest","in":"query","required":false,"schema":{"type":"boolean","description":"Keep the most recent incomplete transaction","default":true,"title":"Keep Latest"},"description":"Keep the most recent incomplete transaction"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCleanup"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payouts/pending":{"get":{"tags":["admin-payouts"],"summary":"List Pending Payouts","description":"Everything currently owed, oldest request first.","operationId":"list_pending_payouts_api_v1_admin_payouts_pending_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingPayout"},"title":"Response List Pending Payouts Api V1 Admin Payouts Pending Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payouts/{withdrawal_id}/mark-paid":{"post":{"tags":["admin-payouts"],"summary":"Mark Payout Paid","description":"Record that the payout was sent from the platform's PayPal account.","operationId":"mark_payout_paid_api_v1_admin_payouts__withdrawal_id__mark_paid_post","parameters":[{"name":"withdrawal_id","in":"path","required":true,"schema":{"type":"string","title":"Withdrawal Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkPaidRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutActionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payouts/{withdrawal_id}/reject":{"post":{"tags":["admin-payouts"],"summary":"Reject Payout","description":"Decline the request; the deducted balance returns to the wallet.","operationId":"reject_payout_api_v1_admin_payouts__withdrawal_id__reject_post","parameters":[{"name":"withdrawal_id","in":"path","required":true,"schema":{"type":"string","title":"Withdrawal Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutActionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payouts/{withdrawal_id}/pay-with-paypal":{"post":{"tags":["admin-payouts"],"summary":"Pay With Paypal","description":"Send the payout through PayPal instead of by hand.\n\nMoves the withdrawal to `processing`; the payout sweep settles it once\nPayPal decides. A refusal here changes nothing — the request stays\npending and payable.","operationId":"pay_with_paypal_api_v1_admin_payouts__withdrawal_id__pay_with_paypal_post","parameters":[{"name":"withdrawal_id","in":"path","required":true,"schema":{"type":"string","title":"Withdrawal Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DispatchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payouts/sweep":{"post":{"tags":["admin-payouts"],"summary":"Sweep Payouts","description":"Settle in-flight payouts now, without waiting for the timer.","operationId":"sweep_payouts_api_v1_admin_payouts_sweep_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutSweepResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/payouts/reconcile-paypal":{"post":{"tags":["admin-payouts"],"summary":"Reconcile Paypal","description":"Settle PayPal orders that were captured but never fulfilled.\n\nThe webhook is the usual safety net; this is the net under the net, for\ndeliveries that never arrived. Read-only against PayPal — it settles\nwhat PayPal already captured and never captures anything itself.","operationId":"reconcile_paypal_api_v1_admin_payouts_reconcile_paypal_post","parameters":[{"name":"min_age_minutes","in":"query","required":false,"schema":{"type":"integer","default":15,"title":"Min Age Minutes"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dry Run"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconciliationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/escrow/held":{"get":{"tags":["admin-escrow"],"summary":"List Held Escrow","description":"Every paid transaction whose money is still sitting in escrow.\n\nOrdered oldest first: the point of the list is the backlog, and the row\nthat has been waiting longest is the one most likely to be owed.","operationId":"list_held_escrow_api_v1_admin_escrow_held_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HeldEscrow"},"title":"Response List Held Escrow Api V1 Admin Escrow Held Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/escrow/{transaction_id}/settle-offline":{"post":{"tags":["admin-escrow"],"summary":"Settle Escrow Offline","description":"Close an escrow that was already settled outside this platform.\n\nBookkeeping, not a payment. The Stripe-era sales were paid by hand while\nthe site was half-working: the seller has their money and the organisers\nhave theirs, and only the ledger never heard. Releasing those normally\nwould credit a wallet the platform would then owe a second time, or\nattempt a Connect transfer that pays twice.\n\nSo this moves no money and calls no provider — it marks the escrow closed\nand records on the row who was actually paid and why. It is deliberately\nnot the release path: `/payments/release-escrow/{id}` remains the only\nway money leaves.","operationId":"settle_escrow_offline_api_v1_admin_escrow__transaction_id__settle_offline_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettleOfflineRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettleOfflineResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/held-payouts":{"get":{"tags":["admin-held-payouts"],"summary":"List Held Payouts","description":"Card money waiting for its recipient, oldest first.\n\nOldest first because the point of the list is what has been waiting: a\nrow that became owed on request months ago is the one somebody is most\nlikely writing in about.","operationId":"list_held_payouts_api_v1_admin_held_payouts_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"open (held and owed on request, the default), held, owed_on_request, paid, refunded, or all","default":"open","title":"Status"},"description":"open (held and owed on request, the default), held, owed_on_request, paid, refunded, or all"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HeldPayout"},"title":"Response List Held Payouts Api V1 Admin Held Payouts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/held-payouts/{payout_id}/pay":{"post":{"tags":["admin-held-payouts"],"summary":"Pay Held Payout","description":"Pay one held share, because its recipient asked for it.\n\nStripe if their account can take it by now — the same transfer the\nautomatic payer makes, so a share paid here and a share paid on connect\nare recorded identically. Otherwise their OpenGiving wallet, which they\nwithdraw through PayPal.\n\nRefuses a row that has already been paid or refunded rather than paying\nit again: this is the one place a person moves this money by hand, and\nthe money has left either way.","operationId":"pay_held_payout_api_v1_admin_held_payouts__payout_id__pay_post","parameters":[{"name":"payout_id","in":"path","required":true,"schema":{"type":"string","title":"Payout Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaidPayout"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/ledger-audit":{"get":{"tags":["admin-ledger"],"summary":"Ledger Audit","description":"Report drift between derived money values and the rows behind them.","operationId":"ledger_audit_api_v1_admin_ledger_audit_get","parameters":[{"name":"check","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Run one check only. One of: campaign_raised, wallet_balance, escrow_credited, split_integrity, profile_donated, wallet_lifetime, claim_transferred, campaign_count_ceiling, stripe_covers_held_escrow, service_fee_recorded","title":"Check"},"description":"Run one check only. One of: campaign_raised, wallet_balance, escrow_credited, split_integrity, profile_donated, wallet_lifetime, claim_transferred, campaign_count_ceiling, stripe_covers_held_escrow, service_fee_recorded"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerAuditReport"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/indexnow":{"get":{"tags":["admin-indexnow"],"summary":"Indexnow Status","description":"Report the sweep's watermark and what its last pass did.","operationId":"indexnow_status_api_v1_admin_indexnow_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexNowStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/email-suppressions":{"get":{"tags":["admin-email-suppressions"],"summary":"List Email Suppressions","description":"Who is suppressed, why, and since when.","operationId":"list_email_suppressions_api_v1_admin_email_suppressions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Alias for offset: page N starts at (N-1)*limit.","title":"Page"},"description":"Alias for offset: page N starts at (N-1)*limit."},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring match, to find one address without paging","title":"Email"},"description":"Substring match, to find one address without paging"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSuppressionPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin-email-suppressions"],"summary":"Remove Email Suppression","description":"Lift a suppression.\n\n`reason` is required rather than optional. There is no audit table, so the\nlog line is the only record of why somebody decided a bounced address was\nsafe to mail again, and an unexplained one is not worth writing down.\n\nReturns `removed: false` rather than 404 when there was nothing to lift, so\na retry after a successful delete is not an error.","operationId":"remove_email_suppression_api_v1_admin_email_suppressions_delete","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","description":"The address to un-suppress","title":"Email"},"description":"The address to un-suppress"},{"name":"reason","in":"query","required":true,"schema":{"type":"string","minLength":3,"description":"Why this is being lifted. Recorded in the log.","title":"Reason"},"description":"Why this is being lifted. Recorded in the log."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSuppressionLifted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/referrals/track/{code}":{"get":{"tags":["referrals"],"summary":"Track Referral","description":"Track a referral click. This is a public endpoint called by the frontend\nwhen a user lands on the site with a ?ref= parameter.","operationId":"track_referral_api_v1_referrals_track__code__get","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string","title":"Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralClickTracked"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/referrals/stats":{"get":{"tags":["referrals"],"summary":"Get Referral Stats","description":"Get comprehensive referral statistics for admin dashboard.","operationId":"get_referral_stats_api_v1_referrals_stats_get","parameters":[{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Start date for filtering","title":"Start Date"},"description":"Start date for filtering"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"End date for filtering","title":"End Date"},"description":"End date for filtering"},{"name":"owner_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OwnerType"},{"type":"null"}],"description":"Filter by owner type","title":"Owner Type"},"description":"Filter by owner type"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/referrals/leaderboard":{"get":{"tags":["referrals"],"summary":"Get Leaderboard","description":"Get referral leaderboard for admin dashboard.","operationId":"get_leaderboard_api_v1_referrals_leaderboard_get","parameters":[{"name":"owner_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OwnerType"},{"type":"null"}],"description":"Filter by owner type","title":"Owner Type"},"description":"Filter by owner type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of entries","default":10,"title":"Limit"},"description":"Number of entries"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/schemas__referral__LeaderboardEntry"},"title":"Response Get Leaderboard Api V1 Referrals Leaderboard Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/referrals/summary":{"get":{"tags":["referrals"],"summary":"Get Referral Summary","description":"Get quick referral summary for admin dashboard cards.","operationId":"get_referral_summary_api_v1_referrals_summary_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/referrals/codes":{"get":{"tags":["referrals"],"summary":"Get All Codes","description":"Get all referral codes with their stats.","operationId":"get_all_codes_api_v1_referrals_codes_get","parameters":[{"name":"owner_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OwnerType"},{"type":"null"}],"description":"Filter by owner type","title":"Owner Type"},"description":"Filter by owner type"},{"name":"include_inactive","in":"query","required":false,"schema":{"type":"boolean","description":"Include inactive codes","default":false,"title":"Include Inactive"},"description":"Include inactive codes"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReferralCodeWithStats"},"title":"Response Get All Codes Api V1 Referrals Codes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["referrals"],"summary":"Create Code","description":"Create a new referral code.","operationId":"create_code_api_v1_referrals_codes_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralCodeCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralCode"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/referrals/codes/{code_id}":{"get":{"tags":["referrals"],"summary":"Get Code","description":"Get a specific referral code with its stats.","operationId":"get_code_api_v1_referrals_codes__code_id__get","parameters":[{"name":"code_id","in":"path","required":true,"schema":{"type":"string","title":"Code Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralCodeWithStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["referrals"],"summary":"Update Code","description":"Update a referral code.","operationId":"update_code_api_v1_referrals_codes__code_id__patch","parameters":[{"name":"code_id","in":"path","required":true,"schema":{"type":"string","title":"Code Id"}},{"name":"owner_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Name"}},{"name":"owner_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Email"}},{"name":"owner_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OwnerType"},{"type":"null"}],"title":"Owner Type"}},{"name":"is_active","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralCode"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["referrals"],"summary":"Delete Code","description":"Deactivate a referral code (soft delete).","operationId":"delete_code_api_v1_referrals_codes__code_id__delete","parameters":[{"name":"code_id","in":"path","required":true,"schema":{"type":"string","title":"Code Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralCode"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/webhooks/stream":{"post":{"tags":["webhooks-stream"],"summary":"Handle Stream Webhook","description":"Handle Stream.io webhooks for chat events.\n\nThe signature is the only authorisation this endpoint has: it is anonymous\nby necessity, and it writes notification rows for whatever user ids the body\nnames. Verification therefore happens before anything else and before the\ntry block, so a rejection cannot be swallowed and reported as a server\nerror.\n\nIt used to read `if x_signature:` with no else, so omitting the header\nskipped the check entirely and the payload was processed unverified.\n\nThe event handled is the one verify_and_parse_webhook returns, not a second\nread of the body. With webhook compression on, the body is gzip, and only\nthe library's parse unzips it.\n\nOnly InvalidWebhookError becomes a 401: a signature mismatch, or a body that\nwon't unzip or parse. Any other exception means verification itself broke,\nsay after a library change, and it surfaces as a 500 with a traceback\nrather than passing for a forged request.","operationId":"handle_stream_webhook_api_v1_webhooks_stream_post","parameters":[{"name":"x-signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/webhooks/resend":{"post":{"tags":["webhooks-resend"],"summary":"Resend Webhook","operationId":"resend_webhook_api_v1_webhooks_resend_post","parameters":[{"name":"svix-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Svix-Id"}},{"name":"svix-timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Svix-Timestamp"}},{"name":"svix-signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Svix-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendWebhookReceipt"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","description":"Root route.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AccountDeletionRequestCreate":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reason","description":"Optional note from the user about why they are leaving"}},"type":"object","title":"AccountDeletionRequestCreate","description":"Schema for requesting deletion of your own account"},"AccountDeletionRequestForRequester":{"properties":{"id_request":{"type":"string","format":"uuid","title":"Id Request"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id","description":"The reviewing admin's user id. Sent to admins only; null in the requester's own answers"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes","description":"The reviewer's note. Sent to admins only; null in the requester's own answers"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"decline_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decline Reason","description":"Why the request was declined, as the reviewing admin wrote it for the requester. Set only when status is \"declined\"; null otherwise, and never taken from a note on an approval"}},"type":"object","required":["id_request","user_id","status","created_at"],"title":"AccountDeletionRequestForRequester","description":"A request as the person who made it reads it.\n\nBuilt by crud.account_deletion.for_the_requester: admin_notes and\nadmin_reviewer_id are always null, a declined request's status reads\n\"declined\", and `decline_reason` is the note the admin wrote for them\nwhen they declined it."},"AccountDeletionRequestList":{"properties":{"requests":{"items":{"$ref":"#/components/schemas/AccountDeletionRequestWithDetails"},"type":"array","title":"Requests"},"total":{"type":"integer","title":"Total"},"pending_count":{"type":"integer","title":"Pending Count"}},"type":"object","required":["requests","total","pending_count"],"title":"AccountDeletionRequestList","description":"Paginated list of deletion requests for the admin queue"},"AccountDeletionRequestResponse":{"properties":{"id_request":{"type":"string","format":"uuid","title":"Id Request"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id","description":"The reviewing admin's user id. Sent to admins only; null in the requester's own answers"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes","description":"The reviewer's note. Sent to admins only; null in the requester's own answers"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id_request","user_id","status","created_at"],"title":"AccountDeletionRequestResponse","description":"Response schema for an account deletion request"},"AccountDeletionRequestWithDetails":{"properties":{"id_request":{"type":"string","format":"uuid","title":"Id Request"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id","description":"The reviewing admin's user id. Sent to admins only; null in the requester's own answers"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes","description":"The reviewer's note. Sent to admins only; null in the requester's own answers"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"user_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Email"},"user_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Name"},"user_created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"User Created At"},"user_locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Locale"},"holdings":{"anyOf":[{"$ref":"#/components/schemas/AccountHoldings"},{"type":"null"}]}},"type":"object","required":["id_request","user_id","status","created_at"],"title":"AccountDeletionRequestWithDetails","description":"A request plus the identity and holdings an admin needs to judge it"},"AccountDeletionStatusResponse":{"properties":{"has_pending_request":{"type":"boolean","title":"Has Pending Request"},"request":{"anyOf":[{"$ref":"#/components/schemas/AccountDeletionRequestForRequester"},{"type":"null"}]}},"type":"object","required":["has_pending_request"],"title":"AccountDeletionStatusResponse","description":"What the app polls to decide which state to render.\n\n`has_pending_request` is the flag the UI switches on, so the client never\nhas to know the status vocabulary.\n\nWith a request pending, `request` is that request. With none pending,\n`request` is the latest request when an admin declined it, so the app\ncan say it was declined and why (`status` \"declined\", `reviewed_at`,\n`decline_reason`). A newer request, pending or withdrawn, supersedes a\ndecline, and then `request` is null."},"AccountHoldings":{"properties":{"active_campaigns":{"type":"integer","title":"Active Campaigns"},"total_raised":{"type":"number","title":"Total Raised"},"open_escrow_transactions":{"type":"integer","title":"Open Escrow Transactions"},"open_escrow_amount":{"type":"number","title":"Open Escrow Amount"},"active_listings":{"type":"integer","title":"Active Listings"}},"type":"object","required":["active_campaigns","total_raised","open_escrow_transactions","open_escrow_amount","active_listings"],"title":"AccountHoldings","description":"What the account still holds, shown to the admin doing the review.\n\nThis is the point of the review: someone who raised money should not be\nable to erase the trail by deleting their account, so these numbers are\nput in front of the reviewer before they can approve."},"AccountLinkRequest":{"properties":{"return_url":{"type":"string","title":"Return Url","description":"URL to redirect after onboarding"},"refresh_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refresh Url","description":"URL if link expires"},"country":{"anyOf":[{"type":"string","pattern":"^[A-Za-z]{2}$"},{"type":"null"}],"title":"Country","description":"The seller's country, as ISO 3166-1 alpha-2 (\"US\", \"BR\"), kept as their payout_country. Only the countries in has-account's supported_countries may connect; any other answers 422 with a plain detail and nothing is made at Stripe. Unset means the country the seller stated with PUT /stripe/connect/payout-country, else \"US\" for app builds that predate both.","examples":["US"]}},"type":"object","required":["return_url"],"title":"AccountLinkRequest","description":"Request to create an account onboarding link"},"AccountLinkResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Stripe-hosted onboarding URL"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"When the link expires"}},"type":"object","required":["url"],"title":"AccountLinkResponse","description":"Account link response"},"AccountStatusResponse":{"properties":{"account_id":{"type":"string","title":"Account Id","description":"Stripe account ID"},"type":{"type":"string","title":"Type","description":"Account type"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Account email"},"charges_enabled":{"type":"boolean","title":"Charges Enabled","description":"Whether account can accept charges"},"payouts_enabled":{"type":"boolean","title":"Payouts Enabled","description":"Whether account can receive payouts"},"details_submitted":{"type":"boolean","title":"Details Submitted","description":"Whether details are submitted"},"onboarding_complete":{"type":"boolean","title":"Onboarding Complete","description":"Whether onboarding is complete"},"pending_requirements":{"items":{"type":"string"},"type":"array","title":"Pending Requirements","description":"Requirements needed now"},"future_requirements":{"items":{"type":"string"},"type":"array","title":"Future Requirements","description":"Requirements needed eventually"},"disabled_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disabled Reason","description":"Why account is disabled"}},"type":"object","required":["account_id","type","charges_enabled","payouts_enabled","details_submitted","onboarding_complete"],"title":"AccountStatusResponse","description":"Detailed account status response"},"Address":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Label","description":"What the owner calls it, e.g. Home"},"address_type":{"type":"string","enum":["home","work","family","other"],"title":"Address Type","description":"The saved address's semantic type; clients choose how to draw it","default":"home"},"recipient_name":{"type":"string","maxLength":120,"minLength":1,"title":"Recipient Name"},"phone":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Phone"},"street1":{"type":"string","maxLength":255,"minLength":1,"title":"Street1"},"street2":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Street2"},"district":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"District","description":"Neighbourhood (bairro)"},"city":{"type":"string","maxLength":120,"minLength":1,"title":"City"},"region":{"type":"string","maxLength":60,"minLength":1,"title":"Region","description":"State, province or region"},"postal_code":{"type":"string","maxLength":20,"minLength":1,"title":"Postal Code"},"country_code":{"type":"string","maxLength":2,"minLength":2,"title":"Country Code","default":"US"},"id_address":{"type":"string","format":"uuid","title":"Id Address"},"is_default":{"type":"boolean","title":"Is Default"},"validation_status":{"type":"string","title":"Validation Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["recipient_name","street1","city","region","postal_code","id_address","is_default","validation_status","created_at","updated_at"],"title":"Address"},"AddressBookConfig":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":false},"max_addresses":{"type":"integer","title":"Max Addresses","default":20},"autocomplete":{"type":"boolean","title":"Autocomplete","default":false},"countries":{"items":{"type":"string"},"type":"array","title":"Countries","default":["US"]}},"type":"object","title":"AddressBookConfig","description":"Whether clients should show saved delivery addresses.\n\nOff until the whole path exists end to end. Flipping this is the launch,\nwhich means the rollback is one environment variable rather than a deploy —\nworth having on a feature that reaches checkout."},"AddressCreate":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Label","description":"What the owner calls it, e.g. Home"},"address_type":{"type":"string","enum":["home","work","family","other"],"title":"Address Type","description":"The saved address's semantic type; clients choose how to draw it","default":"home"},"recipient_name":{"type":"string","maxLength":120,"minLength":1,"title":"Recipient Name"},"phone":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Phone"},"street1":{"type":"string","maxLength":255,"minLength":1,"title":"Street1"},"street2":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Street2"},"district":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"District","description":"Neighbourhood (bairro)"},"city":{"type":"string","maxLength":120,"minLength":1,"title":"City"},"region":{"type":"string","maxLength":60,"minLength":1,"title":"Region","description":"State, province or region"},"postal_code":{"type":"string","maxLength":20,"minLength":1,"title":"Postal Code"},"country_code":{"type":"string","maxLength":2,"minLength":2,"title":"Country Code","default":"US"}},"type":"object","required":["recipient_name","street1","city","region","postal_code"],"title":"AddressCreate","description":"Creating an address never sets the default flag.\n\nPromotion is its own route, so that \"save this address\" and \"make this the\none I ship to\" are separate decisions with separate audit trails. The first\naddress a user saves is made default automatically, because a book with\nentries and no default is a state nothing else in the system expects."},"AddressList":{"properties":{"addresses":{"items":{"$ref":"#/components/schemas/Address"},"type":"array","title":"Addresses"},"total":{"type":"integer","title":"Total"},"max_addresses":{"type":"integer","title":"Max Addresses","default":20}},"type":"object","required":["addresses","total"],"title":"AddressList","description":"A named object, never a bare array.\n\nAndroid has thrown on an envelope-versus-array mismatch before, and a named\nkey leaves room to add a field later without changing the response's type.\nThere is no pagination here on purpose: the list cannot exceed\nMAX_ADDRESSES_PER_USER, and this API already carries five pagination\ndialects across its other endpoints without needing a sixth."},"AddressRemoved":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a missing address is a 404"},"id_address":{"type":"string","title":"Id Address","description":"The address removed"}},"type":"object","required":["success","id_address"],"title":"AddressRemoved","description":"DELETE /addresses/{id}. Android's AddressDeleteResponseDto reads\n`success` as a non-null Boolean; iOS and web don't read the body."},"AddressSuggestion":{"properties":{"place_id":{"type":"string","title":"Place Id"},"primary_text":{"type":"string","title":"Primary Text"},"secondary_text":{"type":"string","title":"Secondary Text","default":""}},"type":"object","required":["place_id","primary_text"],"title":"AddressSuggestion","description":"One row of the list, as two lines of text and something to resolve."},"AddressSuggestionPick":{"properties":{"session_token":{"anyOf":[{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$"},{"type":"null"}],"title":"Session Token"},"language":{"anyOf":[{"type":"string","maxLength":16,"pattern":"^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$"},{"type":"null"}],"title":"Language"}},"type":"object","title":"AddressSuggestionPick","description":"The session a pick belongs to, and the language to answer it in.\n\nThe token matters here more than anywhere: Google bills a whole\nautocomplete session at the session rate only when the details call that\nends it carries the same token."},"AddressSuggestionQuery":{"properties":{"input":{"type":"string","maxLength":200,"minLength":1,"title":"Input"},"session_token":{"anyOf":[{"type":"string","maxLength":36,"pattern":"^[A-Za-z0-9_-]+$"},{"type":"null"}],"title":"Session Token"},"country_code":{"type":"string","maxLength":2,"minLength":2,"title":"Country Code","default":"US"},"language":{"anyOf":[{"type":"string","maxLength":16,"pattern":"^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$"},{"type":"null"}],"title":"Language"}},"type":"object","required":["input"],"title":"AddressSuggestionQuery","description":"What somebody has typed so far, and where they are typing it about."},"AddressSuggestions":{"properties":{"suggestions":{"items":{"$ref":"#/components/schemas/AddressSuggestion"},"type":"array","title":"Suggestions","default":[]},"available":{"type":"boolean","title":"Available","default":false}},"type":"object","title":"AddressSuggestions","description":"The list, and whether suggestions are working at all.\n\n`available` false with an empty list is the answer to every failure: no\nkey, a refusal, a timeout. Nobody waits on Google to type an address, so\nthere is no error shape here for a client to handle."},"AddressUpdate":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Label"},"address_type":{"anyOf":[{"type":"string","enum":["home","work","family","other"]},{"type":"null"}],"title":"Address Type"},"recipient_name":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Recipient Name"},"phone":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Phone"},"street1":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Street1"},"street2":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Street2"},"district":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"District"},"city":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"City"},"region":{"anyOf":[{"type":"string","maxLength":60,"minLength":1},{"type":"null"}],"title":"Region"},"postal_code":{"anyOf":[{"type":"string","maxLength":20,"minLength":1},{"type":"null"}],"title":"Postal Code"},"country_code":{"anyOf":[{"type":"string","maxLength":2,"minLength":2},{"type":"null"}],"title":"Country Code"}},"type":"object","title":"AddressUpdate"},"AddressValidationRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Recipient name"},"street1":{"type":"string","title":"Street1","description":"Street address"},"street2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Street2","description":"Apartment, suite, etc."},"city":{"type":"string","title":"City","description":"City"},"state":{"type":"string","maxLength":2,"minLength":2,"title":"State","description":"State code"},"zip":{"type":"string","title":"Zip","description":"ZIP code"},"country":{"type":"string","title":"Country","description":"Country code","default":"US"}},"type":"object","required":["name","street1","city","state","zip"],"title":"AddressValidationRequest","description":"Request to validate a shipping address"},"AddressValidationResponse":{"properties":{"is_valid":{"type":"boolean","title":"Is Valid","description":"Whether the address is valid"},"address_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Id","description":"Shippo address object ID for reuse"},"validation_messages":{"items":{"type":"string"},"type":"array","title":"Validation Messages","description":"Validation messages/warnings"},"suggested_address":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressBase"},{"type":"null"}],"description":"Suggested corrected address"}},"type":"object","required":["is_valid"],"title":"AddressValidationResponse","description":"Response from address validation"},"AddressVerdict":{"properties":{"status":{"type":"string","title":"Status","description":"'validated', or 'unavailable' when no verdict could be had"},"next_action":{"type":"string","title":"Next Action","description":"ACCEPT, CONFIRM, CONFIRM_ADD_SUBPREMISES, FIX or UNAVAILABLE"},"validation_source":{"type":"string","title":"Validation Source","description":"'google', or 'internal' when unavailable"},"verified":{"type":"boolean","title":"Verified","description":"True only for ACCEPT"},"standardized_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Standardized Address","description":"Google's formatted address"},"has_unconfirmed_components":{"type":"boolean","title":"Has Unconfirmed Components"},"response_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Response Id","description":"Google's response id, for a follow-up call"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Why no verdict, when unavailable"}},"type":"object","required":["status","next_action","validation_source","verified","has_unconfirmed_components"],"title":"AddressVerdict","description":"POST /addresses/validate: what Google's Address Validation said, or that\nit couldn't be asked. Advisory; see services/address_validation.py. No\nclient calls it yet."},"AdminDeletionReview":{"properties":{"approve":{"type":"boolean","title":"Approve","description":"True wipes the account's personal data; False declines the request"},"admin_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Notes","description":"Reviewer's note — required when declining, so the user can be told why"}},"type":"object","required":["approve"],"title":"AdminDeletionReview","description":"Schema for an admin approving or rejecting a deletion request"},"AdminDisputeItem":{"properties":{"id_order":{"type":"string","format":"uuid","title":"Id Order"},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id"},"status":{"type":"string","title":"Status"},"brief":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brief"},"delivery_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Note"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At"},"auto_accept_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Auto Accept At"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"disputed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Disputed At"},"dispute_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dispute Reason"},"resolution":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution"},"resolution_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution Note","description":"The admin's note on how a dispute was settled. Sent to admins only; null for the buyer and seller"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"buyer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Buyer Id"},"seller_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Seller Id"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"total_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Amount"},"total_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Charged","description":"What the buyer was charged for this order, processing fee included. Sent to the buyer only, once paid; null otherwise"},"sale_breakdown":{"anyOf":[{"$ref":"#/components/schemas/SaleBreakdown"},{"type":"null"}],"description":"Where the sale's money goes, as rows: the item's price, then the seller, the campaign, OpenGiving's fee and any processing fee the sale bore. Sent to the seller, and to the dispute desk that decides where this order's money goes (AdminDisputeItem); null for the buyer"},"buyer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Email"},"seller_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Email"}},"type":"object","required":["id_order","transaction_id","status"],"title":"AdminDisputeItem","description":"Dispute row for the admin view: adds contact emails, and carries\nsale_breakdown, which the desk needs to see what releasing would pay."},"AdminGivenGainMigrationRequest":{"properties":{"source_url":{"type":"string","title":"Source Url","description":"Original GivenGain campaign URL"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Organizer's email address (optional for mirrors)"},"consent_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Consent Reference","description":"Reference to consent documentation (e.g., Google Drive path)"},"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title","description":"Campaign title"},"description":{"type":"string","minLength":1,"title":"Description","description":"Campaign description"},"goal":{"type":"number","exclusiveMinimum":0.0,"title":"Goal","description":"Fundraising goal amount"},"location":{"type":"string","minLength":1,"title":"Location","description":"Campaign location"},"category_id":{"type":"string","title":"Category Id","description":"OpenGiving category ID"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name","description":"Organizer name from GivenGain"},"givengain_raised":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Givengain Raised","description":"Amount already raised on GivenGain"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"Image URLs scraped from GivenGain"}},"type":"object","required":["source_url","title","description","goal","location","category_id"],"title":"AdminGivenGainMigrationRequest","description":"Request schema for admin GivenGain mirror campaign migration (email optional)"},"AdminGivenGainMigrationResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the migration was successful","default":true},"campaign_id":{"type":"string","title":"Campaign Id","description":"Created campaign ID"},"campaign_ticker":{"type":"string","title":"Campaign Ticker","description":"Campaign ticker/slug"},"is_mirror":{"type":"boolean","title":"Is Mirror","description":"Whether this is a mirror campaign (no email)"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"User ID if email was provided"},"is_new_user":{"type":"boolean","title":"Is New User","description":"Whether a new account was created","default":false},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email address if provided"},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name","description":"Original organizer name from GivenGain"},"message":{"type":"string","title":"Message","description":"Success message"}},"type":"object","required":["campaign_id","campaign_ticker","is_mirror","message"],"title":"AdminGivenGainMigrationResponse","description":"Response schema for admin GivenGain mirror migration"},"AdminMirrorMigrationRequest":{"properties":{"source_url":{"type":"string","title":"Source Url","description":"Original GoFundMe campaign URL"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Organizer's email address (optional for mirrors)"},"consent_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Consent Reference","description":"Reference to consent documentation (e.g., Google Drive path)"},"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title","description":"Campaign title"},"description":{"type":"string","minLength":1,"title":"Description","description":"Campaign description"},"goal":{"type":"number","exclusiveMinimum":0.0,"title":"Goal","description":"Fundraising goal amount"},"location":{"type":"string","minLength":1,"title":"Location","description":"Campaign location"},"category_id":{"type":"string","title":"Category Id","description":"OpenGiving category ID"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name","description":"Organizer name from GoFundMe"},"gofundme_raised":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Gofundme Raised","description":"Amount already raised on GoFundMe"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"Image URLs scraped from GoFundMe"}},"type":"object","required":["source_url","title","description","goal","location","category_id"],"title":"AdminMirrorMigrationRequest","description":"Request schema for admin mirror campaign migration (email optional)"},"AdminMirrorMigrationResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the migration was successful","default":true},"campaign_id":{"type":"string","title":"Campaign Id","description":"Created campaign ID"},"campaign_ticker":{"type":"string","title":"Campaign Ticker","description":"Campaign ticker/slug"},"is_mirror":{"type":"boolean","title":"Is Mirror","description":"Whether this is a mirror campaign (no email)"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"User ID if email was provided"},"is_new_user":{"type":"boolean","title":"Is New User","description":"Whether a new account was created","default":false},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email address if provided"},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name","description":"Original organizer name from GoFundMe"},"message":{"type":"string","title":"Message","description":"Success message"}},"type":"object","required":["campaign_id","campaign_ticker","is_mirror","message"],"title":"AdminMirrorMigrationResponse","description":"Response schema for admin mirror migration"},"AdminReviewRequest":{"properties":{"status":{"$ref":"#/components/schemas/ReportStatus","description":"New status for the report"},"admin_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Notes","description":"Admin notes about the review"},"resolution":{"anyOf":[{"$ref":"#/components/schemas/ReportResolution"},{"type":"null"}],"description":"Resolution if status is resolved"}},"type":"object","required":["status"],"title":"AdminReviewRequest","description":"Schema for admin reviewing a report"},"AdminSaleRefund":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":1,"title":"Reason","description":"What the buyer asked for, in their words or yours"},"note":{"type":"string","maxLength":2000,"minLength":1,"title":"Note","description":"Why OpenGiving is refunding it. Kept as the admin note."},"take_back_payouts":{"type":"boolean","title":"Take Back Payouts","description":"Take back what the sale already paid out. False refunds the buyer and leaves the seller and the campaign what they were given, which OpenGiving then covers.","default":true}},"type":"object","required":["reason","note"],"title":"AdminSaleRefund","description":"An admin refunding a sale the buyer can no longer ask about.\n\nA buyer's own request closes when they confirm delivery, because\nconfirming pays the seller. What they're told instead is to write to\nsupport, and this is what support does about it."},"AppConfigResponse":{"properties":{"environment":{"type":"string","title":"Environment"},"stripe_mode":{"type":"string","title":"Stripe Mode"},"features":{"$ref":"#/components/schemas/FeatureFlags"},"limits":{"$ref":"#/components/schemas/MonetaryLimits"},"digital":{"$ref":"#/components/schemas/DigitalUploadPolicy"},"review_prompt":{"$ref":"#/components/schemas/ReviewPromptPolicy"},"payouts":{"$ref":"#/components/schemas/PayoutPolicy"},"escrow":{"$ref":"#/components/schemas/EscrowPolicy"},"localization":{"$ref":"#/components/schemas/LocalizationConfig"},"minimum_app_version":{"$ref":"#/components/schemas/MinimumAppVersion"},"addresses":{"$ref":"#/components/schemas/AddressBookConfig","default":{"enabled":false,"max_addresses":20,"autocomplete":false,"countries":["US"]}},"campaign_choice":{"$ref":"#/components/schemas/CampaignChoicePolicy","default":{"buyer_choice_enabled":false,"minimum_donation_pct":5,"maximum_donation_pct":100,"default_donation_pct":10}},"offers":{"$ref":"#/components/schemas/OfferPolicy","default":{"pending_hours":72,"accepted_hours":48,"max_pending_per_buyer":20}},"maintenance_mode":{"type":"boolean","title":"Maintenance Mode","default":false},"maintenance_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Maintenance Message"}},"type":"object","required":["environment","stripe_mode","features","limits","digital","review_prompt","payouts","escrow","localization","minimum_app_version"],"title":"AppConfigResponse","description":"Application configuration returned to mobile/web clients.\nFetched at app launch to configure client behavior."},"ArchiveChannelRequest":{"properties":{"archive":{"type":"boolean","title":"Archive"}},"type":"object","required":["archive"],"title":"ArchiveChannelRequest"},"BadgeCheckResult":{"properties":{"newly_earned_badges":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Newly Earned Badges","description":"List of badge IDs newly earned"},"total_xp_earned":{"type":"integer","title":"Total Xp Earned","description":"Total XP earned from new badges","default":0},"all_earned_badges":{"items":{"$ref":"#/components/schemas/EarnedBadge"},"type":"array","title":"All Earned Badges","description":"All badges currently earned by user"}},"type":"object","title":"BadgeCheckResult","description":"Result of checking badge eligibility"},"BadgeDefinition":{"properties":{"id_badge":{"type":"string","format":"uuid","title":"Id Badge","description":"Unique identifier of the badge"},"name":{"type":"string","maxLength":100,"title":"Name","description":"Name of the badge"},"description":{"type":"string","title":"Description","description":"Description of how to earn this badge"},"category":{"type":"string","maxLength":50,"title":"Category","description":"Badge category: milestone, category, streak, or special"},"criteria_type":{"type":"string","maxLength":50,"title":"Criteria Type","description":"Type of criteria: total_donated, category_donated, streak_days, etc."},"criteria_category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Criteria Category Id","description":"Category ID for category-specific badges"},"criteria_threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Criteria Threshold","description":"Amount or count needed to earn this badge"},"icon_name":{"type":"string","maxLength":100,"title":"Icon Name","description":"Emoji, kept for app builds that draw it as text. New clients draw `icon`."},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set"},"color_hex":{"type":"string","maxLength":7,"title":"Color Hex","description":"Badge color in hex format"},"rarity":{"type":"string","maxLength":20,"title":"Rarity","description":"Badge rarity: common, rare, epic, legendary"},"xp_reward":{"type":"integer","title":"Xp Reward","description":"XP earned when badge is unlocked","default":0},"display_order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Display Order","description":"Order for displaying badges"},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the badge is currently active","default":true},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the badge was created"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the badge was last updated"}},"type":"object","required":["id_badge","name","description","category","criteria_type","icon_name","color_hex","rarity","created_at"],"title":"BadgeDefinition","description":"Badge definition with timestamps"},"BadgeProgress":{"properties":{"badge_definition":{"$ref":"#/components/schemas/BadgeDefinition"},"current_value":{"type":"number","title":"Current Value","description":"User's current value for this badge criteria"},"required_value":{"type":"number","title":"Required Value","description":"Value required to earn the badge"},"progress_percentage":{"type":"number","title":"Progress Percentage","description":"Progress percentage (0-100)"},"is_earned":{"type":"boolean","title":"Is Earned","description":"Whether the badge has been earned"},"earned_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earned At","description":"When earned (if applicable)"}},"type":"object","required":["badge_definition","current_value","required_value","progress_percentage","is_earned"],"title":"BadgeProgress","description":"Progress towards earning a badge"},"Body_unsubscribe_confirm_api_v1_unsubscribe_confirm_post":{"properties":{"token":{"type":"string","title":"Token","default":""}},"type":"object","title":"Body_unsubscribe_confirm_api_v1_unsubscribe_confirm_post"},"Body_unsubscribe_one_click_api_v1_unsubscribe__post":{"properties":{"token":{"type":"string","title":"Token","default":""}},"type":"object","title":"Body_unsubscribe_one_click_api_v1_unsubscribe__post"},"Body_unsubscribe_one_click_api_v1_unsubscribe_post":{"properties":{"token":{"type":"string","title":"Token","default":""}},"type":"object","title":"Body_unsubscribe_one_click_api_v1_unsubscribe_post"},"Body_upload_campaign_image_api_v1_images_upload_campaign__campaign_id__post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_campaign_image_api_v1_images_upload_campaign__campaign_id__post"},"Body_upload_campaign_multi_image_api_v1_images_campaign__campaign_id__images_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"is_primary":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Primary","default":false},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text"}},"type":"object","required":["file"],"title":"Body_upload_campaign_multi_image_api_v1_images_campaign__campaign_id__images_post"},"Body_upload_campaign_update_image_api_v1_images_campaign_update__update_id__images_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"is_primary":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Primary","default":false},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text"}},"type":"object","required":["file"],"title":"Body_upload_campaign_update_image_api_v1_images_campaign_update__update_id__images_post"},"Body_upload_product_image_api_v1_images_upload_product__product_id__post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_product_image_api_v1_images_upload_product__product_id__post"},"Body_upload_product_multi_image_api_v1_images_product__product_id__images_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"is_primary":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Primary","default":false},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text"}},"type":"object","required":["file"],"title":"Body_upload_product_multi_image_api_v1_images_product__product_id__images_post"},"Body_upload_profile_picture_api_v1_images_upload_profile_picture_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_profile_picture_api_v1_images_upload_profile_picture_post"},"BulkMagicListingRequest":{"properties":{"images_base64":{"items":{"type":"string"},"type":"array","title":"Images Base64","description":"Base64-encoded images of products (1-20 images)"},"user_context":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"User Context","description":"Optional context about all items (e.g., 'Vintage items from estate sale')"}},"type":"object","required":["images_base64"],"title":"BulkMagicListingRequest","description":"Request schema for bulk AI-powered magic listing generation"},"BulkMagicListingResponse":{"properties":{"detected_items":{"items":{"$ref":"#/components/schemas/DetectedItem"},"type":"array","title":"Detected Items","description":"List of detected items with their listings"},"ungrouped_image_indices":{"items":{"type":"integer"},"type":"array","title":"Ungrouped Image Indices","description":"Image indices that couldn't be confidently assigned"},"processing_time_ms":{"type":"integer","title":"Processing Time Ms","description":"Total processing time in milliseconds"}},"type":"object","required":["detected_items","processing_time_ms"],"title":"BulkMagicListingResponse","description":"Response schema for bulk AI-generated listing data"},"BulkPushNotificationRequest":{"properties":{"user_ids":{"items":{"type":"string"},"type":"array","title":"User Ids","description":"List of user IDs to send to"},"title":{"type":"string","title":"Title","description":"Notification title"},"body":{"type":"string","title":"Body","description":"Notification body"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon","description":"Notification icon URL"},"image":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image","description":"Notification image URL"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"URL to open when clicked"},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag","description":"Notification tag for grouping"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Notification type","default":"default"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority","description":"Notification priority","default":"normal"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"Additional data payload"}},"type":"object","required":["user_ids","title","body"],"title":"BulkPushNotificationRequest","description":"Schema for sending bulk push notifications."},"BuyerPaysRow":{"properties":{"kind":{"type":"string","enum":["items","tip","digital_fee","shipping"],"title":"Kind","description":"items: every item's price together. tip: the tip to OpenGiving. digital_fee: the flat fee digital items carry. shipping: the postage. Rows that come to nothing aren't sent, except items"},"amount_cents":{"type":"integer","title":"Amount Cents"}},"type":"object","required":["kind","amount_cents"],"title":"BuyerPaysRow","description":"Something the buyer pays for, whichever rail they pay with."},"BuyerRefundRequest":{"properties":{"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"}},"type":"object","required":["reason"],"title":"BuyerRefundRequest","description":"Schema for buyer/donor refund requests"},"Campaign":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the campaign"},"description":{"type":"string","title":"Description","description":"Description of the campaign"},"goal":{"type":"number","minimum":0.0,"title":"Goal","description":"Goal of the campaign"},"raised":{"type":"number","minimum":0.0,"title":"Raised","description":"Raised amount of the campaign","default":0},"ticker":{"type":"string","title":"Ticker","description":"Ticker of the campaign"},"location":{"type":"string","title":"Location","description":"Location of the campaign"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the campaign's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the campaign's location"},"id_campaign":{"type":"string","format":"uuid","title":"Id Campaign","description":"Unique identifier of the campaign"},"organizer_id":{"type":"string","format":"uuid","title":"Organizer Id","description":"Unique identifier of the organizer"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the campaign"},"status":{"type":"string","title":"Status","description":"Status of the campaign"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active","description":"Whether the campaign is active","default":true},"accepts_donations":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Accepts Donations","description":"Whether the campaign accepts donations","default":true},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"},"is_mirror":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Mirror","description":"Whether this is a mirror campaign","default":false},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name","description":"Original organizer name from source platform"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url","description":"Original campaign URL"},"gofundme_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gofundme Raised","description":"Amount raised on GoFundMe"},"gofundme_raised_updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gofundme Raised Updated At","description":"When GoFundMe raised amount was last updated"},"givengain_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Givengain Raised","description":"Amount raised on GivenGain"},"givengain_raised_updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Givengain Raised Updated At","description":"When GivenGain raised amount was last updated"}},"type":"object","required":["title","description","goal","ticker","location","id_campaign","organizer_id","category_id","status"],"title":"Campaign","description":"Schema for campaign responses (includes DB-generated fields)"},"CampaignCategory":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","description":"Category name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Category description"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for UI","default":0},"is_active":{"type":"boolean","title":"Is Active","description":"Whether category is active","default":true},"icon":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set; null draws the client's fallback"},"id_category":{"type":"string","format":"uuid","title":"Id Category","description":"Unique identifier of the category"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["name","id_category","created_at","updated_at"],"title":"CampaignCategory","description":"Campaign category"},"CampaignCategoryCreate":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","description":"Category name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Category description"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for UI","default":0},"is_active":{"type":"boolean","title":"Is Active","description":"Whether category is active","default":true},"icon":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set; null draws the client's fallback"}},"type":"object","required":["name"],"title":"CampaignCategoryCreate","description":"Campaign category creation"},"CampaignChoicePolicy":{"properties":{"buyer_choice_enabled":{"type":"boolean","title":"Buyer Choice Enabled"},"minimum_donation_pct":{"type":"integer","title":"Minimum Donation Pct"},"maximum_donation_pct":{"type":"integer","title":"Maximum Donation Pct"},"default_donation_pct":{"type":"integer","title":"Default Donation Pct"}},"type":"object","required":["buyer_choice_enabled","minimum_donation_pct","maximum_donation_pct","default_donation_pct"],"title":"CampaignChoicePolicy","description":"A listing that names no campaign, and what its buyer may choose.\n\nFour surfaces have to agree about this: whether a seller may create such a\nlisting at all, where the buyer's slider starts, where it stops, and what\nit opens at. Compiled into each client, that is four copies of three\nnumbers, which is how the donation floor drifted the last time -- web\nenforced one figure in five forms, Android allowed a one-cent listing and\niOS enforced nothing.\n\n`buyer_choice_enabled` is the switch. Off until every surface can both\ncreate such a listing and buy one: campaign_id and donation_pct are\nnon-null in every released client's model, so a listing without them\ncannot be decoded by any build that predates this. Flipping it is the\nlaunch, and the rollback is one environment variable.\n\n`default_donation_pct` is where the chooser opens. It is a product\ndecision -- where a buyer starts is most of where they finish -- so it is\na server value rather than a number three app releases would have to move\ntogether."},"CampaignCountCeiling":{"properties":{"campaigns":{"type":"integer","title":"Campaigns"},"alert_at":{"type":"integer","title":"Alert At"},"ceiling":{"type":"integer","title":"Ceiling"},"detail":{"type":"string","title":"Detail"}},"type":"object","required":["campaigns","alert_at","ceiling","detail"],"title":"CampaignCountCeiling"},"CampaignCreate":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the campaign"},"description":{"type":"string","title":"Description","description":"Description of the campaign"},"goal":{"type":"number","minimum":0.0,"title":"Goal","description":"Goal of the campaign"},"raised":{"type":"number","minimum":0.0,"title":"Raised","description":"Raised amount of the campaign","default":0},"ticker":{"type":"string","title":"Ticker","description":"Ticker of the campaign"},"location":{"type":"string","title":"Location","description":"Location of the campaign"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the campaign's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the campaign's location"},"organizer_id":{"type":"string","format":"uuid","title":"Organizer Id","description":"Unique identifier of the organizer"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the campaign"}},"type":"object","required":["title","description","goal","ticker","location","organizer_id","category_id"],"title":"CampaignCreate","description":"Schema for creating a campaign (client request payload)"},"CampaignDeactivationRequest":{"properties":{"reason":{"$ref":"#/components/schemas/DeactivationReason"},"explanation":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Explanation","description":"Additional explanation for deactivation"},"refund_policy":{"$ref":"#/components/schemas/RefundPolicy","default":"full_refund"},"notify_donors":{"type":"boolean","title":"Notify Donors","description":"Whether to notify donors about the deactivation","default":true},"confirm_understanding":{"type":"boolean","title":"Confirm Understanding","description":"Confirmation that user understands the consequences","default":true}},"type":"object","required":["reason"],"title":"CampaignDeactivationRequest","description":"Request schema for campaign deactivation"},"CampaignDeactivationResponse":{"properties":{"campaign_id":{"type":"string","title":"Campaign Id"},"previous_status":{"type":"string","title":"Previous Status"},"new_status":{"type":"string","title":"New Status"},"deactivated_at":{"type":"string","title":"Deactivated At"},"reason":{"$ref":"#/components/schemas/DeactivationReason"},"explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation"},"refund_policy":{"$ref":"#/components/schemas/RefundPolicy"},"total_raised":{"type":"number","title":"Total Raised"},"donor_count":{"type":"integer","title":"Donor Count"},"refund_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Refund Amount"},"message":{"type":"string","title":"Message"}},"type":"object","required":["campaign_id","previous_status","new_status","deactivated_at","reason","explanation","refund_policy","total_raised","donor_count","message"],"title":"CampaignDeactivationResponse","description":"Response schema for campaign deactivation"},"CampaignImage":{"properties":{"id_image":{"type":"string","title":"Id Image","description":"Unique identifier of the image"},"image_url":{"type":"string","title":"Image Url","description":"URL of the image"},"display_order":{"type":"integer","title":"Display Order","description":"Display order of the image"},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this is the primary image"},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text","description":"Alt text for the image"},"file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size","description":"File size in bytes"},"file_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type","description":"MIME type of the file"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"Image width in pixels"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"Image height in pixels"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["id_image","image_url","display_order","is_primary"],"title":"CampaignImage","description":"Schema for campaign images"},"CampaignInquiryRequest":{"properties":{"organizer_id":{"type":"string","title":"Organizer Id"},"campaign_id":{"type":"string","title":"Campaign Id"},"campaign_name":{"type":"string","title":"Campaign Name"}},"type":"object","required":["organizer_id","campaign_id","campaign_name"],"title":"CampaignInquiryRequest"},"CampaignNotificationTest":{"properties":{"message":{"type":"string","title":"Message"},"campaign_id":{"type":"string","title":"Campaign Id"},"notification_id":{"type":"string","title":"Notification Id"},"recipient":{"type":"string","title":"Recipient","description":"The id of the user notified: the caller"}},"type":"object","required":["message","campaign_id","notification_id","recipient"],"title":"CampaignNotificationTest","description":"POST /campaigns/{id}/test-creation-notification (a dev tool). No client calls it."},"CampaignRaisedDrift":{"properties":{"campaign_id":{"type":"string","title":"Campaign Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"cached":{"type":"number","title":"Cached"},"derived":{"type":"number","title":"Derived"},"drift":{"type":"number","title":"Drift"}},"type":"object","required":["campaign_id","cached","derived","drift"],"title":"CampaignRaisedDrift"},"CampaignRaisedRecalculation":{"properties":{"message":{"type":"string","title":"Message"},"campaign_id":{"type":"string","title":"Campaign Id"},"previous_raised":{"type":"number","title":"Previous Raised","description":"What the campaign's raised column said before"},"new_raised":{"type":"number","title":"New Raised","description":"What it says now"},"contribution_count":{"type":"integer","title":"Contribution Count","description":"Completed, active donations to the campaign"}},"type":"object","required":["message","campaign_id","previous_raised","new_raised","contribution_count"],"title":"CampaignRaisedRecalculation","description":"POST /direct_contributions/recalculate-campaign/{id}. No client calls it."},"CampaignReportCreate":{"properties":{"report_category":{"$ref":"#/components/schemas/ReportCategory","description":"Category of the report"},"description":{"type":"string","maxLength":2000,"minLength":20,"title":"Description","description":"Detailed description of the issue"}},"type":"object","required":["report_category","description"],"title":"CampaignReportCreate","description":"Schema for creating a campaign report"},"CampaignReportListResponse":{"properties":{"reports":{"items":{"$ref":"#/components/schemas/CampaignReportWithDetails"},"type":"array","title":"Reports"},"total":{"type":"integer","title":"Total"},"page":{"type":"integer","title":"Page"},"limit":{"type":"integer","title":"Limit"},"total_pages":{"type":"integer","title":"Total Pages"}},"type":"object","required":["reports","total","page","limit","total_pages"],"title":"CampaignReportListResponse","description":"Paginated list of campaign reports"},"CampaignReportResponse":{"properties":{"id_report":{"type":"string","format":"uuid","title":"Id Report"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id"},"reporter_id":{"type":"string","format":"uuid","title":"Reporter Id"},"report_category":{"type":"string","title":"Report Category"},"description":{"type":"string","title":"Description"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"resolution":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id_report","campaign_id","reporter_id","report_category","description","status","created_at"],"title":"CampaignReportResponse","description":"Response schema for a campaign report"},"CampaignReportStats":{"properties":{"total":{"type":"integer","title":"Total","default":0},"pending":{"type":"integer","title":"Pending","default":0},"under_review":{"type":"integer","title":"Under Review","default":0},"resolved":{"type":"integer","title":"Resolved","default":0},"dismissed":{"type":"integer","title":"Dismissed","default":0}},"type":"object","title":"CampaignReportStats","description":"Statistics for campaign reports (admin dashboard)"},"CampaignReportWithDetails":{"properties":{"id_report":{"type":"string","format":"uuid","title":"Id Report"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id"},"reporter_id":{"type":"string","format":"uuid","title":"Reporter Id"},"report_category":{"type":"string","title":"Report Category"},"description":{"type":"string","title":"Description"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"resolution":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Ticker"},"reporter_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reporter Name"},"reporter_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reporter Email"},"reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reviewer Name"}},"type":"object","required":["id_report","campaign_id","reporter_id","report_category","description","status","created_at"],"title":"CampaignReportWithDetails","description":"Report with campaign and reporter details for admin view"},"CampaignStats":{"properties":{"total_count":{"type":"integer","title":"Total Count"},"active_count":{"type":"integer","title":"Active Count"},"total_raised":{"type":"number","title":"Total Raised"}},"type":"object","required":["total_count","active_count","total_raised"],"title":"CampaignStats","description":"Platform-wide campaign totals, computed server-side.\n\nExists because the clients computed these by fetching every campaign and\nadding up the rows. That is one request whose size grows with the platform,\nand `/campaigns/` caps `limit` at 100 -- so the request 422s the moment the\nhundredth campaign is created, on builds already in the app stores."},"CampaignSummary":{"properties":{"id_campaign":{"type":"string","format":"uuid","title":"Id Campaign"},"title":{"type":"string","title":"Title"},"ticker":{"type":"string","title":"Ticker"},"description":{"type":"string","title":"Description"},"goal":{"type":"number","title":"Goal"},"raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Raised","default":0.0},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"category_id":{"type":"string","format":"uuid","title":"Category Id"},"category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category Name"},"primary_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Image Url"}},"type":"object","required":["id_campaign","title","ticker","description","goal","category_id"],"title":"CampaignSummary","description":"Minimal campaign info for pinned campaigns list"},"CampaignTotal":{"properties":{"campaign_id":{"type":"string","title":"Campaign Id"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title","description":"The campaign's name, when the listing's campaign is on record. A client draws \"Goes to <name>\" with it, and a plainer line without it"},"amount_cents":{"type":"integer","title":"Amount Cents"}},"type":"object","required":["campaign_id","amount_cents"],"title":"CampaignTotal","description":"What one campaign gets out of the whole order."},"CampaignUpdate":{"properties":{"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"ID of the campaign this update belongs to"},"title":{"type":"string","maxLength":255,"title":"Title","description":"Title of the update"},"content":{"type":"string","title":"Content","description":"Content of the update"},"id_update":{"type":"string","format":"uuid","title":"Id Update","description":"Unique identifier of the update"},"images":{"items":{"$ref":"#/components/schemas/CampaignUpdateImage"},"type":"array","title":"Images","description":"Images associated with this update"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["campaign_id","title","content","id_update","created_at"],"title":"CampaignUpdate","description":"Schema for campaign update responses"},"CampaignUpdateCreate":{"properties":{"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"ID of the campaign this update belongs to"},"title":{"type":"string","maxLength":255,"title":"Title","description":"Title of the update"},"content":{"type":"string","title":"Content","description":"Content of the update"}},"type":"object","required":["campaign_id","title","content"],"title":"CampaignUpdateCreate","description":"Schema for creating a campaign update"},"CampaignUpdateImage":{"properties":{"image_url":{"type":"string","title":"Image Url","description":"URL of the image"},"display_order":{"type":"integer","title":"Display Order","description":"Display order of the image","default":1},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this is the primary image","default":false},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text","description":"Alternative text for the image"},"id_image":{"type":"string","format":"uuid","title":"Id Image","description":"Unique identifier of the image"},"update_id":{"type":"string","format":"uuid","title":"Update Id","description":"ID of the update this image belongs to"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["image_url","id_image","update_id"],"title":"CampaignUpdateImage","description":"Schema for campaign update image responses"},"CampaignUpdateImageDeleted":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"},"image_id":{"type":"string","title":"Image Id"}},"type":"object","required":["success","message","image_id"],"title":"CampaignUpdateImageDeleted","description":"DELETE /images/campaign_update/{update_id}/images/{image_id}."},"CampaignUpdateImageList":{"properties":{"entity_id":{"type":"string","title":"Entity Id","description":"The update's id"},"entity_type":{"type":"string","title":"Entity Type","description":"Always 'campaign_update'"},"total_count":{"type":"integer","title":"Total Count"},"images":{"items":{"$ref":"#/components/schemas/UpdateImageDetails"},"type":"array","title":"Images"}},"type":"object","required":["entity_id","entity_type","total_count","images"],"title":"CampaignUpdateImageList","description":"GET /images/campaign_update/{update_id}/images."},"CampaignUpdateImageUploaded":{"properties":{"url":{"type":"string","title":"Url","description":"CloudFront URL of the uploaded image"},"image_id":{"type":"string","title":"Image Id"},"entity_id":{"type":"string","title":"Entity Id","description":"The update's id"},"is_primary":{"type":"boolean","title":"Is Primary"},"display_order":{"type":"integer","title":"Display Order"}},"type":"object","required":["url","image_id","entity_id","is_primary","display_order"],"title":"CampaignUpdateImageUploaded","description":"POST /images/campaign_update/{update_id}/images. iOS\n(ImageUploadResponse) requires `url`; web ignores the body."},"CampaignUpdateImagesReordered":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","message"],"title":"CampaignUpdateImagesReordered","description":"POST /images/campaign_update/{update_id}/images/reorder."},"CampaignUpdatePrimaryImage":{"properties":{"success":{"type":"boolean","title":"Success"},"entity_id":{"type":"string","title":"Entity Id","description":"The update's id"},"primary_image":{"$ref":"#/components/schemas/UpdateImageDetails"}},"type":"object","required":["success","entity_id","primary_image"],"title":"CampaignUpdatePrimaryImage","description":"POST /images/campaign_update/{update_id}/images/set-primary."},"CampaignWithDetails":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the campaign"},"description":{"type":"string","title":"Description","description":"Description of the campaign"},"goal":{"type":"number","minimum":0.0,"title":"Goal","description":"Goal of the campaign"},"raised":{"type":"number","minimum":0.0,"title":"Raised","description":"Raised amount of the campaign","default":0},"ticker":{"type":"string","title":"Ticker","description":"Ticker of the campaign"},"location":{"type":"string","title":"Location","description":"Location of the campaign"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the campaign's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the campaign's location"},"id_campaign":{"type":"string","format":"uuid","title":"Id Campaign","description":"Unique identifier of the campaign"},"organizer_id":{"type":"string","format":"uuid","title":"Organizer Id","description":"Unique identifier of the organizer"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the campaign"},"status":{"type":"string","title":"Status","description":"Status of the campaign"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active","description":"Whether the campaign is active","default":true},"accepts_donations":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Accepts Donations","description":"Whether the campaign accepts donations","default":true},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"},"is_mirror":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Mirror","description":"Whether this is a mirror campaign","default":false},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name","description":"Original organizer name from source platform"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url","description":"Original campaign URL"},"gofundme_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gofundme Raised","description":"Amount raised on GoFundMe"},"gofundme_raised_updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gofundme Raised Updated At","description":"When GoFundMe raised amount was last updated"},"givengain_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Givengain Raised","description":"Amount raised on GivenGain"},"givengain_raised_updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Givengain Raised Updated At","description":"When GivenGain raised amount was last updated"},"organizer":{"$ref":"#/components/schemas/UserPublic"},"category":{"$ref":"#/components/schemas/CampaignCategory"},"images":{"items":{"$ref":"#/components/schemas/CampaignImage"},"type":"array","title":"Images","description":"Campaign images"}},"type":"object","required":["title","description","goal","ticker","location","id_campaign","organizer_id","category_id","status","organizer","category"],"title":"CampaignWithDetails","description":"Campaign with organizer and category details"},"CampaignWithOrganizer":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the campaign"},"description":{"type":"string","title":"Description","description":"Description of the campaign"},"goal":{"type":"number","minimum":0.0,"title":"Goal","description":"Goal of the campaign"},"raised":{"type":"number","minimum":0.0,"title":"Raised","description":"Raised amount of the campaign","default":0},"ticker":{"type":"string","title":"Ticker","description":"Ticker of the campaign"},"location":{"type":"string","title":"Location","description":"Location of the campaign"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the campaign's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the campaign's location"},"id_campaign":{"type":"string","format":"uuid","title":"Id Campaign","description":"Unique identifier of the campaign"},"organizer_id":{"type":"string","format":"uuid","title":"Organizer Id","description":"Unique identifier of the organizer"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the campaign"},"status":{"type":"string","title":"Status","description":"Status of the campaign"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active","description":"Whether the campaign is active","default":true},"accepts_donations":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Accepts Donations","description":"Whether the campaign accepts donations","default":true},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"},"is_mirror":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Mirror","description":"Whether this is a mirror campaign","default":false},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name","description":"Original organizer name from source platform"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url","description":"Original campaign URL"},"gofundme_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gofundme Raised","description":"Amount raised on GoFundMe"},"gofundme_raised_updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gofundme Raised Updated At","description":"When GoFundMe raised amount was last updated"},"givengain_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Givengain Raised","description":"Amount raised on GivenGain"},"givengain_raised_updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Givengain Raised Updated At","description":"When GivenGain raised amount was last updated"},"organizer":{"$ref":"#/components/schemas/UserPublic"}},"type":"object","required":["title","description","goal","ticker","location","id_campaign","organizer_id","category_id","status","organizer"],"title":"CampaignWithOrganizer","description":"Campaign with organizer details"},"CanLeaveFeedbackResponse":{"properties":{"can_leave_feedback":{"type":"boolean","title":"Can Leave Feedback"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","required":["can_leave_feedback"],"title":"CanLeaveFeedbackResponse"},"CaptureOrderRequest":{"properties":{"order_id":{"type":"string","title":"Order Id","description":"PayPal order id returned by create-order"}},"type":"object","required":["order_id"],"title":"CaptureOrderRequest"},"CaptureOrderResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"contribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contribution Id"},"transaction_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transaction Id"},"checkout_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkout Session Id"},"amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount"},"already_captured":{"type":"boolean","title":"Already Captured","default":false}},"type":"object","required":["success"],"title":"CaptureOrderResponse"},"CartOrderRequest":{"properties":{"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"e.g. opengiving://paypal-return"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url","description":"e.g. opengiving://paypal-cancel"},"items":{"items":{"$ref":"#/components/schemas/CheckoutItem"},"type":"array","maxItems":50,"minItems":1,"title":"Items","description":"Items to checkout"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional platform tip","default":"0"},"shipping_address":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSchema"},{"type":"null"}],"description":"Shipping address (required only if any item is shippable)"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id","description":"Use a saved address instead of the inline one"},"customer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email","description":"Customer email for receipt"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Keep the buyer's name off each campaign's public donor list","default":false}},"type":"object","required":["items"],"title":"CartOrderRequest","description":"A cart checkout, plus where to send the payer back to (apps only)."},"CartOrderResponse":{"properties":{"order_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Order Value"},"processing_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Processing Fee"},"total_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Charged"},"order_id":{"type":"string","title":"Order Id"},"checkout_session_id":{"type":"string","title":"Checkout Session Id"},"total_amount":{"type":"number","title":"Total Amount"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"approve_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approve Url"}},"type":"object","required":["order_id","checkout_session_id","total_amount"],"title":"CartOrderResponse"},"CategorySuggestion":{"properties":{"suggestion_type":{"$ref":"#/components/schemas/SuggestionType"},"category_name":{"type":"string","maxLength":100,"title":"Category Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"id_suggestion":{"type":"string","format":"uuid","title":"Id Suggestion"},"suggested_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Suggested By"},"suggested_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested By Email"},"suggested_by_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested By Name"},"status":{"$ref":"#/components/schemas/SuggestionStatus"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes","description":"The reviewing admin's notes. Sent to admins only; null for the person who made the suggestion"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"reviewed_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reviewed By","description":"The reviewing admin's user id. Sent to admins only; null for the person who made the suggestion"}},"type":"object","required":["suggestion_type","category_name","id_suggestion","status","created_at"],"title":"CategorySuggestion"},"CategorySuggestionCreate":{"properties":{"suggestion_type":{"$ref":"#/components/schemas/SuggestionType"},"category_name":{"type":"string","maxLength":100,"title":"Category Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["suggestion_type","category_name"],"title":"CategorySuggestionCreate"},"CategorySuggestionUpdate":{"properties":{"status":{"anyOf":[{"$ref":"#/components/schemas/SuggestionStatus"},{"type":"null"}]},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"}},"type":"object","title":"CategorySuggestionUpdate"},"ChannelArchived":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"},"channel_id":{"type":"string","title":"Channel Id"},"archived":{"type":"boolean","title":"Archived"}},"type":"object","required":["success","message","channel_id","archived"],"title":"ChannelArchived","description":"PATCH /chat/channels/{id}/archive. No client calls it."},"ChannelList":{"properties":{"channels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Channels"}},"type":"object","required":["channels"],"title":"ChannelList","description":"GET /chat/channels. Each channel is Stream's own object, passed on as\nStream's query_channels returns it. No client calls this route: the apps\nlist channels with Stream's SDKs."},"ChannelPinned":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"},"channel_id":{"type":"string","title":"Channel Id"},"pinned":{"type":"boolean","title":"Pinned"}},"type":"object","required":["success","message","channel_id","pinned"],"title":"ChannelPinned","description":"PATCH /chat/channels/{id}/pin. No client calls it."},"ChannelRequest":{"properties":{"seller_id":{"type":"string","title":"Seller Id"},"product_id":{"type":"string","title":"Product Id"},"product_name":{"type":"string","title":"Product Name"}},"type":"object","required":["seller_id","product_id","product_name"],"title":"ChannelRequest"},"ChannelResponse":{"properties":{"channel_id":{"type":"string","title":"Channel Id"},"channel_type":{"type":"string","title":"Channel Type"},"members":{"items":{"type":"string"},"type":"array","title":"Members"}},"type":"object","required":["channel_id","channel_type","members"],"title":"ChannelResponse"},"ChatTokenResponse":{"properties":{"token":{"type":"string","title":"Token"},"api_key":{"type":"string","title":"Api Key"},"user_id":{"type":"string","title":"User Id"}},"type":"object","required":["token","api_key","user_id"],"title":"ChatTokenResponse"},"CheckoutItem":{"properties":{"product_id":{"type":"string","title":"Product Id","description":"Product ID to purchase"},"quantity":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Quantity","description":"Quantity (currently only 1 supported)","default":1},"shipping_rate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Rate Id","description":"Shippo rate id from /shipping/rates for this item"},"shipping_shipment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Shipment Id","description":"Shippo shipment id the rate was quoted under"},"campaign_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Id","description":"The campaign the buyer chose, for a listing that names none"},"donation_pct":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Pct","description":"The share of the price the buyer chose to give, for a listing that names none"},"offer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Offer Id","description":"An accepted offer to buy this line at"}},"type":"object","required":["product_id"],"title":"CheckoutItem","description":"Single item in checkout request"},"CheckoutSessionRequest":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CheckoutItem"},"type":"array","maxItems":50,"minItems":1,"title":"Items","description":"Items to checkout"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional platform tip","default":"0"},"shipping_address":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSchema"},{"type":"null"}],"description":"Shipping address (required only if any item is shippable)"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id","description":"Use a saved address instead of the inline one"},"customer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email","description":"Customer email for receipt"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Keep the buyer's name off each campaign's public donor list","default":false}},"type":"object","required":["items"],"title":"CheckoutSessionRequest","description":"Request to create a consolidated checkout session"},"CheckoutSessionResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"Checkout session ID"},"payment_intent_id":{"type":"string","title":"Payment Intent Id","description":"Stripe PaymentIntent ID"},"client_secret":{"type":"string","title":"Client Secret","description":"Client secret for Stripe Elements"},"total_amount":{"type":"number","title":"Total Amount","description":"Total amount to charge (including tip)"},"subtotal":{"type":"number","title":"Subtotal","description":"Subtotal before tip"},"platform_tip":{"type":"number","title":"Platform Tip","description":"Platform tip amount"},"items_breakdown":{"items":{"$ref":"#/components/schemas/ItemBreakdown"},"type":"array","title":"Items Breakdown","description":"Breakdown per item"},"fee_summary":{"$ref":"#/components/schemas/FeeSummary","description":"Fee summary"}},"type":"object","required":["session_id","payment_intent_id","client_secret","total_amount","subtotal","platform_tip","items_breakdown","fee_summary"],"title":"CheckoutSessionResponse","description":"Response after creating checkout session. Money goes out as JSON\nnumbers: web reads numbers, and iOS decodes total_amount as a Double."},"CityList":{"properties":{"cities":{"items":{"$ref":"#/components/schemas/Place"},"type":"array","title":"Cities"}},"type":"object","required":["cities"],"title":"CityList","description":"GET /geography/cities. iOS (CitiesResponse) requires `cities` and each\ncity's name and code; web reads `cities[].name`."},"ClaimCompleteResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id"},"campaign_ticker":{"type":"string","title":"Campaign Ticker"},"new_owner_id":{"type":"string","format":"uuid","title":"New Owner Id"},"transferred_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Transferred Amount","description":"Money raised before the claim that moved into the claimant's wallet, if any"}},"type":"object","required":["success","message","campaign_id","campaign_ticker","new_owner_id"],"title":"ClaimCompleteResponse","description":"Response after completing a claim."},"ClaimEmailResend":{"properties":{"send_to_email":{"type":"string","format":"email","title":"Send To Email","description":"Email the claim link to this address"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name","description":"Name to greet the recipient by"}},"type":"object","required":["send_to_email"],"title":"ClaimEmailResend","description":"Request to email an existing claim link again."},"ClaimEmailResult":{"properties":{"id_claim_token":{"type":"string","format":"uuid","title":"Id Claim Token"},"email_sent":{"type":"boolean","title":"Email Sent"},"email_failure":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email Failure","description":"Why it wasn't sent: 'suppressed' or 'failed', as on ClaimTokenCreated"}},"type":"object","required":["id_claim_token","email_sent"],"title":"ClaimEmailResult","description":"Whether a claim link went out by email."},"ClaimFundsTransferResult":{"properties":{"status":{"type":"string","title":"Status","description":"transferred | dry_run | nothing_to_move | already_transferred | no_wallet"},"from_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From User Id"},"to_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To User Id"},"credited":{"type":"number","title":"Credited","description":"What this campaign put into the previous organizer's wallet","default":0},"refunded":{"type":"number","title":"Refunded","description":"Refunds of those donations already deducted there","default":0},"available":{"type":"number","title":"Available","description":"That wallet's available balance at the time","default":0},"amount":{"type":"number","title":"Amount","description":"What moved, or would move","default":0},"capped":{"type":"boolean","title":"Capped","description":"True when withdrawals had already consumed part of it","default":false},"held_moved":{"type":"integer","title":"Held Moved","description":"Card shares of this campaign that were held for the previous organizer and now belong to the claimant. Nothing moved: the money is in the platform's Stripe balance either way.","default":0}},"type":"object","required":["status"],"title":"ClaimFundsTransferResult","description":"What moving a claimed campaign's money did, or would do (dry run)."},"ClaimInitiateRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"Email address of the claimant"},"name":{"type":"string","maxLength":255,"minLength":2,"title":"Name","description":"Full name of the claimant"}},"type":"object","required":["email","name"],"title":"ClaimInitiateRequest","description":"Request to initiate a claim (public endpoint)."},"ClaimInitiateResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"},"verification_required":{"type":"boolean","title":"Verification Required","default":true},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"}},"type":"object","required":["success","message"],"title":"ClaimInitiateResponse","description":"Response after initiating a claim."},"ClaimPublicInfo":{"properties":{"valid":{"type":"boolean","title":"Valid"},"status":{"type":"string","title":"Status"},"campaign_title":{"type":"string","title":"Campaign Title"},"campaign_ticker":{"type":"string","title":"Campaign Ticker"},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name"},"campaign_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Description"},"campaign_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Image Url"},"campaign_goal":{"type":"number","title":"Campaign Goal"},"campaign_raised":{"type":"number","title":"Campaign Raised"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"already_claimed":{"type":"boolean","title":"Already Claimed","default":false},"expired":{"type":"boolean","title":"Expired","default":false},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"}},"type":"object","required":["valid","status","campaign_title","campaign_ticker","campaign_goal","campaign_raised","expires_at"],"title":"ClaimPublicInfo","description":"Public information about a claim token (for claim page)."},"ClaimTokenCreate":{"properties":{"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes","description":"Admin notes about this claim token"},"expiry_days":{"type":"integer","maximum":90.0,"minimum":1.0,"title":"Expiry Days","description":"Number of days until token expires","default":30},"send_to_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Send To Email","description":"Email the claim link to this address"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name","description":"Name to greet the recipient by"}},"type":"object","title":"ClaimTokenCreate","description":"Request schema for generating a claim token."},"ClaimTokenCreated":{"properties":{"id_claim_token":{"type":"string","format":"uuid","title":"Id Claim Token"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id"},"token":{"type":"string","title":"Token"},"status":{"type":"string","title":"Status"},"claimant_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimant Email"},"claimant_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimant Name"},"created_by":{"type":"string","format":"uuid","title":"Created By"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"claimed_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Claimed By"},"claimed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Claimed At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"claim_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claim Url"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Ticker"},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name"},"campaign_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Image Url"},"email_sent":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Email Sent","description":"Whether the claim link was emailed. Null when no address was given."},"email_failure":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email Failure","description":"Why the link wasn't emailed: 'suppressed' (the address bounced or complained before, so nothing was sent) or 'failed' (the send raised). The token exists either way; copy the link or resend it."}},"type":"object","required":["id_claim_token","campaign_id","token","status","created_by","expires_at","created_at"],"title":"ClaimTokenCreated","description":"A new claim token, and whether its link went out by email."},"ClaimTokenWithCampaign":{"properties":{"id_claim_token":{"type":"string","format":"uuid","title":"Id Claim Token"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id"},"token":{"type":"string","title":"Token"},"status":{"type":"string","title":"Status"},"claimant_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimant Email"},"claimant_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimant Name"},"created_by":{"type":"string","format":"uuid","title":"Created By"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"claimed_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Claimed By"},"claimed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Claimed At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"claim_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claim Url"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Ticker"},"original_organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Organizer Name"},"campaign_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Image Url"}},"type":"object","required":["id_claim_token","campaign_id","token","status","created_by","expires_at","created_at"],"title":"ClaimTokenWithCampaign","description":"Claim token with campaign details."},"CleanupCandidate":{"properties":{"id":{"type":"string","title":"Id","description":"The transaction's id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"payment_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Status"},"product_title":{"type":"string","title":"Product Title","description":"'Unknown' when the product is gone"},"total_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Amount"}},"type":"object","required":["id","product_title"],"title":"CleanupCandidate","description":"An abandoned purchase a cleanup would delete."},"CleanupCandidates":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"total_candidates":{"type":"integer","title":"Total Candidates"},"hours_threshold":{"type":"integer","title":"Hours Threshold"},"candidates":{"items":{"$ref":"#/components/schemas/CleanupCandidate"},"type":"array","title":"Candidates"}},"type":"object","required":["success","total_candidates","hours_threshold","candidates"],"title":"CleanupCandidates","description":"GET /admin/cleanup/cleanup/candidates."},"CleanupResult":{"properties":{"dry_run":{"type":"boolean","title":"Dry Run"},"total_found":{"type":"integer","title":"Total Found"},"transactions":{"anyOf":[{"items":{"$ref":"#/components/schemas/CleanupCandidate"},"type":"array"},{"type":"null"}],"title":"Transactions"},"deleted_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deleted Count"},"orphans_removed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Orphans Removed"},"errors":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Errors"},"cutoff_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cutoff Time","description":"ISO 8601"},"hours_threshold":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hours Threshold"}},"type":"object","required":["dry_run","total_found"],"title":"CleanupResult","description":"A dry run sends dry_run, total_found and transactions; a real one\neverything else."},"CleanupRun":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"message":{"type":"string","title":"Message"},"result":{"$ref":"#/components/schemas/CleanupResult"}},"type":"object","required":["success","message","result"],"title":"CleanupRun","description":"POST /admin/cleanup/cleanup/transactions."},"ClickCount":{"properties":{"clicks":{"type":"integer","title":"Clicks"}},"type":"object","required":["clicks"],"title":"ClickCount"},"ClicksAndConversions":{"properties":{"clicks":{"type":"integer","title":"Clicks"},"conversions":{"type":"integer","title":"Conversions"},"conversion_rate":{"type":"number","title":"Conversion Rate","description":"Percent of clicks that converted, to 2 places"}},"type":"object","required":["clicks","conversions","conversion_rate"],"title":"ClicksAndConversions"},"CodeClicks":{"properties":{"code":{"type":"string","title":"Code","description":"Referral code"},"owner_name":{"type":"string","title":"Owner Name","description":"Code owner name"},"owner_type":{"type":"string","title":"Owner Type","description":"Type of owner"},"clicks":{"type":"integer","title":"Clicks","description":"Total clicks","default":0},"conversions":{"type":"integer","title":"Conversions","description":"Total conversions","default":0}},"type":"object","required":["code","owner_name","owner_type"],"title":"CodeClicks","description":"Click counts by referral code"},"ConnectAccountResponse":{"properties":{"account_id":{"type":"string","title":"Account Id","description":"Stripe account ID (acct_xxx)"},"type":{"type":"string","title":"Type","description":"Account type (express)"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Account email"},"charges_enabled":{"type":"boolean","title":"Charges Enabled","description":"Whether account can accept charges"},"payouts_enabled":{"type":"boolean","title":"Payouts Enabled","description":"Whether account can receive payouts"},"details_submitted":{"type":"boolean","title":"Details Submitted","description":"Whether details are submitted"},"onboarding_complete":{"type":"boolean","title":"Onboarding Complete","description":"Whether onboarding is complete","default":false}},"type":"object","required":["account_id","type","charges_enabled","payouts_enabled","details_submitted"],"title":"ConnectAccountResponse","description":"Stripe Connect account response"},"ContributionSyncStatus":{"properties":{"message":{"type":"string","title":"Message","description":"What the sync did, in English"},"status":{"type":"string","title":"Status","description":"The contribution's payment status after the sync"},"stripe_payment_intent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Payment Intent Id","description":"The Stripe PaymentIntent synced; absent when there is none"}},"type":"object","required":["message","status"],"title":"ContributionSyncStatus","description":"POST /direct_contributions/{id}/sync-status. iOS decodes message and\nstatus as required; Android and web read nothing."},"CreateConnectAccountRequest":{"properties":{"country":{"anyOf":[{"type":"string","pattern":"^[A-Za-z]{2}$"},{"type":"null"}],"title":"Country","description":"The seller's country, as ISO 3166-1 alpha-2 (\"US\", \"BR\"), kept as their payout_country. Only the countries in has-account's supported_countries may connect; any other answers 422 with a plain detail and nothing is made at Stripe. Unset means the country the seller stated with PUT /stripe/connect/payout-country, else \"US\" for app builds that predate both.","examples":["US"]},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata","description":"Additional metadata"}},"type":"object","title":"CreateConnectAccountRequest","description":"Request to create a Stripe Connect Express account"},"CreateOrderRequest":{"properties":{"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"e.g. opengiving://paypal-return"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url","description":"e.g. opengiving://paypal-cancel"},"contribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contribution Id","description":"An existing direct_contributions row"},"campaign_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Id","description":"Campaign to contribute to"},"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Amount","description":"Contribution amount, excluding the tip"},"platform_tip":{"type":"number","maximum":10000.0,"minimum":0.0,"title":"Platform Tip","description":"Optional tip to OpenGiving","default":0},"message":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Message"},"anonymous":{"type":"boolean","title":"Anonymous","default":false}},"type":"object","title":"CreateOrderRequest","description":"Either point at an existing pending contribution, or describe a new one.\n\nThe browser path sends campaign_id/amount: PayPal must not depend on the\nStripe contribution endpoint, which also opens a PaymentIntent — the one\nthing that is paused while the Stripe review runs."},"CreateOrderResponse":{"properties":{"order_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Order Value"},"processing_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Processing Fee"},"total_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Charged"},"order_id":{"type":"string","title":"Order Id"},"contribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contribution Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"approve_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approve Url"}},"type":"object","required":["order_id"],"title":"CreateOrderResponse"},"CreatePaymentIntentRequest":{"properties":{"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount","description":"Payment amount in dollars"},"currency":{"type":"string","title":"Currency","description":"Payment currency","default":"USD"},"payment_type":{"type":"string","title":"Payment Type","description":"Type of payment (direct_contribution, marketplace_transaction)"},"reference_id":{"type":"string","format":"uuid","title":"Reference Id","description":"Reference to campaign or transaction"},"donation_percentage":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Percentage","description":"Percentage going to campaign","default":0},"customer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email","description":"Customer email for receipt"},"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"Return URL after payment"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata","description":"Additional metadata"}},"type":"object","required":["amount","payment_type","reference_id"],"title":"CreatePaymentIntentRequest","description":"Request to create a Stripe PaymentIntent"},"DailyClicks":{"properties":{"date":{"type":"string","title":"Date","description":"Date in YYYY-MM-DD format"},"clicks":{"type":"integer","title":"Clicks","description":"Number of clicks on this day","default":0},"conversions":{"type":"integer","title":"Conversions","description":"Number of conversions on this day","default":0}},"type":"object","required":["date"],"title":"DailyClicks","description":"Daily click counts"},"DashboardLinkResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Stripe Express Dashboard URL"}},"type":"object","required":["url"],"title":"DashboardLinkResponse","description":"Express Dashboard login link response"},"DeactivationImpactSummary":{"properties":{"campaign_id":{"type":"string","title":"Campaign Id"},"current_raised":{"type":"number","title":"Current Raised"},"donor_count":{"type":"integer","title":"Donor Count"},"pending_transactions":{"type":"integer","title":"Pending Transactions"},"linked_products":{"type":"integer","title":"Linked Products"},"estimated_refund_amount":{"type":"number","title":"Estimated Refund Amount","default":0.0},"cannot_deactivate_reasons":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Cannot Deactivate Reasons"},"warnings":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Warnings"}},"type":"object","required":["campaign_id","current_raised","donor_count","pending_transactions","linked_products"],"title":"DeactivationImpactSummary","description":"Summary of what will happen when campaign is deactivated"},"DeactivationReason":{"type":"string","enum":["goal_achieved","no_longer_needed","personal_reasons","duplicate_campaign","change_of_plans","insufficient_support","other"],"title":"DeactivationReason","description":"Valid reasons for campaign deactivation"},"DeliveryChannelRequest":{"properties":{"seller_id":{"type":"string","title":"Seller Id"},"transaction_id":{"type":"string","title":"Transaction Id"},"product_name":{"type":"string","title":"Product Name"}},"type":"object","required":["seller_id","transaction_id","product_name"],"title":"DeliveryChannelRequest"},"DeliveryCodeInfo":{"properties":{"code":{"type":"string","title":"Code","description":"Code (masked for buyers)"},"attempts_remaining":{"type":"integer","title":"Attempts Remaining","description":"Number of attempts remaining"},"is_verified":{"type":"boolean","title":"Is Verified","description":"Whether code has been verified"},"verified_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verified At","description":"Code verification timestamp"}},"type":"object","required":["code","attempts_remaining","is_verified"],"title":"DeliveryCodeInfo"},"DeliveryCodeResponse":{"properties":{"code":{"type":"string","title":"Code","description":"4-digit delivery confirmation code"},"message":{"type":"string","title":"Message","description":"Response message"}},"type":"object","required":["code","message"],"title":"DeliveryCodeResponse"},"DeliveryConfirmation":{"properties":{"message":{"type":"string","title":"Message","description":"Always 'Delivery confirmed successfully'"},"delivery_status":{"type":"string","title":"Delivery Status","description":"Always 'confirmed': the code was verified"},"escrow_released":{"type":"boolean","title":"Escrow Released","description":"Whether this sale's escrow has been released. Confirming doesn't release it: that happens 7 days later, or when the seller or an admin releases it, so this is usually false"}},"type":"object","required":["message","delivery_status","escrow_released"],"title":"DeliveryConfirmation","description":"POST /transactions/{id}/confirm-delivery, once the buyer's code checks out.\n\niOS decodes all three keys as required (DeliveryConfirmationResult), so\nnone may be dropped or null."},"DetectedItem":{"properties":{"item_id":{"type":"string","title":"Item Id","description":"Temporary UUID for frontend tracking"},"image_indices":{"items":{"type":"integer"},"type":"array","title":"Image Indices","description":"Which images belong to this item (0-based)"},"confidence_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence Score","description":"Confidence in grouping"},"listing":{"$ref":"#/components/schemas/DetectedItemListing","description":"AI-generated listing details"},"grouping_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grouping Reason","description":"Why AI grouped these images together"}},"type":"object","required":["item_id","image_indices","confidence_score","listing"],"title":"DetectedItem","description":"A detected item with its grouped images and listing details"},"DetectedItemListing":{"properties":{"title":{"type":"string","title":"Title","description":"AI-generated product title"},"description":{"type":"string","title":"Description","description":"AI-generated product description"},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Category Id","description":"Matched category ID"},"category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category Name","description":"Matched category name"},"condition":{"type":"string","title":"Condition","description":"AI-determined condition"},"suggested_price":{"anyOf":[{"type":"number","maximum":100000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Suggested Price","description":"AI-suggested price; clamped to MINIMUM_LISTING_PRICE"},"confidence_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence Score","description":"AI confidence score"},"suggested_keywords":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Suggested Keywords","description":"Suggested keywords"}},"type":"object","required":["title","description","condition","confidence_score"],"title":"DetectedItemListing","description":"Listing details for a detected item"},"DevicePlatform":{"type":"string","enum":["ios","android"],"title":"DevicePlatform","description":"The push transport a token belongs to.\n\nAn enum rather than free text because it selects which transport sends the\npayload. `notification_type` on the notifications table is free text and\nthat has already cost us -- twenty-five values with no schema, two\nnamespaces that drifted apart, and no way to find out which are live\nwithout a caller census."},"DeviceTokenRegister":{"properties":{"token":{"type":"string","title":"Token","description":"APNs device token (hex) or FCM registration token"},"platform":{"$ref":"#/components/schemas/DevicePlatform","description":"Which push transport issued the token"},"locale":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Locale","description":"BCP 47 tag, e.g. pt-BR. Push copy is rendered server-side, so the device has to say which language it wants."},"app_version":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"App Version","description":"Client build, for debugging delivery"},"device_model":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Device Model","description":"Device model, for debugging delivery"},"apns_sandbox":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Apns Sandbox","description":"iOS only: whether this token came from a build signed with a development profile, and therefore belongs to the APNs sandbox host. The device is the only thing that knows -- it reads its own provisioning profile -- and getting it wrong means BadDeviceToken, which reads as a dead device."}},"type":"object","required":["token","platform"],"title":"DeviceTokenRegister","description":"What a phone sends after the OS hands it a token."},"DeviceTokenResponse":{"properties":{"id_device_token":{"type":"string","title":"Id Device Token"},"platform":{"$ref":"#/components/schemas/DevicePlatform"},"locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locale"},"app_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"App Version"},"device_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Model"},"apns_sandbox":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Apns Sandbox"},"is_active":{"type":"boolean","title":"Is Active"},"last_seen_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id_device_token","platform","is_active","created_at"],"title":"DeviceTokenResponse","description":"A registered device, as returned to the client."},"DigitalAsset":{"properties":{"id_asset":{"type":"string","format":"uuid","title":"Id Asset"},"product_id":{"type":"string","format":"uuid","title":"Product Id"},"file_name":{"type":"string","title":"File Name"},"file_size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size Bytes"},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type"},"version":{"type":"integer","title":"Version"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id_asset","product_id","file_name","version","is_active"],"title":"DigitalAsset","description":"A file attached to a digital product (no storage details exposed)."},"DigitalAssetPresignRequest":{"properties":{"file_name":{"type":"string","maxLength":255,"minLength":1,"title":"File Name","description":"Original file name"},"content_type":{"type":"string","maxLength":100,"title":"Content Type","description":"MIME type of the file"},"file_size_bytes":{"type":"integer","exclusiveMinimum":0.0,"title":"File Size Bytes","description":"Size of the file in bytes"}},"type":"object","required":["file_name","content_type","file_size_bytes"],"title":"DigitalAssetPresignRequest","description":"Seller requests a presigned upload slot for a product file."},"DigitalAssetPresignResponse":{"properties":{"asset_id":{"type":"string","format":"uuid","title":"Asset Id","description":"Id of the pending asset (confirm after upload)"},"upload_url":{"type":"string","title":"Upload Url","description":"Presigned S3 PUT URL"},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds the upload URL stays valid"}},"type":"object","required":["asset_id","upload_url","expires_in"],"title":"DigitalAssetPresignResponse","description":"Presigned PUT the seller uploads the file to, plus the pending asset id."},"DigitalDownloadResponse":{"properties":{"download_url":{"type":"string","title":"Download Url","description":"Presigned S3 GET URL (short-lived)"},"file_name":{"type":"string","title":"File Name","description":"File name for the download"},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds the link stays valid"},"downloads_remaining":{"type":"integer","title":"Downloads Remaining","description":"Downloads left on this entitlement"}},"type":"object","required":["download_url","file_name","expires_in","downloads_remaining"],"title":"DigitalDownloadResponse","description":"A short-lived download link for an entitled buyer."},"DigitalEntitlement":{"properties":{"id_delivery":{"type":"string","format":"uuid","title":"Id Delivery"},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id"},"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"file_name":{"type":"string","title":"File Name","description":"File name of the entitled asset"},"download_count":{"type":"integer","title":"Download Count"},"max_downloads":{"type":"integer","title":"Max Downloads"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["id_delivery","transaction_id","asset_id","file_name","download_count","max_downloads"],"title":"DigitalEntitlement","description":"A buyer's download entitlement (their 'library' row for a purchase)."},"DigitalUploadPolicy":{"properties":{"allowed_extensions":{"items":{"type":"string"},"type":"array","title":"Allowed Extensions"},"max_file_mb":{"type":"integer","title":"Max File Mb"},"buyer_fee":{"type":"number","title":"Buyer Fee"},"minimum_donation_pct":{"type":"integer","title":"Minimum Donation Pct"}},"type":"object","required":["allowed_extensions","max_file_mb","buyer_fee","minimum_donation_pct"],"title":"DigitalUploadPolicy","description":"What a seller is allowed to upload as a digital product.\n\nPublished for the same reason as MonetaryLimits: four hand-maintained\ncopies of this list existed — server, web, iOS, Android — and a client that\nguesses short hides a format the server would happily accept, while one\nthat guesses long lets a seller pick a file the upload then refuses.\n\nIt also decouples adding a format from the app stores. Extensions move by\nenvironment variable and reach every surface at once, instead of waiting on\ntwo store reviews."},"DirectContribution":{"properties":{"id_contribution":{"type":"string","format":"uuid","title":"Id Contribution","description":"Unique identifier of the contribution"},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Unique identifier of the user who made the contribution"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Unique identifier of the campaign that the contribution was made to"},"amount":{"type":"number","exclusiveMinimum":0.0,"title":"Amount","description":"Contribution amount; the floor is MINIMUM_DONATION_AMOUNT"},"platform_tip":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Platform Tip","description":"Optional tip to OpenGiving platform","default":0},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Message of the contribution"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the contribution is anonymous"}},"type":"object","required":["id_contribution","user_id","campaign_id","amount","anonymous"],"title":"DirectContribution"},"DirectContributionCreate":{"properties":{"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Unique identifier of the campaign that the contribution was made to"},"amount":{"type":"number","exclusiveMinimum":0.0,"title":"Amount","description":"Contribution amount; the floor is MINIMUM_DONATION_AMOUNT"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"null"}],"title":"Platform Tip","description":"Optional tip to OpenGiving platform","default":0},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Message of the contribution"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the contribution is anonymous"}},"type":"object","required":["campaign_id","amount","anonymous"],"title":"DirectContributionCreate"},"DirectContributionRequest":{"properties":{"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Campaign to donate to"},"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount","description":"Donation amount"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional platform tip","default":"0"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Donation message"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether donation is anonymous","default":false},"customer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email","description":"Donor email for receipt"},"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"Return URL after payment"}},"type":"object","required":["campaign_id","amount"],"title":"DirectContributionRequest","description":"Request to create a direct donation/contribution"},"DirectContributionResponse":{"properties":{"contribution_id":{"type":"string","title":"Contribution Id","description":"Internal contribution ID"},"payment_intent_id":{"type":"string","title":"Payment Intent Id","description":"Stripe PaymentIntent ID"},"client_secret":{"type":"string","title":"Client Secret","description":"Client secret for frontend"},"amount":{"type":"integer","title":"Amount","description":"Amount in cents"},"fee_breakdown":{"$ref":"#/components/schemas/FeeCalculationResponse","description":"Fee breakdown"}},"type":"object","required":["contribution_id","payment_intent_id","client_secret","amount","fee_breakdown"],"title":"DirectContributionResponse","description":"Direct contribution response"},"DirectoryEntry":{"properties":{"user":{"$ref":"#/components/schemas/UserPublic"},"profile":{"$ref":"#/components/schemas/GivingProfile"}},"type":"object","required":["user","profile"],"title":"DirectoryEntry","description":"One row of the public GivingProfiles directory."},"DispatchResponse":{"properties":{"withdrawal_id":{"type":"string","title":"Withdrawal Id"},"batch_id":{"type":"string","title":"Batch Id"},"batch_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Batch Status"},"amount":{"type":"number","title":"Amount"}},"type":"object","required":["withdrawal_id","batch_id","amount"],"title":"DispatchResponse"},"DisputeResolveRequest":{"properties":{"resolution":{"type":"string","enum":["release","refund"],"title":"Resolution","description":"release = pay the seller (force-accept); refund = refund the buyer"},"note":{"anyOf":[{"type":"string","maxLength":10000},{"type":"null"}],"title":"Note","description":"Admin note on the decision"}},"type":"object","required":["resolution"],"title":"DisputeResolveRequest"},"DonationPaymentBreakdown":{"properties":{"buyer_pays":{"items":{"$ref":"#/components/schemas/DonorPaysRow"},"type":"array","title":"Buyer Pays","description":"donation: the gift. tip: the tip to OpenGiving, only when there was one"},"processing_fee_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Processing Fee Cents","description":"The processing fee the donor was billed. Null when none was, and until it's paid"},"fee_kind":{"type":"string","enum":["processing_fee","service_fee"],"title":"Fee Kind","description":"What to call the fee the donor is billed. processing_fee: each rail bills its own processor's fee. service_fee: every rail bills the same fee","default":"processing_fee"},"total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Cents","description":"What the donor was charged. Null until it's paid"},"recipients":{"items":{"$ref":"#/components/schemas/DonationRecipientRow"},"type":"array","title":"Recipients","description":"campaign: what the campaign was credited, once paid. processing_fee: taken from the gift, only when it was. Empty until it's paid"},"refunded_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Refunded Cents","description":"What was refunded to the donor, once a refund went through. Null otherwise"}},"type":"object","required":["buyer_pays","recipients"],"title":"DonationPaymentBreakdown","description":"What a donor paid for one donation, row by row, and where it went.\n\nThe donation quote's kinds (services.purchase_breakdown.donation_paid_breakdown),\nso My Donations draws a donation with the words Donate Now drew it with."},"DonationQuote":{"properties":{"buyer_pays":{"items":{"$ref":"#/components/schemas/DonorPaysRow"},"type":"array","title":"Buyer Pays"},"rails":{"items":{"$ref":"#/components/schemas/RailTotal"},"type":"array","title":"Rails","description":"One per rail the caller is offered, card first"},"rails_named":{"type":"boolean","title":"Rails Named","description":"Whether each rail's rows say which rail they're for: when there's more than one"},"fee_kind":{"type":"string","enum":["processing_fee","service_fee"],"title":"Fee Kind","description":"What to call the fee the payer is billed. processing_fee: each rail bills its own processor's fee. service_fee: every rail bills the same fee, so the rails' totals are the same and one total can be shown","default":"processing_fee"},"fees":{"items":{"$ref":"#/components/schemas/FeeRow"},"type":"array","title":"Fees","description":"The fee rows to draw, in order. One under a single service fee, one per rail that bills the payer otherwise, and none while the payer isn't billed a fee or shipping is still to be chosen. Which rows exist is decided here so no client groups fees its own way"},"totals":{"items":{"$ref":"#/components/schemas/TotalRow"},"type":"array","title":"Totals","description":"The total rows to draw, in order. One under a single service fee, since every rail charges the same; otherwise one per rail"},"recipients":{"items":{"$ref":"#/components/schemas/DonationRecipientRow"},"type":"array","title":"Recipients","description":"The campaign, then the fee when the gift bears it"}},"type":"object","required":["buyer_pays","rails","rails_named","recipients"],"title":"DonationQuote","description":"The purchase quote's shape for a donation: what the donor pays, each\nrail's fee and total, and where the gift goes. There's no postage and one\nrecipient, so no shipping_pending and no per-item grouping."},"DonationQuoteRequest":{"properties":{"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount","description":"The donation. Quoted whatever it is; the minimum is refused when the donation is placed, not here, so a donor typing an amount still sees it"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional tip to OpenGiving","default":"0"}},"type":"object","required":["amount"],"title":"DonationQuoteRequest","description":"A donation as Donate Now is about to send it: the gift and the tip."},"DonationRecipientRow":{"properties":{"kind":{"type":"string","enum":["campaign","processing_fee"],"title":"Kind","description":"campaign: what the campaign receives, always sent. processing_fee: taken from the gift, only when the donor isn't billed it"},"amount_cents":{"type":"integer","title":"Amount Cents"}},"type":"object","required":["kind","amount_cents"],"title":"DonationRecipientRow","description":"Where part of the donation goes."},"DonationRefundHistoryItem":{"properties":{"refund_type":{"type":"string","title":"Refund Type"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"original_amount":{"type":"number","title":"Original Amount"},"refund_amount":{"type":"number","title":"Refund Amount"},"requester_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Requester Id"},"recipient_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Recipient Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"},"id_refund":{"type":"string","format":"uuid","title":"Id Refund"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name"},"donor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Donor Name"},"requester_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Name"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"admin_reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Reviewer Name"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the donation was given anonymously. An organizer is never sent an anonymous donor's name or ids","default":false},"campaign_deleted":{"type":"boolean","title":"Campaign Deleted","description":"Whether the donation's campaign no longer exists; campaign_title is then null","default":false},"organizer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Organizer Id"},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider"},"organizer_credited":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Organizer Credited"},"organizer_available_balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Organizer Available Balance"},"decision":{"type":"string","enum":["approved","declined"],"title":"Decision","description":"What the last decision on it was"},"decided_by":{"type":"string","enum":["seller","organizer","opengiving"],"title":"Decided By","description":"Who made that decision: the caller, as seller or organizer, or OpenGiving (an admin, or a refund recorded from Stripe)"},"decline_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decline Reason","description":"The reason the payer was given, when it was declined with one"},"outcome":{"type":"string","enum":["refunded","in_progress","waiting_on_opengiving","declined","failed"],"title":"Outcome","description":"refunded: the money went back. in_progress: approved and on its way. waiting_on_opengiving: approved, and an admin decides the rest. failed: the payment provider refused it. declined: turned down"}},"type":"object","required":["refund_type","original_amount","refund_amount","reason","id_refund","status","created_at","updated_at","decision","decided_by","outcome"],"title":"DonationRefundHistoryItem","description":"GET /refunds/refunds/organizer/history: a decided donation refund on one\nof the caller's campaigns. The organizer pending list's row, an anonymous\ndonor masked the same way, and how it was decided."},"Donor":{"properties":{"id":{"type":"string","title":"Id","description":"Unique identifier of the donation"},"name":{"type":"string","title":"Name","description":"Name of the donor (anonymous if applicable)"},"amount":{"type":"number","title":"Amount","description":"Amount donated"},"date":{"type":"string","format":"date-time","title":"Date","description":"Date of the donation"},"donation_type":{"type":"string","title":"Donation Type","description":"Type of donation: 'direct' or 'purchase'"},"is_anonymous":{"type":"boolean","title":"Is Anonymous","description":"Whether the donation is anonymous","default":false},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"Profile to link the donor to. Omitted for anonymous donations — the name is already redacted, and sending the id would undo that."},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"The donor's profile picture, on the same terms as user_id: withheld when they chose anonymity, and when their account is gone. A face names somebody more plainly than a name does, so it never outlives the link it sits beside."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Optional message from the donor"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name","description":"The other half of a purchase: whoever sold the item, redacted to 'Anonymous' if they chose that on the listing. Null on a direct donation, which has no seller."},"seller_is_anonymous":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Seller Is Anonymous","description":"Whether the seller asked to stay off this list. Null on a direct donation — 'no seller here', which false would not say."},"seller_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller User Id","description":"Profile to link the seller to, on the same terms as user_id: omitted when they chose anonymity, and when their account is gone."},"seller_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Image Url","description":"The seller's picture, on the same terms as image_url."}},"type":"object","required":["id","name","amount","date","donation_type"],"title":"Donor","description":"One entry on a campaign's public list of supporters.\n\nA donation has one person behind it. A sale has two: the buyer paid, and\nthe seller gave up the item, and the campaign's share came out of the one\ntransaction between them. So a sale is one entry naming the pair --\n`name` and `seller_name` -- rather than two entries splitting money that\nwas only given once.\n\nEach of them answers for themselves. The buyer chooses at checkout\n(transactions.anonymous), the seller on the listing (products.anonymous),\nand one choosing to be anonymous says nothing about the other: an entry can\nread \"Alice B. and Anonymous\", \"Anonymous and Bob C.\", or, when both chose\nit, \"Anonymous\".\n\nThe seller fields are optional and absent on a donation, which has no\nseller. They were added after iOS and Android had shipped builds decoding\nthis model, so they are additive on purpose: an older build ignores them\nand shows the buyer alone, which is less than the entry says but nothing\nit says is wrong."},"DonorPaysRow":{"properties":{"kind":{"type":"string","enum":["donation","tip"],"title":"Kind","description":"donation: the gift. tip: the tip to OpenGiving, only when there is one"},"amount_cents":{"type":"integer","title":"Amount Cents"}},"type":"object","required":["kind","amount_cents"],"title":"DonorPaysRow","description":"Something the donor pays for, whichever rail they pay with."},"EarnedBadge":{"properties":{"badge_id":{"type":"string","format":"uuid","title":"Badge Id","description":"ID of the badge definition"},"earned_at":{"type":"string","format":"date-time","title":"Earned At","description":"When the badge was earned"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress","description":"Current progress towards next tier (if applicable)"}},"type":"object","required":["badge_id","earned_at"],"title":"EarnedBadge","description":"Represents a badge earned by a user"},"EmailSuppression":{"properties":{"email":{"type":"string","title":"Email"},"reason":{"type":"string","title":"Reason","description":"'bounce' or 'complaint'"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"},"email_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email Id","description":"The Resend email that bounced"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["email","reason"],"title":"EmailSuppression"},"EmailSuppressionLifted":{"properties":{"email":{"type":"string","title":"Email","description":"The address, normalised"},"removed":{"type":"boolean","title":"Removed"}},"type":"object","required":["email","removed"],"title":"EmailSuppressionLifted","description":"DELETE /admin/email-suppressions. removed is false when there was\nnothing to lift, so a retry isn't an error."},"EmailSuppressionPage":{"properties":{"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"},"suppressions":{"items":{"$ref":"#/components/schemas/EmailSuppression"},"type":"array","title":"Suppressions"}},"type":"object","required":["total","limit","offset","suppressions"],"title":"EmailSuppressionPage","description":"GET /admin/email-suppressions."},"EscrowPolicy":{"properties":{"auto_release":{"type":"boolean","title":"Auto Release"},"auto_release_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Auto Release Days"}},"type":"object","required":["auto_release"],"title":"EscrowPolicy","description":"When a sale's held payment goes out if nobody releases it.\n\nThe seller, or an admin, can release a confirmed sale's payment; if\nnobody does, the nightly sweep (services/escrow_release\n.auto_release_due_escrow) releases it this many days after the buyer\nconfirmed delivery. Web, iOS and Android each pinned 7, which is what\nESCROW_AUTO_RELEASE_DAYS used to be, to tell a seller when the money\ncomes.\n\nIt is 0 since 2026-09-17: the sale is released where the buyer confirms\nit, and the sweep only retries. A client reading 0 should say the money\ngoes out when the buyer confirms delivery, not name a number of days.\n\n`auto_release_days` is null when the sweep is off, because then nothing\nreleases on its own. A sale confirmed longer ago than the sweep's\nbackfill limit (ESCROW_AUTO_RELEASE_MAX_AGE_DAYS) is left for a person\ntoo; a date that has passed shouldn't be shown as a promise."},"FeatureFlags":{"properties":{"payments_enabled":{"type":"boolean","title":"Payments Enabled","default":true},"chat_enabled":{"type":"boolean","title":"Chat Enabled","default":true},"push_notifications_enabled":{"type":"boolean","title":"Push Notifications Enabled","default":true}},"type":"object","title":"FeatureFlags","description":"Feature flags for conditional functionality"},"FeeCalculationRequest":{"properties":{"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount","description":"Transaction amount"},"payment_type":{"type":"string","title":"Payment Type","description":"Type of payment"},"donation_percentage":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Donation Percentage","description":"Percentage going to campaign","default":0},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider","description":"Rail the payer will use (paypal/stripe). The processing fee differs per rail, so the total differs too; omit to quote the live one."},"product_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Type","description":"Kind of listing being bought. Digital listings are billed a flat buyer fee on top of the price and pay no percentage platform fee; omit for the rest."},"digital_item_count":{"anyOf":[{"type":"integer","maximum":500.0,"minimum":0.0},{"type":"null"}],"title":"Digital Item Count","description":"For a cart: how many of its items are digital. The flat fee is per item, so a basket cannot be described by product_type alone. Takes precedence over product_type."},"goods_subtotal":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Goods Subtotal","description":"The part of `amount` that is sale value, excluding the tip and the postage. The platform's percentage is charged on this; settlement always was. Omit and the whole amount is assumed, which is what a cart quoting a tip and postage used to do."},"digital_subtotal":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Digital Subtotal","description":"The part of `goods_subtotal` that is digital listings. Those pay the flat buyer fee instead of the percentage, so only the rest is charged. Omit and the flat fee is taken to cover everything, which is true of one digital listing and not of a basket that holds one."}},"type":"object","required":["amount","payment_type"],"title":"FeeCalculationRequest","description":"Request for fee calculation"},"FeeCalculationResponse":{"properties":{"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount","description":"Original amount"},"stripe_fee":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Stripe Fee","description":"Deprecated: same value as processing_fee, under the name it had when Stripe was the only rail"},"processing_fee":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Processing Fee","description":"Payment processing fee kept by the provider"},"platform_fee":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Platform Fee","description":"OpenGiving platform fee"},"total_fees":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Total Fees","description":"Total fees"},"net_amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Net Amount","description":"Net amount after fees"},"seller_amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Seller Amount","description":"Amount going to seller","default":"0"},"campaign_amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Campaign Amount","description":"Amount going to campaign","default":"0"},"buyer_fee":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Buyer Fee","description":"Flat fee billed to the buyer above the list price. Non-zero on digital listings only, and already included in total_charged.","default":"0"},"total_charged":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Total Charged","description":"What the payer is billed. Equals amount unless the payer covers the processing fee, in which case it is amount + processing_fee. Show this as the total."},"payer_covers_processing_fee":{"type":"boolean","title":"Payer Covers Processing Fee","description":"Whether processing_fee is added to the payer's total rather than deducted from the recipients. Tells a client whether to render the fee as a line item.","default":false},"fee_kind":{"type":"string","enum":["processing_fee","service_fee"],"title":"Fee Kind","description":"What the fee the payer is billed is called. processing_fee: each rail bills its own processor's fee, so a client quoting two rails shows two totals. service_fee: every rail bills the same fee, so there is one fee and one total to show."}},"type":"object","required":["amount","stripe_fee","platform_fee","total_fees","net_amount"],"title":"FeeCalculationResponse","description":"Fee calculation response"},"FeeRow":{"properties":{"kind":{"type":"string","enum":["service_fee","processing_fees","processing_fee_by_card","processing_fee_with_paypal","platform_fee"],"title":"Kind","description":"service_fee: one fee every rail bills, the digital items' flat fee included. processing_fees: one rail's fee, drawn alone. processing_fee_by_card / processing_fee_with_paypal: that rail's fee, beside another rail's. platform_fee: OpenGiving's own cut, billed on top of the prices rather than taken out of the sale -- a separate charge by a separate party, so it is its own row beside the processor's"},"amount_cents":{"type":"integer","title":"Amount Cents"}},"type":"object","required":["kind","amount_cents"],"title":"FeeRow","description":"A fee row, named as it's drawn."},"FeeSummary":{"properties":{"stripe_fee":{"type":"number","title":"Stripe Fee","description":"Single processing fee for the whole cart"},"platform_fee":{"type":"number","title":"Platform Fee","description":"OpenGiving's fee, billed on top of the subtotal"},"total_fees":{"type":"number","title":"Total Fees","description":"Total fees"},"net_to_recipients":{"type":"number","title":"Net To Recipients","description":"Net amount distributed to sellers/campaigns"}},"type":"object","required":["stripe_fee","platform_fee","total_fees","net_to_recipients"],"title":"FeeSummary","description":"Summary of all fees for the checkout. Money goes out as JSON numbers."},"Feedback":{"properties":{"website_rating":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Website Rating","description":"Website rating from 1 to 5 stars"},"seller_rating":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Seller Rating","description":"Seller rating from 1 to 5 stars"},"website_review":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Website Review","description":"Optional website review text"},"seller_review":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Seller Review","description":"Optional seller review text"},"is_anonymous":{"type":"boolean","title":"Is Anonymous","description":"Whether the feedback should be anonymous","default":false},"id_feedback":{"type":"string","format":"uuid","title":"Id Feedback"},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id"},"buyer_id":{"type":"string","format":"uuid","title":"Buyer Id"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["website_rating","seller_rating","id_feedback","transaction_id","buyer_id","seller_id","created_at"],"title":"Feedback"},"FeedbackCreate":{"properties":{"website_rating":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Website Rating","description":"Website rating from 1 to 5 stars"},"seller_rating":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Seller Rating","description":"Seller rating from 1 to 5 stars"},"website_review":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Website Review","description":"Optional website review text"},"seller_review":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Seller Review","description":"Optional seller review text"},"is_anonymous":{"type":"boolean","title":"Is Anonymous","description":"Whether the feedback should be anonymous","default":false},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id","description":"ID of the transaction being reviewed"}},"type":"object","required":["website_rating","seller_rating","transaction_id"],"title":"FeedbackCreate"},"FeedbackWithBuyerInfo":{"properties":{"website_rating":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Website Rating","description":"Website rating from 1 to 5 stars"},"seller_rating":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Seller Rating","description":"Seller rating from 1 to 5 stars"},"website_review":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Website Review","description":"Optional website review text"},"seller_review":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Seller Review","description":"Optional seller review text"},"is_anonymous":{"type":"boolean","title":"Is Anonymous","description":"Whether the feedback should be anonymous","default":false},"id_feedback":{"type":"string","format":"uuid","title":"Id Feedback"},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id"},"buyer_id":{"type":"string","format":"uuid","title":"Buyer Id"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"buyer_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Image Url"}},"type":"object","required":["website_rating","seller_rating","id_feedback","transaction_id","buyer_id","seller_id","created_at"],"title":"FeedbackWithBuyerInfo"},"GivenGainImportPreview":{"properties":{"title":{"type":"string","title":"Title","description":"Campaign title"},"description":{"type":"string","title":"Description","description":"Campaign description/story"},"goal":{"type":"number","minimum":0.0,"title":"Goal","description":"Fundraising goal amount"},"raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Raised","description":"Amount already raised on GivenGain"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Campaign location"},"original_category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Category","description":"Original GivenGain category"},"suggested_category_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Category Id","description":"Suggested OpenGiving category ID"},"suggested_category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Category Name","description":"Suggested OpenGiving category name"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"Image URLs (up to 5)"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name","description":"Original organizer/charity name (for reference)"},"source_url":{"type":"string","title":"Source Url","description":"Original GivenGain URL"},"can_import":{"type":"boolean","title":"Can Import","description":"Whether the campaign can be imported","default":true},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Any warnings about the import"},"extraction_confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Extraction Confidence","description":"Confidence score of extraction"},"ai_enhanced":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ai Enhanced","description":"Whether AI was used to fill missing data","default":false},"ai_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ai Confidence","description":"AI's confidence in inferred data"}},"type":"object","required":["title","description","goal","source_url","extraction_confidence"],"title":"GivenGainImportPreview","description":"Preview response with editable fields and metadata"},"GivenGainImportRequest":{"properties":{"url":{"type":"string","title":"Url","description":"GivenGain campaign URL"}},"type":"object","required":["url"],"title":"GivenGainImportRequest","description":"Request schema for GivenGain campaign import"},"GivenGainMigrationRequest":{"properties":{"source_url":{"type":"string","title":"Source Url","description":"Original GivenGain campaign URL"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Deprecated - session email is used"},"consent":{"type":"boolean","title":"Consent","description":"User has consented to migration"},"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title","description":"Campaign title"},"description":{"type":"string","minLength":1,"title":"Description","description":"Campaign description"},"goal":{"type":"number","exclusiveMinimum":0.0,"title":"Goal","description":"Fundraising goal amount"},"location":{"type":"string","minLength":1,"title":"Location","description":"Campaign location"},"category_id":{"type":"string","title":"Category Id","description":"OpenGiving category ID"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name","description":"Organizer name from GivenGain"},"images":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Images","description":"Image URLs scraped from the source campaign"}},"type":"object","required":["source_url","consent","title","description","goal","location","category_id"],"title":"GivenGainMigrationRequest","description":"Request schema for migrating a GivenGain campaign (no auth required)"},"GivenGainMigrationResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the migration was successful","default":true},"campaign_id":{"type":"string","title":"Campaign Id","description":"Created campaign ID"},"campaign_ticker":{"type":"string","title":"Campaign Ticker","description":"Campaign ticker/slug"},"user_id":{"type":"string","title":"User Id","description":"User ID (new or existing)"},"is_new_user":{"type":"boolean","title":"Is New User","description":"Whether a new account was created"},"email":{"type":"string","title":"Email","description":"Email address of the organizer"},"message":{"type":"string","title":"Message","description":"Success message"}},"type":"object","required":["campaign_id","campaign_ticker","user_id","is_new_user","email","message"],"title":"GivenGainMigrationResponse","description":"Response schema for successful migration"},"GivenGainRefreshRequest":{"properties":{"givengain_url":{"type":"string","title":"Givengain Url","description":"GivenGain campaign URL to scrape data from"}},"type":"object","required":["givengain_url"],"title":"GivenGainRefreshRequest","description":"Request schema for refreshing GivenGain data on an existing campaign"},"GivenGainRefreshResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the refresh was successful","default":true},"campaign_id":{"type":"string","title":"Campaign Id","description":"Campaign ID that was updated"},"givengain_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Givengain Raised","description":"Raised amount from GivenGain"},"source_url":{"type":"string","title":"Source Url","description":"GivenGain URL that was scraped"},"updated_at":{"type":"string","title":"Updated At","description":"Timestamp of the update"},"message":{"type":"string","title":"Message","description":"Status message"}},"type":"object","required":["campaign_id","source_url","updated_at","message"],"title":"GivenGainRefreshResponse","description":"Response schema for GivenGain data refresh"},"GivingProfile":{"properties":{"id_giving_profile":{"type":"string","format":"uuid","title":"Id Giving Profile","description":"Unique identifier of the giving profile"},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Unique identifier of the user"},"total_donated":{"type":"number","title":"Total Donated","description":"Total amount donated by the user (all-time)","default":0.0},"campaigns_supported":{"type":"integer","title":"Campaigns Supported","description":"Number of campaigns supported by the user","default":0},"donation_streak":{"type":"integer","title":"Donation Streak","description":"Legacy donation streak field (deprecated, use current_streak)","default":0},"donated_this_week":{"type":"number","title":"Donated This Week","description":"Amount donated this week","default":0.0},"donated_this_month":{"type":"number","title":"Donated This Month","description":"Amount donated this month","default":0.0},"donated_this_year":{"type":"number","title":"Donated This Year","description":"Amount donated this year","default":0.0},"current_streak":{"type":"integer","title":"Current Streak","description":"Current donation streak in days","default":0},"longest_streak":{"type":"integer","title":"Longest Streak","description":"Longest donation streak ever achieved","default":0},"last_donation_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Donation Date","description":"Date of last donation"},"streak_freeze_count":{"type":"integer","title":"Streak Freeze Count","description":"Number of streak freezes available","default":0},"experience_points":{"type":"integer","title":"Experience Points","description":"Total XP earned","default":0},"next_level_xp":{"type":"integer","title":"Next Level Xp","description":"XP required to reach next level","default":100},"level":{"type":"integer","title":"Level","description":"Current level of the user","default":1},"category_stats":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Category Stats","description":"Category donation stats: [{category_id, amount, count}, ...]"},"favorite_category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Favorite Category Id","description":"Most donated category ID"},"badges":{"items":{"type":"string"},"type":"array","title":"Badges","description":"Legacy badges field (deprecated)"},"earned_badges":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Earned Badges","description":"Earned badges: [{badge_id, earned_at, progress}, ...]"},"theme_color":{"type":"string","title":"Theme Color","description":"Profile theme color","default":"primary"},"show_stats_publicly":{"type":"boolean","title":"Show Stats Publicly","description":"Whether to show stats publicly","default":true},"show_badges_publicly":{"type":"boolean","title":"Show Badges Publicly","description":"Whether to show badges publicly","default":true},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the profile is active","default":true},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"}},"type":"object","required":["id_giving_profile","user_id"],"title":"GivingProfile","description":"Complete giving profile with timestamps"},"GivingProfileCreate":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id","description":"User ID for this profile"},"theme_color":{"type":"string","title":"Theme Color","default":"primary"},"show_stats_publicly":{"type":"boolean","title":"Show Stats Publicly","default":true},"show_badges_publicly":{"type":"boolean","title":"Show Badges Publicly","default":true}},"type":"object","required":["user_id"],"title":"GivingProfileCreate","description":"Schema for creating a new giving profile"},"GivingProfileEnhanced":{"properties":{"id_giving_profile":{"type":"string","format":"uuid","title":"Id Giving Profile","description":"Unique identifier of the giving profile"},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Unique identifier of the user"},"total_donated":{"type":"number","title":"Total Donated","description":"Total amount donated by the user (all-time)","default":0.0},"campaigns_supported":{"type":"integer","title":"Campaigns Supported","description":"Number of campaigns supported by the user","default":0},"donation_streak":{"type":"integer","title":"Donation Streak","description":"Legacy donation streak field (deprecated, use current_streak)","default":0},"donated_this_week":{"type":"number","title":"Donated This Week","description":"Amount donated this week","default":0.0},"donated_this_month":{"type":"number","title":"Donated This Month","description":"Amount donated this month","default":0.0},"donated_this_year":{"type":"number","title":"Donated This Year","description":"Amount donated this year","default":0.0},"current_streak":{"type":"integer","title":"Current Streak","description":"Current donation streak in days","default":0},"longest_streak":{"type":"integer","title":"Longest Streak","description":"Longest donation streak ever achieved","default":0},"last_donation_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Donation Date","description":"Date of last donation"},"streak_freeze_count":{"type":"integer","title":"Streak Freeze Count","description":"Number of streak freezes available","default":0},"experience_points":{"type":"integer","title":"Experience Points","description":"Total XP earned","default":0},"next_level_xp":{"type":"integer","title":"Next Level Xp","description":"XP required to reach next level","default":100},"level":{"type":"integer","title":"Level","description":"Current level of the user","default":1},"category_stats":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Category Stats","description":"Category donation stats: [{category_id, amount, count}, ...]"},"favorite_category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Favorite Category Id","description":"Most donated category ID"},"badges":{"items":{"type":"string"},"type":"array","title":"Badges","description":"Legacy badges field (deprecated)"},"earned_badges":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Earned Badges","description":"Earned badges: [{badge_id, earned_at, progress}, ...]"},"theme_color":{"type":"string","title":"Theme Color","description":"Profile theme color","default":"primary"},"show_stats_publicly":{"type":"boolean","title":"Show Stats Publicly","description":"Whether to show stats publicly","default":true},"show_badges_publicly":{"type":"boolean","title":"Show Badges Publicly","description":"Whether to show badges publicly","default":true},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the profile is active","default":true},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"},"impact_metrics":{"$ref":"#/components/schemas/ImpactMetrics","description":"Estimated impact from donations"},"items_sold":{"type":"integer","title":"Items Sold","description":"Total marketplace items sold","default":0},"streak_stats":{"$ref":"#/components/schemas/StreakStats","description":"Detailed streak statistics"},"pinned_campaigns":{"items":{"$ref":"#/components/schemas/PinnedCampaignSummary"},"type":"array","title":"Pinned Campaigns","description":"User's pinned campaigns"}},"type":"object","required":["id_giving_profile","user_id"],"title":"GivingProfileEnhanced","description":"Extended giving profile with computed metrics for profile display"},"GoFundMeImportPreview":{"properties":{"title":{"type":"string","title":"Title","description":"Campaign title"},"description":{"type":"string","title":"Description","description":"Campaign description/story"},"goal":{"type":"number","minimum":0.0,"title":"Goal","description":"Fundraising goal amount"},"raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Raised","description":"Amount already raised on GoFundMe"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Campaign location"},"original_category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Category","description":"Original GoFundMe category"},"suggested_category_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Category Id","description":"Suggested OpenGiving category ID"},"suggested_category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Category Name","description":"Suggested OpenGiving category name"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"Image URLs (up to 5)"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name","description":"Original organizer name (for reference)"},"source_url":{"type":"string","title":"Source Url","description":"Original GoFundMe URL"},"can_import":{"type":"boolean","title":"Can Import","description":"Whether the campaign can be imported","default":true},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Any warnings about the import"},"extraction_confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Extraction Confidence","description":"Confidence score of extraction"},"ai_enhanced":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ai Enhanced","description":"Whether AI was used to fill missing data","default":false},"ai_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ai Confidence","description":"AI's confidence in inferred data"}},"type":"object","required":["title","description","goal","source_url","extraction_confidence"],"title":"GoFundMeImportPreview","description":"Preview response with editable fields and metadata"},"GoFundMeImportRequest":{"properties":{"url":{"type":"string","title":"Url","description":"GoFundMe campaign URL"}},"type":"object","required":["url"],"title":"GoFundMeImportRequest","description":"Request schema for GoFundMe campaign import"},"GoFundMeMigrationRequest":{"properties":{"source_url":{"type":"string","title":"Source Url","description":"Original GoFundMe campaign URL"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Deprecated - session email is used"},"consent":{"type":"boolean","title":"Consent","description":"User has consented to migration"},"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title","description":"Campaign title"},"description":{"type":"string","minLength":1,"title":"Description","description":"Campaign description"},"goal":{"type":"number","exclusiveMinimum":0.0,"title":"Goal","description":"Fundraising goal amount"},"location":{"type":"string","minLength":1,"title":"Location","description":"Campaign location"},"category_id":{"type":"string","title":"Category Id","description":"OpenGiving category ID"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name","description":"Organizer name from GoFundMe"},"images":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Images","description":"Image URLs scraped from the source campaign"}},"type":"object","required":["source_url","consent","title","description","goal","location","category_id"],"title":"GoFundMeMigrationRequest","description":"Request schema for migrating a GoFundMe campaign (no auth required)"},"GoFundMeMigrationResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the migration was successful","default":true},"campaign_id":{"type":"string","title":"Campaign Id","description":"Created campaign ID"},"campaign_ticker":{"type":"string","title":"Campaign Ticker","description":"Campaign ticker/slug"},"user_id":{"type":"string","title":"User Id","description":"User ID (new or existing)"},"is_new_user":{"type":"boolean","title":"Is New User","description":"Whether a new account was created"},"email":{"type":"string","title":"Email","description":"Email address of the organizer"},"message":{"type":"string","title":"Message","description":"Success message"}},"type":"object","required":["campaign_id","campaign_ticker","user_id","is_new_user","email","message"],"title":"GoFundMeMigrationResponse","description":"Response schema for successful migration"},"GoFundMeRefreshRequest":{"properties":{"gofundme_url":{"type":"string","title":"Gofundme Url","description":"GoFundMe campaign URL to scrape data from"}},"type":"object","required":["gofundme_url"],"title":"GoFundMeRefreshRequest","description":"Request schema for refreshing GoFundMe data on an existing campaign"},"GoFundMeRefreshResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the refresh was successful","default":true},"campaign_id":{"type":"string","title":"Campaign Id","description":"Campaign ID that was updated"},"gofundme_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gofundme Raised","description":"Raised amount from GoFundMe"},"source_url":{"type":"string","title":"Source Url","description":"GoFundMe URL that was scraped"},"updated_at":{"type":"string","title":"Updated At","description":"Timestamp of the update"},"message":{"type":"string","title":"Message","description":"Status message"}},"type":"object","required":["campaign_id","source_url","updated_at","message"],"title":"GoFundMeRefreshResponse","description":"Response schema for GoFundMe data refresh"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthStatus":{"properties":{"status":{"type":"string","enum":["ok","degraded"],"title":"Status"},"service":{"type":"string","title":"Service"},"components":{"additionalProperties":{"type":"string","enum":["ok","down"]},"type":"object","title":"Components"}},"type":"object","required":["status","service","components"],"title":"HealthStatus","description":"How the service is, part by part, for anyone who asks.\n\nA part is \"ok\" or \"down\". The whole is \"ok\" when every part is, and\n\"degraded\" otherwise: the API answering at all means it isn't down.\nNothing here says why a part is down; that goes to the log."},"HeldEscrow":{"properties":{"transaction_id":{"type":"string","title":"Transaction Id"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Type"},"seller_id":{"type":"string","title":"Seller Id"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"seller_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Email"},"seller_amount":{"type":"number","title":"Seller Amount"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_amount":{"type":"number","title":"Campaign Amount"},"total_amount":{"type":"number","title":"Total Amount"},"delivery_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Status"},"paid_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paid At"},"days_held":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Held"}},"type":"object","required":["transaction_id","seller_id","seller_amount","campaign_amount","total_amount"],"title":"HeldEscrow"},"HeldPayout":{"properties":{"id":{"type":"string","title":"Id"},"recipient_id":{"type":"string","title":"Recipient Id"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"recipient_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Email"},"source":{"type":"string","title":"Source","description":"sale_seller, sale_campaign or donation"},"transaction_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contribution Id"},"amount":{"type":"number","title":"Amount"},"is_test_mode":{"type":"boolean","title":"Is Test Mode"},"status":{"type":"string","title":"Status","description":"held or owed_on_request"},"held_since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Held Since","description":"ISO 8601"},"owed_since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owed Since","description":"ISO 8601"},"days_held":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Held"},"has_stripe_account":{"type":"boolean","title":"Has Stripe Account","default":false}},"type":"object","required":["id","recipient_id","source","amount","is_test_mode","status"],"title":"HeldPayout","description":"One recipient's share of one card payment, still to be paid."},"ImageDeleteResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"type":"string","title":"Message","default":"Image deleted successfully"},"image_id":{"type":"string","title":"Image Id","description":"ID of the deleted image"},"entity_id":{"type":"string","title":"Entity Id","description":"ID of the campaign or product"},"deleted_image_url":{"type":"string","title":"Deleted Image Url","description":"URL of the deleted image"}},"type":"object","required":["image_id","entity_id","deleted_image_url"],"title":"ImageDeleteResponse"},"ImageReorderRequest":{"properties":{"image_orders":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Image Orders","description":"List of objects with id_image and display_order keys"}},"type":"object","required":["image_orders"],"title":"ImageReorderRequest","examples":[{"image_orders":[{"display_order":1,"id_image":"uuid-1"},{"display_order":2,"id_image":"uuid-2"}]}]},"ImageReorderResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"type":"string","title":"Message","default":"Images reordered successfully"},"entity_id":{"type":"string","title":"Entity Id","description":"ID of the campaign or product"},"images":{"items":{"$ref":"#/components/schemas/ImageResponse"},"type":"array","title":"Images","description":"Updated images in new order"}},"type":"object","required":["entity_id","images"],"title":"ImageReorderResponse"},"ImageResponse":{"properties":{"image_url":{"type":"string","title":"Image Url","description":"CloudFront URL of the image"},"display_order":{"type":"integer","minimum":1.0,"title":"Display Order","description":"Display order (1-based)"},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this is the primary image","default":false},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text","description":"Alt text for accessibility"},"file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size","description":"File size in bytes"},"file_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type","description":"MIME type of the image"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"Image width in pixels"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"Image height in pixels"},"id_image":{"type":"string","title":"Id Image","description":"Unique image identifier"},"entity_id":{"type":"string","title":"Entity Id","description":"ID of the campaign or product"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["image_url","display_order","id_image","entity_id","created_at","updated_at"],"title":"ImageResponse"},"ImageUploadResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"url":{"type":"string","title":"Url","description":"CloudFront URL of uploaded image"},"image_id":{"type":"string","title":"Image Id","description":"Database ID of the created image record"},"entity_id":{"type":"string","title":"Entity Id","description":"ID of the campaign or product"},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this image was set as primary"},"display_order":{"type":"integer","title":"Display Order","description":"Display order assigned to this image"}},"type":"object","required":["url","image_id","entity_id","is_primary","display_order"],"title":"ImageUploadResponse"},"ImagesListResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"entity_id":{"type":"string","title":"Entity Id","description":"ID of the campaign or product"},"entity_type":{"type":"string","title":"Entity Type","description":"Type: 'campaign' or 'product'"},"total_count":{"type":"integer","title":"Total Count","description":"Total number of images"},"images":{"items":{"$ref":"#/components/schemas/ImageResponse"},"type":"array","title":"Images","description":"List of images"}},"type":"object","required":["entity_id","entity_type","total_count","images"],"title":"ImagesListResponse"},"ImpactMetrics":{"properties":{"meals_provided":{"type":"integer","title":"Meals Provided","description":"Estimated meals provided","default":0},"books_donated":{"type":"integer","title":"Books Donated","description":"Estimated books donated","default":0},"days_of_clean_water":{"type":"integer","title":"Days Of Clean Water","description":"Estimated days of clean water","default":0},"trees_planted":{"type":"integer","title":"Trees Planted","description":"Estimated trees planted","default":0},"animals_sheltered":{"type":"integer","title":"Animals Sheltered","description":"Estimated animals sheltered","default":0},"medical_supplies":{"type":"integer","title":"Medical Supplies","description":"Estimated medical supply kits","default":0}},"type":"object","title":"ImpactMetrics","description":"Estimated impact metrics based on donation amount"},"IndexNowStatus":{"properties":{"configured":{"type":"boolean","title":"Configured","description":"Production, with a key. False everywhere else, and then the loop is not running at all."},"interval_seconds":{"type":"integer","title":"Interval Seconds","description":"How often the loop wakes"},"submitted_through":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitted Through","description":"ISO 8601. The watermark: every change before this has been dealt with. Null when no pass has ever finished."},"behind_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Behind Seconds","description":"How far behind now the watermark is. Around interval_seconds on a healthy job; null when there is no watermark."},"last_sweep":{"anyOf":[{"$ref":"#/components/schemas/IndexNowSweep"},{"type":"null"}],"description":"Null when no pass has run since this was deployed, or when Redis is unreachable."}},"type":"object","required":["configured","interval_seconds"],"title":"IndexNowStatus","description":"GET /admin/indexnow."},"IndexNowSweep":{"properties":{"at":{"type":"string","title":"At","description":"ISO 8601, when the pass ended"},"outcome":{"type":"string","title":"Outcome","description":"submitted: the endpoint took the URLs. nothing-changed: the window was empty, which is the usual answer. flood-skipped: more than FLOOD_CEILING rows moved, so it was a bulk update and was not sent. refused: the endpoint would not take it, and the watermark stayed put so the next pass retries the same window. read-failed: the database would not say what changed."},"window_from":{"type":"string","title":"Window From","description":"ISO 8601, the watermark this pass read from"},"found":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Found","description":"Rows that moved in the window, or null when it could not be read"},"submitted":{"type":"integer","title":"Submitted","description":"URLs the endpoint accepted"}},"type":"object","required":["at","outcome","window_from","submitted"],"title":"IndexNowSweep","description":"What one pass did, as `services.indexnow` wrote it down."},"ItemBreakdown":{"properties":{"product_id":{"type":"string","title":"Product Id","description":"Product ID"},"product_title":{"type":"string","title":"Product Title","description":"Product title at time of checkout"},"price":{"type":"number","title":"Price","description":"Item price"},"seller_id":{"type":"string","title":"Seller Id","description":"Seller user ID"},"campaign_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Id","description":"Campaign ID if linked"},"donation_pct":{"type":"integer","title":"Donation Pct","description":"Percentage going to campaign"},"seller_amount":{"type":"number","title":"Seller Amount","description":"Amount going to seller after fees"},"campaign_amount":{"type":"number","title":"Campaign Amount","description":"Amount going to campaign"}},"type":"object","required":["product_id","product_title","price","seller_id","donation_pct","seller_amount","campaign_amount"],"title":"ItemBreakdown","description":"Fee breakdown for a single item. Money goes out as JSON numbers."},"ItemRecipients":{"properties":{"product_id":{"type":"string","title":"Product Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"The item's title, only when the cart holds more than one item"},"rows":{"items":{"$ref":"#/components/schemas/RecipientRow"},"type":"array","title":"Rows"}},"type":"object","required":["product_id","rows"],"title":"ItemRecipients","description":"Where one item's price and flat fee go. The rows add up to both."},"LedgerAuditReport":{"properties":{"checked_at":{"type":"string","title":"Checked At","description":"ISO 8601"},"clean":{"type":"boolean","title":"Clean","description":"No findings and no check errored"},"total_findings":{"type":"integer","title":"Total Findings"},"counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Counts","description":"Rows found, by check"},"findings":{"$ref":"#/components/schemas/LedgerFindings"},"errors":{"additionalProperties":{"type":"string"},"type":"object","title":"Errors","description":"A check that raised, and what it raised"}},"type":"object","required":["checked_at","clean","total_findings","counts","findings","errors"],"title":"LedgerAuditReport","description":"GET /admin/ledger-audit."},"LedgerFindings":{"properties":{"campaign_raised":{"anyOf":[{"items":{"$ref":"#/components/schemas/CampaignRaisedDrift"},"type":"array"},{"type":"null"}],"title":"Campaign Raised"},"wallet_balance":{"anyOf":[{"items":{"$ref":"#/components/schemas/WalletBalanceDrift"},"type":"array"},{"type":"null"}],"title":"Wallet Balance"},"escrow_credited":{"anyOf":[{"items":{"$ref":"#/components/schemas/UncreditedEscrow"},"type":"array"},{"type":"null"}],"title":"Escrow Credited"},"split_integrity":{"anyOf":[{"items":{"$ref":"#/components/schemas/SplitOverrun"},"type":"array"},{"type":"null"}],"title":"Split Integrity"},"profile_donated":{"anyOf":[{"items":{"$ref":"#/components/schemas/ProfileDonatedDrift"},"type":"array"},{"type":"null"}],"title":"Profile Donated"},"wallet_lifetime":{"anyOf":[{"items":{"$ref":"#/components/schemas/WalletLifetimeDrift"},"type":"array"},{"type":"null"}],"title":"Wallet Lifetime"},"claim_transferred":{"anyOf":[{"items":{"$ref":"#/components/schemas/StrandedClaimMoney"},"type":"array"},{"type":"null"}],"title":"Claim Transferred"},"campaign_count_ceiling":{"anyOf":[{"items":{"$ref":"#/components/schemas/CampaignCountCeiling"},"type":"array"},{"type":"null"}],"title":"Campaign Count Ceiling"},"stripe_covers_held_escrow":{"anyOf":[{"items":{"$ref":"#/components/schemas/StripeEscrowCoverage"},"type":"array"},{"type":"null"}],"title":"Stripe Covers Held Escrow"},"service_fee_recorded":{"anyOf":[{"items":{"$ref":"#/components/schemas/ServiceFeeUnrecorded"},"type":"array"},{"type":"null"}],"title":"Service Fee Recorded"}},"type":"object","title":"LedgerFindings","description":"The rows each check that ran found; empty is healthy."},"LegacyAddressCheck":{"properties":{"valid":{"type":"boolean","title":"Valid"},"verified":{"type":"boolean","title":"Verified"},"confidence":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Confidence","description":"high, medium, low or unknown"},"suggestions":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Suggestions","description":"Always empty"},"standardized_address":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Standardized Address","description":"Google's one-line formatted address, or {} when it gave none"},"validation_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validation Source","description":"'google' or 'internal'"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why it wasn't checked"}},"type":"object","required":["valid","verified"],"title":"LegacyAddressCheck","description":"POST /locations/validate-address, the shape web's locationService reads.\n\nSent without unset keys: a request missing street, city or state gets\nvalid, verified and error; a checked one gets the other five."},"LevelInfo":{"properties":{"user_id":{"type":"string","title":"User Id","description":"User ID"},"level":{"type":"integer","title":"Level","description":"Current level"},"total_xp":{"type":"integer","title":"Total Xp","description":"Total XP earned"},"xp_progress_current_level":{"type":"integer","title":"Xp Progress Current Level","description":"XP progress within current level"},"xp_required_next_level":{"type":"integer","title":"Xp Required Next Level","description":"XP required to reach next level"},"progress_percentage":{"type":"number","title":"Progress Percentage","description":"Progress percentage to next level"},"tier_name":{"type":"string","title":"Tier Name","description":"Tier name (Beginner, Bronze, Silver, etc.)"},"tier_color":{"type":"string","title":"Tier Color","description":"Tier color in hex"},"total_xp_for_current_level":{"type":"integer","title":"Total Xp For Current Level","description":"Total XP required to reach current level"},"total_xp_for_next_level":{"type":"integer","title":"Total Xp For Next Level","description":"Total XP required to reach next level"}},"type":"object","required":["user_id","level","total_xp","xp_progress_current_level","xp_required_next_level","progress_percentage","tier_name","tier_color","total_xp_for_current_level","total_xp_for_next_level"],"title":"LevelInfo","description":"Detailed level information for a user"},"LevelTier":{"properties":{"name":{"type":"string","title":"Name","description":"Beginner, Bronze, Silver, Gold, Platinum or Diamond"},"color":{"type":"string","title":"Color","description":"Hex colour"}},"type":"object","required":["name","color"],"title":"LevelTier","description":"A band of levels' name and colour."},"LocalizationConfig":{"properties":{"default_locale":{"type":"string","title":"Default Locale"},"supported_locales":{"items":{"type":"string"},"type":"array","title":"Supported Locales"}},"type":"object","required":["default_locale","supported_locales"],"title":"LocalizationConfig","description":"Which languages the clients may offer.\n\nLanguage only. Which campaigns someone sees by default is a separate\nquestion — a Brazilian in Boston wants Portuguese and US campaigns — and\nkeeping the two apart here is what stops the app from being unable to\nexpress that person later.\n\nA client should offer the intersection of `supported_locales` and the\ncatalogues it actually ships, so a tag can be added here before the\ntranslations exist without breaking anyone, and removing one withdraws it\nfrom every client at once instead of waiting on two store reviews."},"MagicCampaignRequest":{"properties":{"images_base64":{"items":{"type":"string"},"type":"array","title":"Images Base64","description":"Base64-encoded images representing the campaign (1-5 images)"},"user_description":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"User Description","description":"Optional user-provided description"}},"type":"object","required":["images_base64"],"title":"MagicCampaignRequest","description":"Request schema for AI-powered magic campaign generation"},"MagicCampaignResponse":{"properties":{"title":{"type":"string","title":"Title","description":"AI-generated campaign title"},"description":{"type":"string","title":"Description","description":"AI-generated campaign description"},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Category Id","description":"Matched category ID"},"category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category Name","description":"Matched category name"},"suggested_goal":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":1.0},{"type":"null"}],"title":"Suggested Goal","description":"AI-suggested fundraising goal"},"confidence_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence Score","description":"AI confidence score (0-1)"},"suggested_keywords":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Suggested Keywords","description":"Suggested keywords for the campaign"}},"type":"object","required":["title","description","confidence_score"],"title":"MagicCampaignResponse","description":"Response schema for AI-generated campaign data"},"MagicListingRequest":{"properties":{"images_base64":{"items":{"type":"string"},"type":"array","title":"Images Base64","description":"Base64-encoded images of the product (1-5 images)"},"user_description":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"User Description","description":"Optional user-provided description"}},"type":"object","required":["images_base64"],"title":"MagicListingRequest","description":"Request schema for AI-powered magic listing generation"},"MagicListingResponse":{"properties":{"title":{"type":"string","title":"Title","description":"AI-generated product title"},"description":{"type":"string","title":"Description","description":"AI-generated product description"},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Category Id","description":"Matched category ID"},"category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category Name","description":"Matched category name"},"condition":{"type":"string","title":"Condition","description":"AI-determined condition (new/like new/good/fair/poor)"},"suggested_price":{"anyOf":[{"type":"number","maximum":100000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Suggested Price","description":"AI-suggested price in dollars; clamped to MINIMUM_LISTING_PRICE"},"confidence_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence Score","description":"AI confidence score (0-1)"},"suggested_keywords":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Suggested Keywords","description":"Suggested keywords for the listing"}},"type":"object","required":["title","description","condition","confidence_score"],"title":"MagicListingResponse","description":"Response schema for AI-generated listing data"},"MainCampaignImageDeleted":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"message":{"type":"string","title":"Message"},"campaign_id":{"type":"string","title":"Campaign Id"},"deleted_image_url":{"type":"string","title":"Deleted Image Url"}},"type":"object","required":["success","message","campaign_id","deleted_image_url"],"title":"MainCampaignImageDeleted","description":"DELETE /images/delete/campaign/{id}: the campaign's primary image,\nremoved. Web wraps it; nothing calls it."},"MainProductImageDeleted":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"message":{"type":"string","title":"Message"},"product_id":{"type":"string","title":"Product Id"},"deleted_image_url":{"type":"string","title":"Deleted Image Url"}},"type":"object","required":["success","message","product_id","deleted_image_url"],"title":"MainProductImageDeleted","description":"DELETE /images/delete/product/{id}: the product's primary image,\nremoved. Web wraps it; nothing calls it."},"MarkPaidRequest":{"properties":{"payout_reference":{"type":"string","maxLength":200,"minLength":1,"title":"Payout Reference","description":"PayPal transaction id (or equivalent) of the payout that was sent"}},"type":"object","required":["payout_reference"],"title":"MarkPaidRequest"},"MarketplaceCheckoutRequest":{"properties":{"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id","description":"Transaction ID"},"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount","description":"Total payment amount"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Seller user ID"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id","description":"Campaign ID for donation portion"},"donation_percentage":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Donation Percentage","description":"Percentage going to campaign","default":0},"platform_tip":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional platform tip","default":"0"},"customer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email","description":"Customer email"},"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"Return URL after payment"}},"type":"object","required":["transaction_id","amount","seller_id"],"title":"MarketplaceCheckoutRequest","description":"Request to initiate marketplace checkout with Stripe"},"MarketplaceCheckoutResponse":{"properties":{"payment_intent_id":{"type":"string","title":"Payment Intent Id","description":"Stripe PaymentIntent ID"},"client_secret":{"type":"string","title":"Client Secret","description":"Client secret for frontend"},"amount":{"type":"integer","title":"Amount","description":"Amount in cents"},"fee_breakdown":{"$ref":"#/components/schemas/FeeCalculationResponse","description":"Fee breakdown"},"transfer_group":{"type":"string","title":"Transfer Group","description":"Transfer group for escrow"}},"type":"object","required":["payment_intent_id","client_secret","amount","fee_breakdown","transfer_group"],"title":"MarketplaceCheckoutResponse","description":"Marketplace checkout response"},"MarketplaceOrderRequest":{"properties":{"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"e.g. opengiving://paypal-return"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url","description":"e.g. opengiving://paypal-cancel"},"transaction_id":{"type":"string","title":"Transaction Id","description":"A pending transactions row owned by the caller"}},"type":"object","required":["transaction_id"],"title":"MarketplaceOrderRequest"},"MarketplaceOrderResponse":{"properties":{"order_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Order Value"},"processing_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Processing Fee"},"total_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Charged"},"order_id":{"type":"string","title":"Order Id"},"transaction_id":{"type":"string","title":"Transaction Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"approve_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approve Url"}},"type":"object","required":["order_id","transaction_id"],"title":"MarketplaceOrderResponse"},"MerchantAccountCreateRequest":{"properties":{"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"email":{"type":"string","title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"street_address":{"type":"string","title":"Street Address"},"city":{"type":"string","title":"City"},"state":{"type":"string","title":"State"},"postal_code":{"type":"string","title":"Postal Code"},"account_type":{"type":"string","pattern":"^(individual|business)$","title":"Account Type","default":"individual"},"ssn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ssn"},"business_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Name"},"tax_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Id"},"account_number":{"type":"string","title":"Account Number"},"routing_number":{"type":"string","title":"Routing Number"},"accept_terms":{"type":"boolean","title":"Accept Terms","default":true}},"type":"object","required":["first_name","last_name","email","street_address","city","state","postal_code","account_number","routing_number"],"title":"MerchantAccountCreateRequest","description":"Request to create a merchant account for payouts (Stripe Express today)"},"MerchantAccountCreateResponse":{"properties":{"merchant_account_id":{"type":"string","title":"Merchant Account Id"},"status":{"type":"string","title":"Status"},"message":{"type":"string","title":"Message"}},"type":"object","required":["merchant_account_id","status","message"],"title":"MerchantAccountCreateResponse","description":"Response after creating merchant account"},"MerchantAccountResponse":{"properties":{"has_merchant_account":{"type":"boolean","title":"Has Merchant Account"},"merchant_account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Merchant Account Id"},"status":{"type":"string","title":"Status"},"can_withdraw":{"type":"boolean","title":"Can Withdraw"}},"type":"object","required":["has_merchant_account","merchant_account_id","status","can_withdraw"],"title":"MerchantAccountResponse","description":"Response with merchant account status"},"Message":{"properties":{"message":{"type":"string","title":"Message","description":"What happened, in English"}},"type":"object","required":["message"],"title":"Message","description":"{\"message\": ...}"},"MinimumAppVersion":{"properties":{"ios":{"$ref":"#/components/schemas/PlatformVersionPolicy"},"android":{"$ref":"#/components/schemas/PlatformVersionPolicy"}},"type":"object","required":["ios","android"],"title":"MinimumAppVersion","description":"Force-upgrade policy, per platform.\n\nPublished rather than evaluated here on purpose: this endpoint answers the\nsame document to everyone and is cacheable, while \"is THIS build too old\"\ndepends on who is asking. The caller compares — component-wise and\nnumerically, so 1.10.0 is newer than 1.9.0 rather than older, which a string\ncomparison gets backwards.\n\nThis policy previously existed only in the environment variables of an AWS\nLambda that nothing in these repos referenced. Serving it from here is what\nlets it be read, reviewed and changed in one place."},"MonetaryLimits":{"properties":{"minimum_listing_price":{"type":"number","title":"Minimum Listing Price"},"minimum_donation_amount":{"type":"number","title":"Minimum Donation Amount"},"minimum_withdrawal_amount":{"type":"number","title":"Minimum Withdrawal Amount"},"minimum_donation_pct":{"type":"integer","title":"Minimum Donation Pct"}},"type":"object","required":["minimum_listing_price","minimum_donation_amount","minimum_withdrawal_amount","minimum_donation_pct"],"title":"MonetaryLimits","description":"The floors every client must agree with the server about.\n\nPublished because three clients had been keeping their own copies and all\nthree had drifted: web enforced $1.00 in five separate listing forms,\nAndroid allowed a one-cent listing, and iOS enforced nothing at all. A\nclient that guesses low sends a request the server refuses; one that\nguesses high blocks a listing the server would accept."},"MyDonation":{"properties":{"id":{"type":"string","title":"Id","description":"The contribution's id"},"type":{"type":"string","title":"Type","description":"'direct': these rows are direct donations"},"amount":{"type":"number","title":"Amount","description":"Amount donated, in dollars"},"campaign_id":{"type":"string","title":"Campaign Id","description":"The campaign's id"},"campaign_title":{"type":"string","title":"Campaign Title","description":"The campaign's title; 'Campaign Deleted', or the title with ' (Deleted)', once it is gone"},"campaign_status":{"type":"string","title":"Campaign Status","description":"The campaign's status; 'deleted' once it is gone"},"campaign_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Slug","description":"Always null"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"The donor's message"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the donation is anonymous"},"payment_status":{"type":"string","title":"Payment Status","description":"Payment status; 'pending' when none is recorded"},"date":{"type":"string","title":"Date","description":"When the donation was made, ISO 8601; empty when unknown"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title","description":"Always null: these are direct donations"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id","description":"Always null: these are direct donations"},"refund_status":{"anyOf":[{"type":"string","enum":["pending","approved","processed","denied"]},{"type":"null"}],"title":"Refund Status","description":"Where the donor's refund request stands: pending (waiting on the organizer or OpenGiving), approved (on its way), processed (refunded) or denied. A refund that went through is reported over a newer one that didn't. Null when no refund was asked for"},"refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refund Id","description":"The id of the refund refund_status describes; null when there is none"},"refund_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Refund Amount","description":"That refund's amount, in dollars; null when there is none"},"payment_breakdown":{"anyOf":[{"$ref":"#/components/schemas/DonationPaymentBreakdown"},{"type":"null"}],"description":"What the donor paid and where it went, as rows to show. Every row of these routes is the caller's own donation"}},"type":"object","required":["id","type","amount","campaign_id","campaign_title","campaign_status","anonymous","payment_status","date"],"title":"MyDonation","description":"One row of GET /direct_contributions/my-donations (and its /search).\n\nEvery key the route has always sent, including the ones it always sends\nnull, because the clients decode them: Android requires id, amount,\ncampaign_id, campaign_title, payment_status and date as non-null, and\n`anonymous` may not be null; iOS requires id, type, amount, campaign_id,\nanonymous and date; web reads nearly all of them."},"MyRefundRequest":{"properties":{"refund_type":{"type":"string","title":"Refund Type"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"original_amount":{"type":"number","title":"Original Amount"},"refund_amount":{"type":"number","title":"Refund Amount"},"requester_id":{"type":"string","format":"uuid","title":"Requester Id"},"recipient_id":{"type":"string","format":"uuid","title":"Recipient Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"},"id_refund":{"type":"string","format":"uuid","title":"Id Refund"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name"},"donor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Donor Name"},"requester_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Name"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"admin_reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Reviewer Name"},"decision":{"anyOf":[{"type":"string","enum":["approved","declined"]},{"type":"null"}],"title":"Decision","description":"What the last decision on it was; null while pending"},"decided_by":{"anyOf":[{"type":"string","enum":["seller","organizer","opengiving"]},{"type":"null"}],"title":"Decided By","description":"Who made that decision: the seller, the campaign's organizer, or OpenGiving; null while pending"},"decline_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decline Reason","description":"The reason it was declined with, as the decider gave it to the payer; null unless declined with one"},"outcome":{"anyOf":[{"type":"string","enum":["refunded","in_progress","waiting_on_opengiving","declined","failed"]},{"type":"null"}],"title":"Outcome","description":"How it ended, as on the history routes; null while pending"}},"type":"object","required":["refund_type","original_amount","refund_amount","requester_id","recipient_id","reason","id_refund","status","created_at","updated_at"],"title":"MyRefundRequest","description":"GET /refunds/refunds/my-requests: a refund the caller asked for, as the\nbuyer or donor sees it.\n\nadmin_notes, admin_reviewer_id and admin_reviewer_name are always null\nhere. They held notes written for admins (a provider's error, why it was\nparked), an approver's notes, and whoever reviewed it, which can be an\nadmin. The keys stay for clients that decode them. What the payer is\nmeant to read is below: all null while the refund is pending."},"NameUpdate":{"properties":{"first_name":{"type":"string","maxLength":100,"minLength":1,"title":"First Name"},"last_name":{"type":"string","maxLength":100,"title":"Last Name","default":""}},"type":"object","required":["first_name"],"title":"NameUpdate","description":"The caller's own name. First name required; last name may be empty."},"NeutralCartRequest":{"properties":{"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"e.g. opengiving://paypal-return"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url","description":"e.g. opengiving://paypal-cancel"},"items":{"items":{"$ref":"#/components/schemas/CheckoutItem"},"type":"array","maxItems":50,"minItems":1,"title":"Items","description":"Items to checkout"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional platform tip","default":"0"},"shipping_address":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddressSchema"},{"type":"null"}],"description":"Shipping address (required only if any item is shippable)"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id","description":"Use a saved address instead of the inline one"},"customer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Email","description":"Customer email for receipt"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Keep the buyer's name off each campaign's public donor list","default":false},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"}},"type":"object","required":["items"],"title":"NeutralCartRequest"},"NeutralContributionRequest":{"properties":{"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"e.g. opengiving://paypal-return"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url","description":"e.g. opengiving://paypal-cancel"},"contribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contribution Id","description":"An existing direct_contributions row"},"campaign_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Id","description":"Campaign to contribute to"},"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Amount","description":"Contribution amount, excluding the tip"},"platform_tip":{"type":"number","maximum":10000.0,"minimum":0.0,"title":"Platform Tip","description":"Optional tip to OpenGiving","default":0},"message":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Message"},"anonymous":{"type":"boolean","title":"Anonymous","default":false},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider","description":"paypal or stripe; omit to let the server choose"}},"type":"object","title":"NeutralContributionRequest"},"NeutralMarketplaceRequest":{"properties":{"return_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Return Url","description":"e.g. opengiving://paypal-return"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url","description":"e.g. opengiving://paypal-cancel"},"transaction_id":{"type":"string","title":"Transaction Id","description":"A pending transactions row owned by the caller"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"}},"type":"object","required":["transaction_id"],"title":"NeutralMarketplaceRequest"},"NewsletterConfirm":{"properties":{"token":{"type":"string","title":"Token","description":"The token from the confirmation email's link","default":""}},"type":"object","title":"NewsletterConfirm"},"NewsletterRefusal":{"properties":{"detail":{"type":"string","title":"Detail","description":"Why, in English"},"code":{"type":"string","enum":["invalid_link","send_failed","subscribe_failed"],"title":"Code","description":"invalid_link: the token isn't one this service signed for the newsletter; send_failed: the confirmation email couldn't be sent; subscribe_failed: the mailing list refused the address"}},"type":"object","required":["detail","code"],"title":"NewsletterRefusal","description":"What the newsletter routes answer when they don't do it.\n\n`code` says why and doesn't change, so a client words it itself. `detail`\nis an English sentence of ours."},"NewsletterSubscribe":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"The address to send the confirmation link to"},"locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locale","description":"The reader's language, e.g. pt-BR"}},"type":"object","required":["email"],"title":"NewsletterSubscribe"},"NextLevelXP":{"properties":{"current_level":{"type":"integer","title":"Current Level"},"next_level":{"type":"integer","title":"Next Level"},"xp_required_for_next_level":{"type":"integer","title":"Xp Required For Next Level","description":"XP from current_level to next_level"},"total_xp_for_next_level":{"type":"integer","title":"Total Xp For Next Level","description":"XP from level 1 to next_level"}},"type":"object","required":["current_level","next_level","xp_required_for_next_level","total_xp_for_next_level"],"title":"NextLevelXP","description":"GET /xp/next-level-xp/{level}. Web wraps it with other key names; no\nscreen calls it."},"Notification":{"properties":{"notification_type":{"type":"string","title":"Notification Type","description":"Type of notification"},"title":{"type":"string","maxLength":255,"title":"Title","description":"Notification title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Notification content"},"notification_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Notification Metadata","description":"Additional metadata"},"related_entity_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Related Entity Type","description":"Related entity type"},"related_entity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Related Entity Id","description":"Related entity ID"},"priority":{"type":"string","enum":["low","normal","high","urgent"],"title":"Priority","description":"Notification priority","default":"normal"},"id_notification":{"type":"string","format":"uuid","title":"Id Notification","description":"Notification ID"},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"User ID"},"is_read":{"type":"boolean","title":"Is Read","description":"Read status","default":false},"is_archived":{"type":"boolean","title":"Is Archived","description":"Archive status","default":false},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Expiration date"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["notification_type","title","id_notification","user_id","created_at"],"title":"Notification"},"NotificationClickTrack":{"properties":{"notificationId":{"type":"string","title":"Notificationid","description":"ID of notification log entry"},"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"Action taken (click, dismiss, etc.)"},"timestamp":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timestamp","description":"Client timestamp of click"}},"type":"object","required":["notificationId"],"title":"NotificationClickTrack","description":"Schema for tracking notification clicks."},"NotificationCreate":{"properties":{"notification_type":{"type":"string","title":"Notification Type","description":"Type of notification"},"title":{"type":"string","maxLength":255,"title":"Title","description":"Notification title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Notification content"},"notification_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Notification Metadata","description":"Additional metadata"},"related_entity_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Related Entity Type","description":"Related entity type"},"related_entity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Related Entity Id","description":"Related entity ID"},"priority":{"type":"string","enum":["low","normal","high","urgent"],"title":"Priority","description":"Notification priority","default":"normal"},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"User ID to send notification to"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Expiration date"}},"type":"object","required":["notification_type","title","user_id"],"title":"NotificationCreate"},"NotificationPreferences":{"properties":{"email_enabled":{"type":"boolean","title":"Email Enabled","description":"Enable email notifications","default":true},"push_enabled":{"type":"boolean","title":"Push Enabled","description":"Enable push notifications","default":true},"campaign_updates":{"type":"boolean","title":"Campaign Updates","description":"Campaign update notifications","default":true},"donation_received":{"type":"boolean","title":"Donation Received","description":"Donation received notifications","default":true},"product_sold":{"type":"boolean","title":"Product Sold","description":"Product sold notifications","default":true},"offers":{"type":"boolean","title":"Offers","description":"Offer notifications","default":true},"system_announcements":{"type":"boolean","title":"System Announcements","description":"System announcement notifications","default":true},"marketing_enabled":{"type":"boolean","title":"Marketing Enabled","description":"Marketing notifications","default":false},"id_preference":{"type":"string","format":"uuid","title":"Id Preference","description":"Preference ID"},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"User ID"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["id_preference","user_id","created_at"],"title":"NotificationPreferences"},"NotificationPreferencesUpdate":{"properties":{"email_enabled":{"type":"boolean","title":"Email Enabled","description":"Enable email notifications","default":true},"push_enabled":{"type":"boolean","title":"Push Enabled","description":"Enable push notifications","default":true},"campaign_updates":{"type":"boolean","title":"Campaign Updates","description":"Campaign update notifications","default":true},"donation_received":{"type":"boolean","title":"Donation Received","description":"Donation received notifications","default":true},"product_sold":{"type":"boolean","title":"Product Sold","description":"Product sold notifications","default":true},"offers":{"type":"boolean","title":"Offers","description":"Offer notifications","default":true},"system_announcements":{"type":"boolean","title":"System Announcements","description":"System announcement notifications","default":true},"marketing_enabled":{"type":"boolean","title":"Marketing Enabled","description":"Marketing notifications","default":false}},"type":"object","title":"NotificationPreferencesUpdate"},"NotificationStats":{"properties":{"total_count":{"type":"integer","title":"Total Count","description":"Total notifications"},"unread_count":{"type":"integer","title":"Unread Count","description":"Unread notifications"},"archived_count":{"type":"integer","title":"Archived Count","description":"Archived notifications"}},"type":"object","required":["total_count","unread_count","archived_count"],"title":"NotificationStats"},"NotificationStatsResponse":{"properties":{"total_sent":{"type":"integer","title":"Total Sent"},"total_failed":{"type":"integer","title":"Total Failed"},"total_clicked":{"type":"integer","title":"Total Clicked"},"click_rate":{"type":"number","title":"Click Rate"},"success_rate":{"type":"number","title":"Success Rate"},"type_breakdown":{"additionalProperties":{"type":"integer"},"type":"object","title":"Type Breakdown"},"period_days":{"type":"integer","title":"Period Days"}},"type":"object","required":["total_sent","total_failed","total_clicked","click_rate","success_rate","type_breakdown","period_days"],"title":"NotificationStatsResponse","description":"Schema for notification statistics response."},"NotificationTemplateText":{"properties":{"title":{"type":"string","title":"Title"},"body":{"type":"string","title":"Body"},"type":{"type":"string","title":"Type"},"priority":{"type":"string","title":"Priority"}},"type":"object","required":["title","body","type","priority"],"title":"NotificationTemplateText","description":"What GET /push/templates says about one template."},"NotificationTemplates":{"properties":{"templates":{"items":{"type":"string"},"type":"array","title":"Templates","description":"Every template's name"},"template_data":{"additionalProperties":{"$ref":"#/components/schemas/NotificationTemplateText"},"type":"object","title":"Template Data","description":"Each template, by name"}},"type":"object","required":["templates","template_data"],"title":"NotificationTemplates","description":"GET /push/templates. No client calls it."},"Offer":{"properties":{"id_offer":{"type":"string","format":"uuid","title":"Id Offer"},"product_id":{"type":"string","format":"uuid","title":"Product Id"},"buyer_id":{"type":"string","format":"uuid","title":"Buyer Id"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id"},"amount":{"type":"number","title":"Amount"},"proposed_by":{"type":"string","enum":["buyer","seller"],"title":"Proposed By"},"state":{"type":"string","title":"State","description":"The state to act on: the stored one, except that a pending or accepted offer past its expiry is 'expired' whether or not the sweep has reached it"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"replaces_offer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Replaces Offer Id","description":"The offer this one answers, for a counter"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"decided_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Decided At"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id","description":"The purchase that spent it, once it has been spent"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id_offer","product_id","buyer_id","seller_id","amount","proposed_by","state","expires_at","created_at"],"title":"Offer"},"OfferCounter":{"properties":{"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"}],"title":"Amount","description":"The item price being proposed, in dollars"},"message":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Message","description":"A note to the other side"}},"type":"object","required":["amount"],"title":"OfferCounter","description":"The answerer's different price. Same shape, other direction."},"OfferCreate":{"properties":{"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,2}0*$"}],"title":"Amount","description":"The item price being proposed, in dollars"},"message":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Message","description":"A note to the other side"}},"type":"object","required":["amount"],"title":"OfferCreate","description":"A buyer's opening offer.\n\nThe amount is the item price being proposed, never a total: the tip, the\npostage, the donation share and every fee are worked out from it, the way\nthey are worked out from the listing's own price. Bounds are the database's\n(`amount > 0`) -- the floor that matters is MINIMUM_LISTING_PRICE and the\nceiling is the listing's price, and both are checked in crud/offer.py where\nthe listing is in hand and the answer can say which one refused it."},"OfferList":{"properties":{"offers":{"items":{"$ref":"#/components/schemas/OfferWithContext"},"type":"array","title":"Offers"}},"type":"object","required":["offers"],"title":"OfferList"},"OfferPolicy":{"properties":{"pending_hours":{"type":"integer","title":"Pending Hours"},"accepted_hours":{"type":"integer","title":"Accepted Hours"},"max_pending_per_buyer":{"type":"integer","title":"Max Pending Per Buyer"}},"type":"object","required":["pending_hours","accepted_hours","max_pending_per_buyer"],"title":"OfferPolicy","description":"The clocks an offer runs on.\n\nThere is no switch any more. Offers are part of the marketplace, the way\na cart is, and a flag that is always true is a branch nobody exercises\nand a question every screen has to keep asking.\n\nThe two windows are published rather than compiled in because every\nsurface has to say the same thing about when an offer stops being good --\n\"expires in 3 days\" on one screen and \"2 days\" on another is the same\ndrift the donation floor had, with a price on the end of it.\n\nThe floor an offer is held to is `limits.minimum_listing_price`, which is\nalready published: an offer is a price, and it is held to the price floor.\nThe ceiling is the listing's own price, which the client already has."},"OfferWithContext":{"properties":{"id_offer":{"type":"string","format":"uuid","title":"Id Offer"},"product_id":{"type":"string","format":"uuid","title":"Product Id"},"buyer_id":{"type":"string","format":"uuid","title":"Buyer Id"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id"},"amount":{"type":"number","title":"Amount"},"proposed_by":{"type":"string","enum":["buyer","seller"],"title":"Proposed By"},"state":{"type":"string","title":"State","description":"The state to act on: the stored one, except that a pending or accepted offer past its expiry is 'expired' whether or not the sweep has reached it"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"replaces_offer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Replaces Offer Id","description":"The offer this one answers, for a counter"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"decided_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Decided At"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id","description":"The purchase that spent it, once it has been spent"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Product Price","description":"The listing's own price, to show the offer against"},"other_party":{"anyOf":[{"$ref":"#/components/schemas/UserPublic"},{"type":"null"}],"description":"The person on the other side of this offer, as the reader sees them"}},"type":"object","required":["id_offer","product_id","buyer_id","seller_id","amount","proposed_by","state","expires_at","created_at"],"title":"OfferWithContext","description":"An offer with what a list of them has to draw beside it."},"OwnerType":{"type":"string","enum":["team_member","influencer","partner","affiliate"],"title":"OwnerType","description":"Types of referral code owners"},"PaginatedResponse_CampaignUpdate_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/CampaignUpdate"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[CampaignUpdate]"},"PaginatedResponse_CampaignWithDetails_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/CampaignWithDetails"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[CampaignWithDetails]"},"PaginatedResponse_DirectContribution_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/DirectContribution"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[DirectContribution]"},"PaginatedResponse_DonationRefundHistoryItem_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/DonationRefundHistoryItem"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[DonationRefundHistoryItem]"},"PaginatedResponse_Donor_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Donor"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[Donor]"},"PaginatedResponse_MyDonation_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MyDonation"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[MyDonation]"},"PaginatedResponse_ProductWithCampaignDetails_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ProductWithCampaignDetails"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[ProductWithCampaignDetails]"},"PaginatedResponse_SaleRefundHistoryItem_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SaleRefundHistoryItem"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[SaleRefundHistoryItem]"},"PaginatedResponse_TransactionWithDetails_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/TransactionWithDetails"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[TransactionWithDetails]"},"PaginationMeta":{"properties":{"page":{"type":"integer","title":"Page"},"limit":{"type":"integer","title":"Limit"},"total":{"type":"integer","title":"Total"},"total_pages":{"type":"integer","title":"Total Pages"},"has_next":{"type":"boolean","title":"Has Next"},"has_prev":{"type":"boolean","title":"Has Prev"}},"type":"object","required":["page","limit","total","total_pages","has_next","has_prev"],"title":"PaginationMeta","description":"Pagination metadata"},"PaidPayout":{"properties":{"id":{"type":"string","title":"Id"},"status":{"type":"string","title":"Status"},"paid_to":{"type":"string","title":"Paid To","description":"stripe or wallet"},"amount":{"type":"number","title":"Amount"},"stripe_transfer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Transfer Id"},"wallet_transaction_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wallet Transaction Id"}},"type":"object","required":["id","status","paid_to","amount"],"title":"PaidPayout"},"PayPalAvailability":{"properties":{"available":{"type":"boolean","title":"Available"},"environment":{"type":"string","title":"Environment","description":"'sandbox' or 'live'"},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id","description":"Public PayPal client id; null when unset"}},"type":"object","required":["available","environment"],"title":"PayPalAvailability","description":"GET /paypal/available. Web's PayPalButton reads `available` and\n`client_id`, and hides PayPal when either is missing."},"PayPalWebhookReceipt":{"properties":{"received":{"type":"boolean","title":"Received"},"duplicate":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Duplicate"}},"type":"object","required":["received"],"title":"PayPalWebhookReceipt","description":"What POST /paypal/webhook tells PayPal. `duplicate` is sent only for\nan event already recorded."},"PaymentBreakdown":{"properties":{"buyer_pays":{"items":{"$ref":"#/components/schemas/BuyerPaysRow"},"type":"array","title":"Buyer Pays","description":"items: this item's price. tip: its tip to OpenGiving (a cart item's share of the cart's tip). digital_fee: the flat fee on a digital item. shipping: its postage. Rows that come to nothing aren't sent, except items"},"processing_fee_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Processing Fee Cents","description":"The processing fee the buyer was billed for this item. Null when none was billed, and until it's paid"},"platform_fee_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Platform Fee Cents","description":"OpenGiving's own fee for this item, billed to the buyer on top of the price rather than taken out of the sale. Null when there is none -- a digital item pays its flat fee instead -- and until it's paid"},"fee_kind":{"type":"string","enum":["processing_fee","service_fee"],"title":"Fee Kind","description":"What to call the fee the payer is billed. processing_fee: each rail bills its own processor's fee. service_fee: every rail bills the same fee, so the rails' totals are the same and one total can be shown","default":"processing_fee"},"total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Cents","description":"What the buyer was charged for this item, total_charged in cents. Null until it's paid"}},"type":"object","required":["buyer_pays"],"title":"PaymentBreakdown","description":"What the buyer paid for one purchase, row by row (order_breakdown).\n\nThe rows are the purchase quote's buyer_pays kinds. With the processing\nfee and the platform fee they add up to the total, once there is one."},"PaymentHealth":{"properties":{"status":{"type":"string","title":"Status","description":"'healthy' or 'unhealthy'"},"providers":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Providers","description":"Each rail, and whether it can take a payment"},"modes":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Modes","description":"'live' or 'test'/'sandbox', per live rail"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider","description":"The live rails, comma-separated"},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode","description":"'live' if any rail is live, else 'test'"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"}},"type":"object","required":["status"],"title":"PaymentHealth","description":"GET /payments/health. Three answers: healthy (providers, modes and the\nStripe-era provider and mode), unhealthy with no provider (providers and\nmessage), or unhealthy after an error (message). Each sends only its own\nkeys. No client calls it."},"PaymentIntentResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Stripe PaymentIntent ID (pi_xxx)"},"client_secret":{"type":"string","title":"Client Secret","description":"Client secret for frontend confirmation"},"amount":{"type":"integer","title":"Amount","description":"Amount in cents"},"currency":{"type":"string","title":"Currency","description":"Currency code"},"status":{"type":"string","title":"Status","description":"PaymentIntent status"},"transfer_group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transfer Group","description":"Transfer group for linked transfers"}},"type":"object","required":["id","client_secret","amount","currency","status"],"title":"PaymentIntentResponse","description":"Stripe PaymentIntent creation response"},"PaymentOrderResponse":{"properties":{"provider":{"type":"string","title":"Provider"},"reference":{"type":"string","title":"Reference","description":"PayPal order id, or Stripe PaymentIntent id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"approve_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approve Url"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"},"contribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contribution Id"},"transaction_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transaction Id"},"checkout_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkout Session Id"},"amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount"}},"type":"object","required":["provider","reference"],"title":"PaymentOrderResponse","description":"One checkout, however it was opened.\n\nThe two rails hand back different things — PayPal an approval URL the\npayer visits, Stripe a client secret the app confirms — so both are\noptional and the client uses whichever arrived."},"PaymentStatusResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Stripe PaymentIntent ID"},"status":{"type":"string","title":"Status","description":"Payment status"},"amount":{"type":"integer","title":"Amount","description":"Amount in cents"},"currency":{"type":"string","title":"Currency","description":"Currency code"},"transfer_group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transfer Group","description":"Transfer group"},"charges":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Charges","description":"Associated charges"},"receipt_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Receipt Url","description":"Receipt URL if available"}},"type":"object","required":["id","status","amount","currency"],"title":"PaymentStatusResponse","description":"Payment status response"},"PaymentsAvailability":{"properties":{"card_payments":{"type":"boolean","title":"Card Payments","description":"Whether the caller may pay by card. Asked with product_ids, whether they may pay by card for all of those listings together"},"paypal":{"type":"boolean","title":"Paypal"},"paypal_client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paypal Client Id"},"paypal_environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paypal Environment"},"card_payments_by_product":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Card Payments By Product","description":"Only when product_ids were given: each listing id, and whether it can be paid by card. Every listing that exists can be while cards are on, whether or not its seller has connected Stripe; false for an id that isn't a listing"}},"type":"object","required":["card_payments","paypal"],"title":"PaymentsAvailability","description":"Which payment rails are live right now — the one probe every client\nmakes before rendering a checkout. Public: nothing here is secret."},"PayoutActionResponse":{"properties":{"withdrawal_id":{"type":"string","title":"Withdrawal Id"},"status":{"type":"string","title":"Status"}},"type":"object","required":["withdrawal_id","status"],"title":"PayoutActionResponse"},"PayoutCountryRequest":{"properties":{"country":{"type":"string","pattern":"^[A-Za-z]{2}$","title":"Country","description":"Where the seller is paid, as ISO 3166-1 alpha-2 (\"US\", \"BR\"). Any assigned code is kept, including ones that can't connect Stripe: that's how a seller in Brazil says so. A two-letter code that isn't a country answers 422.","examples":["BR"]}},"type":"object","required":["country"],"title":"PayoutCountryRequest","description":"PUT /stripe/connect/payout-country."},"PayoutPolicy":{"properties":{"automatic":{"type":"boolean","title":"Automatic"},"review_threshold_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Review Threshold Amount"}},"type":"object","required":["automatic"],"title":"PayoutPolicy","description":"How a withdrawal is paid, so the apps can say so truthfully.\n\nBoth apps told people that payouts are \"sent automatically, usually\nwithin a few minutes\" and that \"withdrawals over $250 are reviewed by our\nteam first\", as literals compiled into the wallet screen. Both sentences\nwere true only because production sets PAYOUT_AUTO_DISPATCH_ENABLED and\nleaves PAYOUT_AUTO_MAX_AMOUNT at its default: the code default for\ndispatch is off, and neither value reached the apps from anywhere.\nTurning auto-dispatch off, or moving the ceiling, would have made two\napps lie until their next store release.\n\n`automatic` is whether the sweep pays without a person clicking -- payouts\non and auto-dispatch on. `review_threshold_amount` is the ceiling above\nwhich an automatic payout waits for a person instead. Null whenever\nnothing is automatic, because then everything waits for one."},"PayoutSweepResponse":{"properties":{"checked":{"type":"integer","title":"Checked","default":0},"completed":{"type":"integer","title":"Completed","default":0},"failed":{"type":"integer","title":"Failed","default":0},"in_flight":{"type":"integer","title":"In Flight","default":0},"errors":{"type":"integer","title":"Errors","default":0}},"type":"object","title":"PayoutSweepResponse"},"PendingPayout":{"properties":{"withdrawal_id":{"type":"string","title":"Withdrawal Id"},"user_id":{"type":"string","title":"User Id"},"user_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Name"},"user_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Email"},"paypal_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paypal Email"},"amount":{"type":"number","title":"Amount"},"requested_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested At"}},"type":"object","required":["withdrawal_id","user_id","amount"],"title":"PendingPayout"},"PinChannelRequest":{"properties":{"pinned":{"type":"boolean","title":"Pinned"}},"type":"object","required":["pinned"],"title":"PinChannelRequest"},"PinCheck":{"properties":{"is_pinned":{"type":"boolean","title":"Is Pinned"}},"type":"object","required":["is_pinned"],"title":"PinCheck","description":"GET /pinned-campaigns/check/{campaign_id}. No client calls it."},"PinnedCampaignCreate":{"properties":{"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Campaign ID to pin"},"display_order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Display Order","description":"Display order (optional)","default":0}},"type":"object","required":["campaign_id"],"title":"PinnedCampaignCreate","description":"Schema for pinning a campaign"},"PinnedCampaignReorder":{"properties":{"campaign_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Campaign Ids","description":"List of campaign IDs in new order"}},"type":"object","required":["campaign_ids"],"title":"PinnedCampaignReorder","description":"Schema for reordering pinned campaigns"},"PinnedCampaignSummary":{"properties":{"id_campaign":{"type":"string","format":"uuid","title":"Id Campaign"},"title":{"type":"string","title":"Title"},"ticker":{"type":"string","title":"Ticker"},"goal":{"type":"number","title":"Goal"},"raised":{"type":"number","title":"Raised"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"display_order":{"type":"integer","title":"Display Order","default":0},"pinned_at":{"type":"string","format":"date-time","title":"Pinned At"}},"type":"object","required":["id_campaign","title","ticker","goal","raised","pinned_at"],"title":"PinnedCampaignSummary","description":"Summary of a pinned campaign for profile display"},"PinnedCampaignWithDetails":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id","description":"User who pinned the campaign"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Campaign that was pinned"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for sorting","default":0},"id_pinned_campaign":{"type":"string","format":"uuid","title":"Id Pinned Campaign","description":"Unique identifier"},"pinned_at":{"type":"string","format":"date-time","title":"Pinned At","description":"When the campaign was pinned"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"campaign":{"$ref":"#/components/schemas/CampaignSummary"}},"type":"object","required":["user_id","campaign_id","id_pinned_campaign","pinned_at","campaign"],"title":"PinnedCampaignWithDetails","description":"Pinned campaign with full campaign details"},"PinnedCampaignsResponse":{"properties":{"pinned_campaigns":{"items":{"$ref":"#/components/schemas/PinnedCampaignWithDetails"},"type":"array","title":"Pinned Campaigns"},"total_count":{"type":"integer","title":"Total Count","description":"Total number of pinned campaigns"},"max_allowed":{"type":"integer","title":"Max Allowed","description":"Maximum number of pinned campaigns allowed","default":10}},"type":"object","required":["pinned_campaigns","total_count"],"title":"PinnedCampaignsResponse","description":"Response for list of pinned campaigns"},"PinnedChannel":{"properties":{"channel_id":{"type":"string","title":"Channel Id"},"pinned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pinned At","description":"When it was pinned, ISO 8601"}},"type":"object","required":["channel_id"],"title":"PinnedChannel"},"PinnedChannelList":{"properties":{"pinned_channels":{"items":{"$ref":"#/components/schemas/PinnedChannel"},"type":"array","title":"Pinned Channels"}},"type":"object","required":["pinned_channels"],"title":"PinnedChannelList","description":"GET /chat/pinned-channels. No client calls it."},"Place":{"properties":{"name":{"type":"string","title":"Name","description":"The Census NAME, e.g. 'Austin city, Texas'"},"code":{"type":"string","title":"Code","description":"The Census code in the row's second column"}},"type":"object","required":["name","code"],"title":"Place","description":"One row of the Census answer."},"PlatformVersionPolicy":{"properties":{"minimum_version":{"type":"string","title":"Minimum Version"},"minimum_build":{"type":"integer","title":"Minimum Build"},"store_url":{"type":"string","title":"Store Url"}},"type":"object","required":["minimum_version","minimum_build","store_url"],"title":"PlatformVersionPolicy","description":"The lowest build of one platform's app that may still be used."},"PreferredLocaleUpdate":{"properties":{"preferred_locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Locale","description":"BCP-47 tag of the user's chosen language; None clears the choice back to follow-the-client."}},"type":"object","title":"PreferredLocaleUpdate","description":"One field on purpose: the mobile pickers set the language without a\nread-modify-write of the whole user."},"Product":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the product"},"description":{"type":"string","title":"Description","description":"Description of the product"},"price":{"type":"number","exclusiveMinimum":0.0,"title":"Price","description":"Price of the product; the floor is MINIMUM_LISTING_PRICE"},"condition":{"type":"string","title":"Condition","description":"Condition of the product; one of ['digital', 'fair', 'good', 'like new', 'new', 'poor', 'service']"},"donation_pct":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Pct","description":"Share of the price that goes to the campaign. Null when the listing names no campaign and the buyer chooses at checkout; the floor otherwise depends on product_type"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the product"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the listing's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the listing's location"},"campaign_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Message","description":"Message to post to campaign when product sells"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the seller is kept off the campaign's public donor list for sales of this listing","default":false},"product_type":{"type":"string","enum":["physical","digital","service"],"title":"Product Type","description":"Kind of product: physical item, digital download, or service","default":"physical"},"is_online":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Online","description":"Service listings only: true when delivered online, so it has no location"},"is_shippable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Shippable","description":"Whether item can be shipped","default":false},"package_weight_oz":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Weight Oz","description":"Package weight in ounces"},"package_length_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Length In","description":"Package length in inches"},"package_width_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Width In","description":"Package width in inches"},"package_height_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Height In","description":"Package height in inches"},"id_product":{"type":"string","format":"uuid","title":"Id Product","description":"Unique identifier of the product"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id","description":"The campaign this listing supports. Null when the buyer chooses one at checkout; campaign_chosen_by says which"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the product"},"status":{"type":"string","title":"Status","description":"Status of the product"},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the product is active"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"},"publication_state":{"type":"string","title":"Publication State","description":"Why a listing is or is not on sale, named once for every client.\n\n`is_active` alone cannot answer this: it is false both for a soft-deleted\nlisting (which also has deleted_at set) and for a digital one still\nwaiting for its file. Three surfaces show a seller their listings, and\neach deriving this from is_active plus an asset count would be three\nchances to get it wrong, and to disagree with one another.\n\n- `live`            on sale now\n- `awaiting_files`  a digital listing with nothing to deliver yet; the\n                    seller must upload before anyone can buy it\n- `hidden`          not on sale for any other reason","readOnly":true},"campaign_chosen_by":{"type":"string","enum":["seller","buyer"],"title":"Campaign Chosen By","description":"Who picks the campaign this listing's sales fund.\n\n- `seller`  the listing names a campaign and a share; every buyer funds it\n- `buyer`   the listing names neither, so each buyer chooses at checkout\n\nServed as its own field rather than left to each client to infer from a\nnull campaign_id. Four surfaces show a listing and three of them have to\nchange what they draw for it -- the product page, the cart line and the\ncheckout -- and \"campaign_id is null\" written out four times is four\nchances for one of them to also treat a listing whose campaign failed to\nload as a listing the buyer may redirect.","readOnly":true}},"type":"object","required":["title","description","price","condition","id_product","seller_id","category_id","status","is_active","publication_state","campaign_chosen_by"],"title":"Product","description":"Schema for product responses (includes DB-generated fields)"},"ProductCategory":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","description":"Category name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Category description"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for UI","default":0},"is_active":{"type":"boolean","title":"Is Active","description":"Whether category is active","default":true},"icon":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set; null draws the client's fallback"},"id_category":{"type":"string","format":"uuid","title":"Id Category","description":"Unique identifier of the category"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id","description":"Parent category ID"}},"type":"object","required":["name","id_category","created_at","updated_at"],"title":"ProductCategory","description":"Product category with parent reference"},"ProductCategoryCreate":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","description":"Category name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Category description"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for UI","default":0},"is_active":{"type":"boolean","title":"Is Active","description":"Whether category is active","default":true},"icon":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set; null draws the client's fallback"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id","description":"Parent category ID for hierarchy"}},"type":"object","required":["name"],"title":"ProductCategoryCreate","description":"Product category creation with optional parent"},"ProductCategoryFlat":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","description":"Category name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Category description"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for UI","default":0},"is_active":{"type":"boolean","title":"Is Active","description":"Whether category is active","default":true},"icon":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set; null draws the client's fallback"},"id_category":{"type":"string","format":"uuid","title":"Id Category","description":"Unique identifier of the category"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id","description":"Parent category ID"},"parent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Name","description":"Parent category name"}},"type":"object","required":["name","id_category","created_at","updated_at"],"title":"ProductCategoryFlat","description":"Product category with parent name for breadcrumbs"},"ProductCategoryWithChildren":{"properties":{"id_category":{"type":"string","format":"uuid","title":"Id Category","description":"Unique identifier of the category"},"name":{"type":"string","maxLength":100,"title":"Name","description":"Category name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Category description"},"display_order":{"type":"integer","title":"Display Order","description":"Display order for UI","default":0},"is_active":{"type":"boolean","title":"Is Active","description":"Whether category is active","default":true},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon","description":"An icon name from the shared Streamline set"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id","description":"Parent category ID"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp"},"children":{"items":{"$ref":"#/components/schemas/ProductCategoryWithChildren"},"type":"array","title":"Children","description":"Child categories"}},"type":"object","required":["id_category","name","created_at","updated_at"],"title":"ProductCategoryWithChildren","description":"Product category with nested children for tree structure"},"ProductCleanup":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"message":{"type":"string","title":"Message"},"result":{"$ref":"#/components/schemas/ProductCleanupResult"}},"type":"object","required":["success","message","result"],"title":"ProductCleanup","description":"POST /admin/cleanup/cleanup/product/{product_id}."},"ProductCleanupResult":{"properties":{"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id"},"total_found":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Found"},"deleted_count":{"type":"integer","title":"Deleted Count"},"kept_latest":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Kept Latest"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"}},"type":"object","required":["deleted_count"],"title":"ProductCleanupResult","description":"Either what was deleted, or deleted_count 0 and a message."},"ProductCreate":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the product"},"description":{"type":"string","title":"Description","description":"Description of the product"},"price":{"type":"number","exclusiveMinimum":0.0,"title":"Price","description":"Price of the product; the floor is MINIMUM_LISTING_PRICE"},"condition":{"type":"string","title":"Condition","description":"Condition of the product; one of ['digital', 'fair', 'good', 'like new', 'new', 'poor', 'service']"},"donation_pct":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Pct","description":"Share of the price that goes to the campaign. Null when the listing names no campaign and the buyer chooses at checkout; the floor otherwise depends on product_type"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the product"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the listing's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the listing's location"},"campaign_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Message","description":"Message to post to campaign when product sells"},"anonymous":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Anonymous","description":"Keep the seller off the campaign's public donor list for sales of this listing. Omit to leave the stored choice alone; a new listing defaults to false, which is named."},"product_type":{"type":"string","enum":["physical","digital","service"],"title":"Product Type","description":"Kind of product: physical item, digital download, or service","default":"physical"},"is_online":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Online","description":"Service listings only: true when delivered online, so it has no location"},"is_shippable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Shippable","description":"Whether item can be shipped","default":false},"package_weight_oz":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Weight Oz","description":"Package weight in ounces"},"package_length_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Length In","description":"Package length in inches"},"package_width_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Width In","description":"Package width in inches"},"package_height_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Height In","description":"Package height in inches"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id","description":"The campaign this listing supports. Omit to let each buyer choose one at checkout"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the product"}},"type":"object","required":["title","description","price","condition","seller_id","category_id"],"title":"ProductCreate","description":"Schema for creating a product (client request payload)"},"ProductDeactivationImpactSummary":{"properties":{"product_id":{"type":"string","title":"Product Id"},"current_price":{"type":"number","title":"Current Price"},"view_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"View Count","default":0},"is_sold":{"type":"boolean","title":"Is Sold"},"pending_transactions":{"type":"integer","title":"Pending Transactions"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"cannot_deactivate_reasons":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Cannot Deactivate Reasons"},"warnings":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Warnings"}},"type":"object","required":["product_id","current_price","is_sold","pending_transactions"],"title":"ProductDeactivationImpactSummary","description":"Summary of what will happen when product is deactivated"},"ProductDeactivationReason":{"type":"string","enum":["sold_elsewhere","no_longer_selling","damaged_lost","incorrect_listing","change_of_plans","too_many_inquiries","other"],"title":"ProductDeactivationReason","description":"Valid reasons for product deactivation"},"ProductDeactivationRequest":{"properties":{"reason":{"$ref":"#/components/schemas/ProductDeactivationReason"},"explanation":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Explanation","description":"Additional explanation for deactivation"},"refund_policy":{"$ref":"#/components/schemas/ProductRefundPolicy","default":"full_refund"},"notify_buyers":{"type":"boolean","title":"Notify Buyers","description":"Whether to notify buyers about the deactivation","default":true},"confirm_understanding":{"type":"boolean","title":"Confirm Understanding","description":"Confirmation that user understands the consequences","default":true}},"type":"object","required":["reason"],"title":"ProductDeactivationRequest","description":"Request schema for product deactivation"},"ProductDeactivationResponse":{"properties":{"product_id":{"type":"string","title":"Product Id"},"previous_status":{"type":"string","title":"Previous Status"},"new_status":{"type":"string","title":"New Status"},"deactivated_at":{"type":"string","title":"Deactivated At"},"reason":{"$ref":"#/components/schemas/ProductDeactivationReason"},"explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation"},"refund_policy":{"$ref":"#/components/schemas/ProductRefundPolicy"},"pending_transactions_count":{"type":"integer","title":"Pending Transactions Count"},"refund_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Refund Amount"},"message":{"type":"string","title":"Message"}},"type":"object","required":["product_id","previous_status","new_status","deactivated_at","reason","explanation","refund_policy","pending_transactions_count","refund_amount","message"],"title":"ProductDeactivationResponse","description":"Response schema for product deactivation"},"ProductImage":{"properties":{"id_image":{"type":"string","title":"Id Image","description":"Unique identifier of the image"},"image_url":{"type":"string","title":"Image Url","description":"URL of the image"},"display_order":{"type":"integer","title":"Display Order","description":"Display order of the image"},"is_primary":{"type":"boolean","title":"Is Primary","description":"Whether this is the primary image"},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text","description":"Alt text for the image"},"file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size","description":"File size in bytes"},"file_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type","description":"MIME type of the file"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"Image width in pixels"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"Image height in pixels"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["id_image","image_url","display_order","is_primary"],"title":"ProductImage","description":"Schema for product images"},"ProductPriceStats":{"properties":{"min_price":{"type":"number","title":"Min Price","description":"Minimum product price"},"max_price":{"type":"number","title":"Max Price","description":"Maximum product price"},"histogram":{"items":{"type":"integer"},"type":"array","title":"Histogram","description":"Price distribution histogram (20 buckets)"},"total_products":{"type":"integer","title":"Total Products","description":"Total number of active products with prices"}},"type":"object","required":["min_price","max_price","histogram","total_products"],"title":"ProductPriceStats","description":"Price statistics for products (histogram and min/max)"},"ProductRefundPolicy":{"type":"string","enum":["full_refund","no_refund"],"title":"ProductRefundPolicy","description":"Refund policy options for deactivated products"},"ProductUpdate":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the product"},"description":{"type":"string","title":"Description","description":"Description of the product"},"price":{"type":"number","exclusiveMinimum":0.0,"title":"Price","description":"Price of the product; the floor is MINIMUM_LISTING_PRICE"},"condition":{"type":"string","title":"Condition","description":"Condition of the product; one of ['digital', 'fair', 'good', 'like new', 'new', 'poor', 'service']"},"donation_pct":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Pct","description":"Share of the price that goes to the campaign. Null when the listing names no campaign and the buyer chooses at checkout; the floor otherwise depends on product_type"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the product"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the listing's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the listing's location"},"campaign_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Message","description":"Message to post to campaign when product sells"},"anonymous":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Anonymous","description":"Keep the seller off the campaign's public donor list for sales of this listing. Omit to leave the stored choice alone; a new listing defaults to false, which is named."},"product_type":{"type":"string","enum":["physical","digital","service"],"title":"Product Type","description":"Kind of product: physical item, digital download, or service","default":"physical"},"is_online":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Online","description":"Service listings only: true when delivered online, so it has no location"},"is_shippable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Shippable","description":"Whether item can be shipped","default":false},"package_weight_oz":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Weight Oz","description":"Package weight in ounces"},"package_length_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Length In","description":"Package length in inches"},"package_width_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Width In","description":"Package width in inches"},"package_height_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Height In","description":"Package height in inches"},"id_product":{"type":"string","format":"uuid","title":"Id Product","description":"Unique identifier of the product"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id","description":"The campaign this listing supports. Null to let each buyer choose one at checkout"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the product"},"status":{"type":"string","title":"Status","description":"Status of the product"},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the product is active"}},"type":"object","required":["title","description","price","condition","id_product","seller_id","category_id","status","is_active"],"title":"ProductUpdate","description":"The request body of PATCH /products/.\n\nIt has no rules that depend on product_type, because the body doesn't\ndecide the type: an edit can't change it, and iOS doesn't send it, so the\nbody's default of \"physical\" is wrong for every other kind of listing.\nFastAPI validates the body before the handler runs, so rules on it judged a\ndigital listing by the physical donation floor, and cleared an online\nservice's is_online as a physical listing's rule does.\n\nThe handler builds a ProductCreate with the stored row's type, and every\nrule is applied there. That's also why this declares every field\nProductCreate does: the handler carries those fields over by name."},"ProductWithCampaignDetails":{"properties":{"title":{"type":"string","title":"Title","description":"Title of the product"},"description":{"type":"string","title":"Description","description":"Description of the product"},"price":{"type":"number","exclusiveMinimum":0.0,"title":"Price","description":"Price of the product; the floor is MINIMUM_LISTING_PRICE"},"condition":{"type":"string","title":"Condition","description":"Condition of the product; one of ['digital', 'fair', 'good', 'like new', 'new', 'poor', 'service']"},"donation_pct":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Pct","description":"Share of the price that goes to the campaign. Null when the listing names no campaign and the buyer chooses at checkout; the floor otherwise depends on product_type"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the product"},"location_latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the listing's location"},"location_longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the listing's location"},"campaign_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Message","description":"Message to post to campaign when product sells"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the seller is kept off the campaign's public donor list for sales of this listing","default":false},"product_type":{"type":"string","enum":["physical","digital","service"],"title":"Product Type","description":"Kind of product: physical item, digital download, or service","default":"physical"},"is_online":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Online","description":"Service listings only: true when delivered online, so it has no location"},"is_shippable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Shippable","description":"Whether item can be shipped","default":false},"package_weight_oz":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Weight Oz","description":"Package weight in ounces"},"package_length_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Length In","description":"Package length in inches"},"package_width_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Width In","description":"Package width in inches"},"package_height_in":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Package Height In","description":"Package height in inches"},"id_product":{"type":"string","format":"uuid","title":"Id Product","description":"Unique identifier of the product"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id","description":"The campaign this listing supports. Null when the buyer chooses one at checkout; campaign_chosen_by says which"},"category_id":{"type":"string","format":"uuid","title":"Category Id","description":"Category ID of the product"},"status":{"type":"string","title":"Status","description":"Status of the product"},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the product is active"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title","description":"Name of the campaign"},"category":{"$ref":"#/components/schemas/ProductCategory","description":"Product category details"},"images":{"items":{"$ref":"#/components/schemas/ProductImage"},"type":"array","title":"Images","description":"Product images"},"publication_state":{"type":"string","title":"Publication State","description":"Why a listing is or is not on sale, named once for every client.\n\n`is_active` alone cannot answer this: it is false both for a soft-deleted\nlisting (which also has deleted_at set) and for a digital one still\nwaiting for its file. Three surfaces show a seller their listings, and\neach deriving this from is_active plus an asset count would be three\nchances to get it wrong, and to disagree with one another.\n\n- `live`            on sale now\n- `awaiting_files`  a digital listing with nothing to deliver yet; the\n                    seller must upload before anyone can buy it\n- `hidden`          not on sale for any other reason","readOnly":true},"campaign_chosen_by":{"type":"string","enum":["seller","buyer"],"title":"Campaign Chosen By","description":"Who picks the campaign this listing's sales fund.\n\n- `seller`  the listing names a campaign and a share; every buyer funds it\n- `buyer`   the listing names neither, so each buyer chooses at checkout\n\nServed as its own field rather than left to each client to infer from a\nnull campaign_id. Four surfaces show a listing and three of them have to\nchange what they draw for it -- the product page, the cart line and the\ncheckout -- and \"campaign_id is null\" written out four times is four\nchances for one of them to also treat a listing whose campaign failed to\nload as a listing the buyer may redirect.","readOnly":true}},"type":"object","required":["title","description","price","condition","id_product","seller_id","category_id","status","is_active","category","publication_state","campaign_chosen_by"],"title":"ProductWithCampaignDetails","description":"Product with campaign and category information"},"ProfileDonatedDrift":{"properties":{"giving_profile_id":{"type":"string","title":"Giving Profile Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"cached":{"type":"number","title":"Cached"},"derived":{"type":"number","title":"Derived"},"drift":{"type":"number","title":"Drift"}},"type":"object","required":["giving_profile_id","cached","derived","drift"],"title":"ProfileDonatedDrift"},"PurchaseLabelRequest":{"properties":{"rate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rate Id","description":"Ignored. The order's stored rate is what gets bought."}},"type":"object","title":"PurchaseLabelRequest","description":"Request to purchase a shipping label.\n\nThe body carries no price and no longer decides which rate is bought. The\norder already records the rate the buyer was billed for, and the endpoint\nbuys that one -- see api/endpoints/shipping.py. `rate_id` is kept, and\noptional, so existing clients keep validating; it is compared to the stored\nrate and logged when it disagrees, never obeyed."},"PurchaseLabelResponse":{"properties":{"shippo_transaction_id":{"type":"string","title":"Shippo Transaction Id","description":"Shippo transaction ID for the label"},"tracking_number":{"type":"string","title":"Tracking Number","description":"Carrier tracking number"},"tracking_url":{"type":"string","title":"Tracking Url","description":"URL to track on carrier website"},"label_url":{"type":"string","title":"Label Url","description":"URL to download label PDF"},"carrier":{"type":"string","title":"Carrier","description":"Carrier name"},"service":{"type":"string","title":"Service","description":"Service level"},"label_cost_cents":{"type":"integer","title":"Label Cost Cents","description":"Label cost absorbed by platform (cents)"}},"type":"object","required":["shippo_transaction_id","tracking_number","tracking_url","label_url","carrier","service","label_cost_cents"],"title":"PurchaseLabelResponse","description":"Response after purchasing a shipping label"},"PurchaseQuote":{"properties":{"buyer_pays":{"items":{"$ref":"#/components/schemas/BuyerPaysRow"},"type":"array","title":"Buyer Pays"},"rails":{"items":{"$ref":"#/components/schemas/RailTotal"},"type":"array","title":"Rails","description":"One per rail the caller is offered, card first. Empty while shipping_pending"},"rails_named":{"type":"boolean","title":"Rails Named","description":"Whether each rail's rows say which rail they're for: when there's more than one"},"fee_kind":{"type":"string","enum":["processing_fee","service_fee"],"title":"Fee Kind","description":"What to call the fee the payer is billed. processing_fee: each rail bills its own processor's fee. service_fee: every rail bills the same fee, so the rails' totals are the same and one total can be shown","default":"processing_fee"},"fees":{"items":{"$ref":"#/components/schemas/FeeRow"},"type":"array","title":"Fees","description":"The fee rows to draw, in order. One under a single service fee, one per rail that bills the payer otherwise, and none while the payer isn't billed a fee or shipping is still to be chosen. Which rows exist is decided here so no client groups fees its own way"},"totals":{"items":{"$ref":"#/components/schemas/TotalRow"},"type":"array","title":"Totals","description":"The total rows to draw, in order. One under a single service fee, since every rail charges the same; otherwise one per rail"},"goes_to":{"items":{"$ref":"#/components/schemas/CampaignTotal"},"type":"array","title":"Goes To","description":"What each campaign the order funds receives, one row per campaign, in the order they first appear. Grouped here rather than per item: which item sent the money is the seller's business, and an item's own line already says its percentage. No percentage on these rows, since two items at different rates have no one share between them"},"goes_to_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Goes To Total Cents","description":"The sum to draw as a last row under goes_to, or null when there is nothing to add up: below two campaigns the row and the sum are the same number. Not contribution_total_cents, which is always the sum, for a screen that shows it instead of the rows"},"contribution_total_cents":{"type":"integer","title":"Contribution Total Cents","description":"What every campaign this order funds receives, added up: the sum of goes_to. Sent so a screen that shows only a total -- the cart's dropdown -- can say what the order gives without adding the rows up itself","default":0},"shipping_pending":{"type":"boolean","title":"Shipping Pending","description":"postage_pending was sent for a cart with an item that ships. The fee is taken on the postage too, so there's no fee or total until a rate is chosen"},"recipients":{"items":{"$ref":"#/components/schemas/ItemRecipients"},"type":"array","title":"Recipients","description":"One per item, in the order they were sent"}},"type":"object","required":["buyer_pays","rails","rails_named","shipping_pending","recipients"],"title":"PurchaseQuote"},"PurchaseQuoteRequest":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CheckoutItem"},"type":"array","maxItems":50,"minItems":1,"title":"Items","description":"Items to checkout"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Platform Tip","description":"Optional platform tip","default":"0"},"postage_pending":{"type":"boolean","title":"Postage Pending","description":"True while a rate is still to be chosen for an item that ships, as on Buy Now's first step. There's no fee or total until then. Only the client knows this: an item sent with no rate can also be one no carrier priced, which is ordered with no postage","default":false}},"type":"object","required":["items"],"title":"PurchaseQuoteRequest","description":"A cart, and whether the buyer is still to choose postage for it."},"PushNotificationRequest":{"properties":{"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"Specific user ID to send to"},"title":{"type":"string","title":"Title","description":"Notification title"},"body":{"type":"string","title":"Body","description":"Notification body"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon","description":"Notification icon URL"},"image":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image","description":"Notification image URL"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"URL to open when clicked"},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag","description":"Notification tag for grouping"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Notification type","default":"default"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority","description":"Notification priority (normal, high)","default":"normal"},"silent":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Silent","description":"Send as silent notification","default":false},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"Additional data payload"}},"type":"object","required":["title","body"],"title":"PushNotificationRequest","description":"Schema for sending a push notification."},"PushNotificationResponse":{"properties":{"message":{"type":"string","title":"Message"},"success":{"type":"boolean","title":"Success"},"sent_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sent Count"},"failed_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Failed Count"},"expired_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expired Count"}},"type":"object","required":["message","success"],"title":"PushNotificationResponse","description":"Schema for push notification send response."},"PushServiceInfo":{"properties":{"is_configured":{"type":"boolean","title":"Is Configured"},"vapid_public_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vapid Public Key"},"supported_features":{"items":{"type":"string"},"type":"array","title":"Supported Features","default":[]}},"type":"object","required":["is_configured"],"title":"PushServiceInfo","description":"Schema for push service information."},"PushSubscriptionCheck":{"properties":{"exists":{"type":"boolean","title":"Exists"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"}},"type":"object","required":["exists","is_active"],"title":"PushSubscriptionCheck","description":"POST /push/verify, which web's push settings read. Sent without unset\nkeys: an unknown or inactive endpoint gets only exists and is_active."},"PushSubscriptionCreate":{"properties":{"endpoint":{"type":"string","title":"Endpoint","description":"Push service endpoint URL"},"keys":{"$ref":"#/components/schemas/PushSubscriptionKeys","description":"Encryption keys"},"userAgent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Useragent","description":"User agent string"}},"type":"object","required":["endpoint","keys"],"title":"PushSubscriptionCreate","description":"Schema for creating a new push subscription."},"PushSubscriptionKeys":{"properties":{"p256dh":{"type":"string","title":"P256Dh","description":"P256DH encryption key"},"auth":{"type":"string","title":"Auth","description":"Authentication key"}},"type":"object","required":["p256dh","auth"],"title":"PushSubscriptionKeys","description":"Push subscription encryption keys."},"PushSubscriptionResponse":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"endpoint":{"type":"string","title":"Endpoint"},"is_active":{"type":"boolean","title":"Is Active"},"device_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Type"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","user_id","endpoint","is_active","device_type","last_used_at","created_at","updated_at"],"title":"PushSubscriptionResponse","description":"Schema for push subscription response."},"PushSubscriptionUnsubscribe":{"properties":{"endpoint":{"type":"string","title":"Endpoint","description":"Push service endpoint URL to remove"}},"type":"object","required":["endpoint"],"title":"PushSubscriptionUnsubscribe","description":"Schema for unsubscribing from push notifications."},"PushSubscriptionVerify":{"properties":{"endpoint":{"type":"string","title":"Endpoint","description":"Push service endpoint URL to verify"}},"type":"object","required":["endpoint"],"title":"PushSubscriptionVerify","description":"Schema for verifying push subscription exists."},"RailTotal":{"properties":{"rail":{"type":"string","enum":["stripe","paypal"],"title":"Rail"},"processing_fee_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Processing Fee Cents","description":"The fee the buyer is billed on top. Null when they aren't billed it: each item's recipients give it up instead"},"total_cents":{"type":"integer","title":"Total Cents","description":"What this rail charges: the buyer_pays rows and the processing fee"}},"type":"object","required":["rail","processing_fee_cents","total_cents"],"title":"RailTotal","description":"What one rail bills: its processing fee and its total."},"RecipientRow":{"properties":{"kind":{"type":"string","enum":["seller","campaign","opengiving_fee","processing_fee"],"title":"Kind","description":"seller and campaign: each one's share, always sent. The campaign's is its cut of the sale and its part of a digital item's flat fee together. opengiving_fee: OpenGiving's percentage and its part of the flat fee. processing_fee: taken from the sale, only when the buyer isn't billed it"},"amount_cents":{"type":"integer","title":"Amount Cents"},"pct":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pct","description":"The share of the sale, on seller and campaign rows. Not sent on a campaign row that also holds part of a flat fee: the percentage describes the sale, and that figure is more than the sale's share"}},"type":"object","required":["kind","amount_cents"],"title":"RecipientRow","description":"Where part of one item's money goes."},"ReconciliationResponse":{"properties":{"checked":{"type":"integer","title":"Checked"},"settled":{"type":"integer","title":"Settled"},"settled_orders":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Settled Orders","default":[]},"still_open":{"type":"integer","title":"Still Open","default":0},"expired":{"type":"integer","title":"Expired","default":0},"failed":{"type":"integer","title":"Failed","default":0},"failures":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Failures","default":[]},"dry_run":{"type":"boolean","title":"Dry Run","default":false}},"type":"object","required":["checked","settled"],"title":"ReconciliationResponse"},"ReferralClickTracked":{"properties":{"success":{"type":"boolean","title":"Success"},"tracked":{"type":"boolean","title":"Tracked"}},"type":"object","required":["success","tracked"],"title":"ReferralClickTracked","description":"GET /referrals/track/{code}. `tracked` is false for an unknown code;\nsuccess is true either way, so the route can't be used to find codes."},"ReferralCode":{"properties":{"code":{"type":"string","maxLength":50,"title":"Code","description":"Unique referral code"},"owner_name":{"type":"string","maxLength":100,"title":"Owner Name","description":"Name of the code owner"},"owner_email":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Owner Email","description":"Email of the code owner"},"owner_type":{"$ref":"#/components/schemas/OwnerType","description":"Type of owner"},"id_referral_code":{"type":"string","format":"uuid","title":"Id Referral Code","description":"Unique identifier"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id","description":"Optional link to users table"},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the code is active","default":true},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the code was created"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the code was last updated"}},"type":"object","required":["code","owner_name","owner_type","id_referral_code","created_at"],"title":"ReferralCode","description":"Full referral code schema with ID"},"ReferralCodeCreate":{"properties":{"code":{"type":"string","maxLength":50,"title":"Code","description":"Unique referral code"},"owner_name":{"type":"string","maxLength":100,"title":"Owner Name","description":"Name of the code owner"},"owner_email":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Owner Email","description":"Email of the code owner"},"owner_type":{"$ref":"#/components/schemas/OwnerType","description":"Type of owner"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id","description":"Optional link to users table"}},"type":"object","required":["code","owner_name","owner_type"],"title":"ReferralCodeCreate","description":"Schema for creating a referral code"},"ReferralCodeWithStats":{"properties":{"code":{"type":"string","maxLength":50,"title":"Code","description":"Unique referral code"},"owner_name":{"type":"string","maxLength":100,"title":"Owner Name","description":"Name of the code owner"},"owner_email":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Owner Email","description":"Email of the code owner"},"owner_type":{"$ref":"#/components/schemas/OwnerType","description":"Type of owner"},"id_referral_code":{"type":"string","format":"uuid","title":"Id Referral Code","description":"Unique identifier"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id","description":"Optional link to users table"},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the code is active","default":true},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the code was created"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the code was last updated"},"total_clicks":{"type":"integer","title":"Total Clicks","description":"Total number of clicks","default":0},"unique_visitors":{"type":"integer","title":"Unique Visitors","description":"Unique visitors based on IP hash","default":0},"conversions":{"type":"integer","title":"Conversions","description":"Number of conversions","default":0},"conversion_rate":{"type":"number","title":"Conversion Rate","description":"Conversion rate percentage","default":0.0}},"type":"object","required":["code","owner_name","owner_type","id_referral_code","created_at"],"title":"ReferralCodeWithStats","description":"Referral code with click statistics"},"ReferralStats":{"properties":{"total_clicks":{"type":"integer","title":"Total Clicks","description":"Total clicks across all codes","default":0},"unique_visitors":{"type":"integer","title":"Unique Visitors","description":"Total unique visitors","default":0},"total_conversions":{"type":"integer","title":"Total Conversions","description":"Total conversions","default":0},"conversion_rate":{"type":"number","title":"Conversion Rate","description":"Overall conversion rate","default":0.0},"clicks_by_day":{"items":{"$ref":"#/components/schemas/DailyClicks"},"type":"array","title":"Clicks By Day","description":"Clicks grouped by day"},"clicks_by_code":{"items":{"$ref":"#/components/schemas/CodeClicks"},"type":"array","title":"Clicks By Code","description":"Clicks grouped by code"},"leaderboard":{"items":{"$ref":"#/components/schemas/schemas__referral__LeaderboardEntry"},"type":"array","title":"Leaderboard","description":"Top performers"}},"type":"object","title":"ReferralStats","description":"Comprehensive referral statistics"},"ReferralSummary":{"properties":{"today":{"$ref":"#/components/schemas/ClickCount"},"this_week":{"$ref":"#/components/schemas/ClickCount"},"all_time":{"$ref":"#/components/schemas/ClicksAndConversions"},"active_codes":{"type":"integer","title":"Active Codes"}},"type":"object","required":["today","this_week","all_time","active_codes"],"title":"ReferralSummary","description":"GET /referrals/summary, the admin dashboard's cards. Web reads every key."},"Refund":{"properties":{"refund_type":{"type":"string","title":"Refund Type"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"original_amount":{"type":"number","title":"Original Amount"},"refund_amount":{"type":"number","title":"Refund Amount"},"requester_id":{"type":"string","format":"uuid","title":"Requester Id"},"recipient_id":{"type":"string","format":"uuid","title":"Recipient Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"},"id_refund":{"type":"string","format":"uuid","title":"Id Refund"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"}},"type":"object","required":["refund_type","original_amount","refund_amount","requester_id","recipient_id","reason","id_refund","status","created_at","updated_at"],"title":"Refund","description":"Full refund response schema"},"RefundApproval":{"properties":{"admin_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Admin Notes","description":"Notes about the approval, kept on the refund where a decline's reason is. The admin refunds page's Admin Notes"}},"type":"object","title":"RefundApproval","description":"The body POST /refunds/refunds/{id}/approve may carry. Optional, as is\nthe body itself: the apps and the web's seller and organizer pages send\nnone, or {}."},"RefundDenial":{"properties":{"message":{"type":"string","title":"Message"},"refund_id":{"type":"string","title":"Refund Id"},"status":{"type":"string","title":"Status"}},"type":"object","required":["message","refund_id","status"],"title":"RefundDenial","description":"POST /refunds/refunds/{id}/deny. Android (RefundDenialDto) reads all\nthree as optional strings; web ignores the body."},"RefundPolicy":{"type":"string","enum":["full_refund","no_refund","partial_refund","transfer_to_similar"],"title":"RefundPolicy","description":"Refund policy options for deactivated campaigns"},"RefundProcessResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"},"refund_id":{"type":"string","format":"uuid","title":"Refund Id"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"amount_refunded":{"type":"number","title":"Amount Refunded"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider"}},"type":"object","required":["success","message","refund_id","amount_refunded"],"title":"RefundProcessResponse","description":"Response for processing a refund"},"RefundQueueItem":{"properties":{"refund_type":{"type":"string","title":"Refund Type"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"original_amount":{"type":"number","title":"Original Amount"},"refund_amount":{"type":"number","title":"Refund Amount"},"requester_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Requester Id"},"recipient_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Recipient Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"},"id_refund":{"type":"string","format":"uuid","title":"Id Refund"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name"},"donor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Donor Name"},"requester_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Name"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"admin_reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Reviewer Name"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Whether the donation was given anonymously. An organizer is never sent an anonymous donor's name or ids","default":false},"campaign_deleted":{"type":"boolean","title":"Campaign Deleted","description":"Whether the donation's campaign no longer exists; campaign_title is then null","default":false},"organizer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Organizer Id"},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider"},"organizer_credited":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Organizer Credited"},"organizer_available_balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Organizer Available Balance"}},"type":"object","required":["refund_type","original_amount","refund_amount","reason","id_refund","status","created_at","updated_at"],"title":"RefundQueueItem","description":"A refund in an organizer's or an admin's queue.\n\nThe requester and recipient are optional because an anonymous donor's\nidentity is not handed to the organizer: a user id resolves to a public\nprofile."},"RefundResolution":{"properties":{"resolution":{"type":"string","enum":["refund_without_clawback","refunded_by_hand","acknowledge","deny"],"title":"Resolution"},"note":{"type":"string","maxLength":2000,"minLength":1,"title":"Note"}},"type":"object","required":["resolution","note"],"title":"RefundResolution","description":"An admin's decision on a refund parked for them.\n\nrefund_without_clawback: send the refund, leave what the payment paid out.\nrefunded_by_hand: the admin paid the payer another way; close it here.\nacknowledge: for a refund already made at Stripe, take it off the queue.\ndeny: turn the request down."},"RefundResolved":{"properties":{"message":{"type":"string","title":"Message"},"refund_id":{"type":"string","format":"uuid","title":"Refund Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"success":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Success"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"amount_refunded":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount Refunded"},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider"}},"type":"object","required":["message","refund_id"],"title":"RefundResolved","description":"POST /refunds/refunds/{id}/resolve. Acknowledging or denying answers\nonly what a denial does (message, refund_id, status); refunding without\nclawback or recording a refund made by hand answers every key an\napproval does."},"RefundWithDetails":{"properties":{"refund_type":{"type":"string","title":"Refund Type"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"original_amount":{"type":"number","title":"Original Amount"},"refund_amount":{"type":"number","title":"Refund Amount"},"requester_id":{"type":"string","format":"uuid","title":"Requester Id"},"recipient_id":{"type":"string","format":"uuid","title":"Recipient Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"},"id_refund":{"type":"string","format":"uuid","title":"Id Refund"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name"},"donor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Donor Name"},"requester_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Name"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"admin_reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Reviewer Name"}},"type":"object","required":["refund_type","original_amount","refund_amount","requester_id","recipient_id","reason","id_refund","status","created_at","updated_at"],"title":"RefundWithDetails","description":"Refund with related transaction/contribution details"},"RejectRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":1,"title":"Reason"}},"type":"object","required":["reason"],"title":"RejectRequest"},"ReleaseEscrowRequest":{"properties":{"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id","description":"Internal transaction ID"},"delivery_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Code","description":"4-digit delivery confirmation code"}},"type":"object","required":["transaction_id"],"title":"ReleaseEscrowRequest","description":"Request to release escrowed funds after delivery confirmation"},"ReleaseEscrowResponse":{"properties":{"transaction_id":{"type":"string","title":"Transaction Id","description":"Transaction ID"},"transfer_group":{"type":"string","title":"Transfer Group","description":"Transfer group linking payments"},"seller_transfer":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Seller Transfer","description":"Where the seller's share went, amount in dollars. Null when the seller was due nothing"},"campaign_transfer":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Campaign Transfer","description":"Where the campaign's share went, amount in dollars. Null when the sale gave the campaign nothing"},"platform_fee_kept":{"type":"number","title":"Platform Fee Kept","description":"Platform fee kept, in dollars"},"total_transferred":{"type":"number","title":"Total Transferred","description":"Total paid out to the seller and the campaign, in dollars"}},"type":"object","required":["transaction_id","transfer_group","platform_fee_kept","total_transferred"],"title":"ReleaseEscrowResponse","description":"POST /payments/release-escrow/{id}. Every amount is in dollars.\n\nA leg is where one party's share went: {\"method\": \"wallet\", \"amount\"}\nwhen it was credited to their OpenGiving wallet (every PayPal sale, and\na card sale's campaign share when the organizer has no Stripe account),\nor {\"method\": \"stripe\", \"amount\", \"id\", \"destination\", \"currency\",\n\"transfer_group\", \"created\"} when it was a Stripe transfer. A Stripe\nleg's amount, and both totals, used to be in cents while a wallet leg's\nwas in dollars."},"ReleaseRefusal":{"properties":{"detail":{"type":"string","title":"Detail","description":"Why, in English"},"code":{"type":"string","enum":["not_found","not_seller","already_released","in_progress","refunded","unpaid","needs_review","not_confirmed","delivery_code_rejected","seller_must_connect_stripe","sale_changed","campaign_deleted","provider_error"],"title":"Code","description":"not_found (404), not_seller (403), and with 400: already_released, in_progress (being released or refunded right now), refunded, unpaid, needs_review (waiting on an admin), not_confirmed (the buyer hasn't confirmed delivery), delivery_code_rejected (a wrong code, or no tries left), seller_must_connect_stripe (a card sale whose seller has no Stripe account that can be paid), sale_changed (it changed while being released; reload), campaign_deleted, provider_error (anything else; still held, try again later)"}},"type":"object","required":["detail","code"],"title":"ReleaseRefusal","description":"What POST /payments/release-escrow/{id} answers when it doesn't release.\n\n`code` says why and doesn't change, so a client words it itself.\n`detail` is an English sentence of ours, never an exception's or Stripe's\ntext, kept for the clients that still show or match it."},"ReportCategory":{"type":"string","enum":["fraud","inappropriate","misleading","spam","other"],"title":"ReportCategory","description":"Categories for campaign reports"},"ReportResolution":{"type":"string","enum":["warning_issued","campaign_removed","no_action","under_investigation"],"title":"ReportResolution","description":"Resolution types for reviewed reports"},"ReportStatus":{"type":"string","enum":["pending","under_review","resolved","dismissed"],"title":"ReportStatus","description":"Status of a campaign report"},"ResendWebhookReceipt":{"properties":{"status":{"type":"string","title":"Status","description":"'ok' or 'already_processed'"},"event_type":{"type":"string","title":"Event Type"},"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"'suppressed', 'logged_not_suppressed' or 'ignored'"}},"type":"object","required":["status","event_type"],"title":"ResendWebhookReceipt","description":"POST /webhooks/resend. Resend reads the status code. An event already\nprocessed gets no action, so this is sent without unset keys."},"ResolvedCity":{"properties":{"city":{"type":"string","title":"City","default":""},"region":{"type":"string","title":"Region","default":""},"country_code":{"type":"string","title":"Country Code","default":""},"label":{"type":"string","title":"Label","default":""},"available":{"type":"boolean","title":"Available","default":false},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"ResolvedCity","description":"A picked city, as its parts and as the line that names it.\n\n`label` is what a campaign or a listing stores -- \"Providence, RI\" -- and\nit is composed on the server so the surfaces that keep it cannot each\ncompose it differently. The parts come too, because a surface that wants\nto place the thing on a map needs the city and the region apart.\n\n`available` false means the pick resolved to no city. It is the one\nfailure a caller has to act on: nothing can be stored, so the box stays\nopen rather than closing on an empty answer."},"ResolvedSuggestion":{"properties":{"address":{"anyOf":[{"$ref":"#/components/schemas/SuggestedAddress"},{"type":"null"}]},"incomplete":{"items":{"type":"string"},"type":"array","title":"Incomplete","default":[]},"available":{"type":"boolean","title":"Available","default":false}},"type":"object","title":"ResolvedSuggestion","description":"What a pick filled in, and what the person still has to.\n\n`incomplete` names the fields a form should keep asking for. A street\nwith no house number is in it even though the street line is not empty:\nGoogle resolves `Angell St, Providence` happily and nothing is delivered\nto it."},"ReviewPromptPolicy":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"minimum_completed_actions":{"type":"integer","title":"Minimum Completed Actions"},"cooldown_days":{"type":"integer","title":"Cooldown Days"}},"type":"object","required":["enabled","minimum_completed_actions","cooldown_days"],"title":"ReviewPromptPolicy","description":"When an app may ask for a store review.\n\nServed rather than compiled in because the rules cannot be measured\ndirectly and will need tuning. Neither store tells you whether the dialog\nwas shown — iOS caps the prompt at roughly three a year per user, Play\nkeeps its own quota, and both silently do nothing once it is spent. So the\nonly feedback is the review count moving weeks later, and every adjustment\nwould otherwise cost a two-week store review on both platforms.\n\n`enabled` is the kill switch. `minimum_completed_actions` is the count of\ndonations or purchases a person must have finished before being asked at\nall: asking after the first one spends a scarce prompt on somebody who has\nno opinion yet. `cooldown_days` keeps a second ask away from someone who\nhas already been asked and did not act.\n\nThe prompt itself must never hang off a button. Apple rejects a review\nrequest made in response to a user asking for one, and Google rejects\ngating it behind \"do you like the app?\" — so these rules describe when the\napp volunteers it after something has gone well, and nothing else."},"SaleBreakdown":{"properties":{"sale":{"items":{"$ref":"#/components/schemas/BuyerPaysRow"},"type":"array","title":"Sale","description":"What the recipients divide: items (the item's price) and, on a digital item, digital_fee. Not the buyer's tip or the processing fee they were billed"},"recipients":{"items":{"$ref":"#/components/schemas/RecipientRow"},"type":"array","title":"Recipients","description":"seller and campaign with their shares (pct), opengiving_fee, and processing_fee when the sale bore it. They add up to the sale rows"}},"type":"object","required":["sale","recipients"],"title":"SaleBreakdown","description":"Where a sale's money goes, as its seller sees it (sale_breakdown)."},"SaleRefundHistoryItem":{"properties":{"refund_type":{"type":"string","title":"Refund Type"},"transaction_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Transaction Id"},"contribution_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contribution Id"},"original_amount":{"type":"number","title":"Original Amount"},"refund_amount":{"type":"number","title":"Refund Amount"},"requester_id":{"type":"string","format":"uuid","title":"Requester Id"},"recipient_id":{"type":"string","format":"uuid","title":"Recipient Id"},"reason":{"type":"string","title":"Reason"},"requester_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Notes"},"id_refund":{"type":"string","format":"uuid","title":"Id Refund"},"status":{"type":"string","title":"Status"},"admin_reviewer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Admin Reviewer Id"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"stripe_refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Refund Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id"},"organizer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organizer Name"},"donor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Donor Name"},"requester_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requester Name"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"admin_reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Reviewer Name"},"decision":{"type":"string","enum":["approved","declined"],"title":"Decision","description":"What the last decision on it was"},"decided_by":{"type":"string","enum":["seller","organizer","opengiving"],"title":"Decided By","description":"Who made that decision: the caller, as seller or organizer, or OpenGiving (an admin, or a refund recorded from Stripe)"},"decline_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decline Reason","description":"The reason the payer was given, when it was declined with one"},"outcome":{"type":"string","enum":["refunded","in_progress","waiting_on_opengiving","declined","failed"],"title":"Outcome","description":"refunded: the money went back. in_progress: approved and on its way. waiting_on_opengiving: approved, and an admin decides the rest. failed: the payment provider refused it. declined: turned down"}},"type":"object","required":["refund_type","original_amount","refund_amount","requester_id","recipient_id","reason","id_refund","status","created_at","updated_at","decision","decided_by","outcome"],"title":"SaleRefundHistoryItem","description":"GET /refunds/refunds/seller/history: a decided refund on one of the\ncaller's sales. The seller pending list's row, and how it was decided."},"SellerRatingsSummary":{"properties":{"seller_id":{"type":"string","format":"uuid","title":"Seller Id"},"average_rating":{"type":"number","title":"Average Rating","description":"Average seller rating"},"total_reviews":{"type":"integer","title":"Total Reviews","description":"Total number of reviews"},"rating_breakdown":{"additionalProperties":true,"type":"object","title":"Rating Breakdown","description":"Breakdown of ratings by star count"}},"type":"object","required":["seller_id","average_rating","total_reviews","rating_breakdown"],"title":"SellerRatingsSummary"},"ServiceBriefUpdate":{"properties":{"brief":{"type":"string","maxLength":10000,"minLength":1,"title":"Brief","description":"What the buyer needs"}},"type":"object","required":["brief"],"title":"ServiceBriefUpdate"},"ServiceDeliverRequest":{"properties":{"delivery_note":{"type":"string","maxLength":10000,"minLength":1,"title":"Delivery Note","description":"What was delivered / where to find it"}},"type":"object","required":["delivery_note"],"title":"ServiceDeliverRequest"},"ServiceDisputeRequest":{"properties":{"reason":{"type":"string","maxLength":10000,"minLength":1,"title":"Reason","description":"Why the delivery is being disputed"}},"type":"object","required":["reason"],"title":"ServiceDisputeRequest"},"ServiceFeeUnrecorded":{"properties":{"kind":{"type":"string","title":"Kind","description":"transaction or contribution"},"id":{"type":"string","title":"Id"},"problem":{"type":"string","title":"Problem","description":"not_recorded: settled with no service fee on record. margin_exceeds_fee: the recorded margin is more than the fee, so the processor kept less than nothing."},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider"},"paid_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paid At","description":"ISO 8601"},"service_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Service Fee"},"service_fee_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Service Fee Margin"}},"type":"object","required":["kind","id","problem"],"title":"ServiceFeeUnrecorded"},"ServiceOrder":{"properties":{"id_order":{"type":"string","format":"uuid","title":"Id Order"},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id"},"status":{"type":"string","title":"Status"},"brief":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brief"},"delivery_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Note"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At"},"auto_accept_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Auto Accept At"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"disputed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Disputed At"},"dispute_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dispute Reason"},"resolution":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution"},"resolution_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution Note","description":"The admin's note on how a dispute was settled. Sent to admins only; null for the buyer and seller"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id_order","transaction_id","status"],"title":"ServiceOrder","description":"A purchased service's fulfillment workflow state."},"ServiceOrderWithContext":{"properties":{"id_order":{"type":"string","format":"uuid","title":"Id Order"},"transaction_id":{"type":"string","format":"uuid","title":"Transaction Id"},"status":{"type":"string","title":"Status"},"brief":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brief"},"delivery_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Note"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At"},"auto_accept_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Auto Accept At"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"disputed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Disputed At"},"dispute_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dispute Reason"},"resolution":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution"},"resolution_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution Note","description":"The admin's note on how a dispute was settled. Sent to admins only; null for the buyer and seller"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"product_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Product Id"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title"},"buyer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Buyer Id"},"seller_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Seller Id"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name"},"total_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Amount"},"total_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Charged","description":"What the buyer was charged for this order, processing fee included. Sent to the buyer only, once paid; null otherwise"},"sale_breakdown":{"anyOf":[{"$ref":"#/components/schemas/SaleBreakdown"},{"type":"null"}],"description":"Where the sale's money goes, as rows: the item's price, then the seller, the campaign, OpenGiving's fee and any processing fee the sale bore. Sent to the seller, and to the dispute desk that decides where this order's money goes (AdminDisputeItem); null for the buyer"}},"type":"object","required":["id_order","transaction_id","status"],"title":"ServiceOrderWithContext","description":"Order plus the listing/party context clients need to render it."},"SetPrimaryImageRequest":{"properties":{"image_id":{"type":"string","title":"Image Id","description":"ID of the image to set as primary"}},"type":"object","required":["image_id"],"title":"SetPrimaryImageRequest"},"SetPrimaryImageResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"type":"string","title":"Message","default":"Primary image updated successfully"},"entity_id":{"type":"string","title":"Entity Id","description":"ID of the campaign or product"},"primary_image":{"$ref":"#/components/schemas/ImageResponse","description":"The new primary image"}},"type":"object","required":["entity_id","primary_image"],"title":"SetPrimaryImageResponse"},"SettleOfflineRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":3,"title":"Reason","description":"Who was actually paid, and when. Recorded on the row."},"credit_campaign_total":{"type":"boolean","title":"Credit Campaign Total","description":"Add this sale's campaign share to the campaign's public raised total. Off by default: whether a hand-paid sale should move a live campaign's public number is a judgement call.","default":false}},"type":"object","required":["reason"],"title":"SettleOfflineRequest"},"SettleOfflineResponse":{"properties":{"transaction_id":{"type":"string","title":"Transaction Id"},"escrow_status":{"type":"string","title":"Escrow Status"},"campaign_credited":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Campaign Credited"}},"type":"object","required":["transaction_id","escrow_status"],"title":"SettleOfflineResponse"},"ShippingAddressBase":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","description":"Recipient name"},"street1":{"type":"string","maxLength":255,"title":"Street1","description":"Street address line 1"},"street2":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Street2","description":"Street address line 2"},"city":{"type":"string","maxLength":100,"title":"City","description":"City"},"state":{"type":"string","maxLength":2,"minLength":2,"title":"State","description":"State code (2 letters)"},"zip":{"type":"string","maxLength":10,"title":"Zip","description":"ZIP/postal code"},"country":{"type":"string","maxLength":2,"title":"Country","description":"Country code (2 letters)","default":"US"},"phone":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Phone","description":"Phone number"},"email":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Email","description":"Email address"}},"type":"object","required":["name","street1","city","state","zip"],"title":"ShippingAddressBase","description":"Base shipping address fields"},"ShippingAddressSchema":{"properties":{"name":{"type":"string","maxLength":100,"minLength":2,"title":"Name","description":"Recipient full name"},"street":{"type":"string","maxLength":255,"minLength":1,"title":"Street","description":"Street address"},"complement":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Complement","description":"Apt, Suite, etc."},"district":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"District","description":"Neighbourhood (bairro)"},"city":{"type":"string","maxLength":100,"minLength":1,"title":"City","description":"City"},"state":{"type":"string","maxLength":100,"minLength":1,"title":"State","description":"State, province or region"},"zip_code":{"type":"string","maxLength":20,"minLength":3,"title":"Zip Code","description":"Postal code"},"country":{"type":"string","title":"Country","description":"Country","default":"USA"}},"type":"object","required":["name","street","city","state","zip_code"],"title":"ShippingAddressSchema","description":"Shipping address for checkout"},"ShippingRate":{"properties":{"rate_id":{"type":"string","title":"Rate Id","description":"Shippo rate object ID (use this to purchase)"},"carrier":{"type":"string","title":"Carrier","description":"Carrier name (e.g., 'USPS', 'UPS', 'FedEx')"},"service":{"type":"string","title":"Service","description":"Service level (e.g., 'Priority Mail', 'Ground')"},"price_cents":{"type":"integer","title":"Price Cents","description":"Shipping cost in cents"},"currency":{"type":"string","title":"Currency","description":"Currency code","default":"USD"},"estimated_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimated Days","description":"Estimated delivery days"},"duration_terms":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Duration Terms","description":"Delivery time description"}},"type":"object","required":["rate_id","carrier","service","price_cents"],"title":"ShippingRate","description":"A single shipping rate option"},"ShippingRateRequest":{"properties":{"to_address":{"$ref":"#/components/schemas/ShippingAddressBase","description":"Destination address"}},"type":"object","required":["to_address"],"title":"ShippingRateRequest","description":"Request body for getting shipping rates"},"ShippingRatesResponse":{"properties":{"shipment_id":{"type":"string","title":"Shipment Id","description":"Shippo shipment ID (for tracking the rate lookup)"},"rates":{"items":{"$ref":"#/components/schemas/ShippingRate"},"type":"array","title":"Rates","description":"Available shipping rates sorted by price"}},"type":"object","required":["shipment_id"],"title":"ShippingRatesResponse","description":"Response containing available shipping rates"},"ShippingUpdate":{"properties":{"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number","description":"Tracking number"},"delivery_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Method","description":"Delivery method: shipping or pickup; omit to keep the order's own"},"delivery_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Notes","description":"Additional notes"}},"type":"object","title":"ShippingUpdate"},"SplitOverrun":{"properties":{"transaction_id":{"type":"string","title":"Transaction Id"},"total_amount":{"type":"number","title":"Total Amount"},"platform_tip":{"type":"number","title":"Platform Tip"},"sale":{"type":"number","title":"Sale"},"buyer_fee":{"type":"number","title":"Buyer Fee"},"seller_amount":{"type":"number","title":"Seller Amount"},"campaign_amount":{"type":"number","title":"Campaign Amount"},"overrun":{"type":"number","title":"Overrun"}},"type":"object","required":["transaction_id","total_amount","platform_tip","sale","buyer_fee","seller_amount","campaign_amount","overrun"],"title":"SplitOverrun"},"StateList":{"properties":{"states":{"items":{"$ref":"#/components/schemas/Place"},"type":"array","title":"States"}},"type":"object","required":["states"],"title":"StateList","description":"GET /geography/states. No client calls it."},"Status":{"properties":{"status":{"type":"string","title":"Status","description":"'ok' or 'success'"}},"type":"object","required":["status"],"title":"Status","description":"{\"status\": ...}"},"StoredPaymentStatus":{"properties":{"payment_intent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Intent Id","description":"Stripe PaymentIntent id; null when none is on record"},"status":{"type":"string","title":"Status","description":"Payment status"},"payment_type":{"type":"string","title":"Payment Type","description":"marketplace_transaction or direct_contribution"},"amount":{"type":"number","title":"Amount","description":"Amount in dollars"},"currency":{"type":"string","title":"Currency","description":"Currency code"},"last_updated":{"type":"string","title":"Last Updated","description":"When the status last changed, ISO 8601"}},"type":"object","required":["status","payment_type","amount","currency","last_updated"],"title":"StoredPaymentStatus","description":"GET /transactions/{id}/payment-status and /direct_contributions/{id}/payment-status.\n\nWhat Stripe says about the payment, else what is stored. No client calls\neither route."},"StoredShippingRate":{"properties":{"status":{"type":"string","title":"Status","description":"Always 'success'"},"message":{"type":"string","title":"Message","description":"Always 'Shipping rate stored'"}},"type":"object","required":["status","message"],"title":"StoredShippingRate","description":"POST /shipping/store-rate/{transaction_id}.\n\niOS (StoreRateAcknowledgement) and Android (StoreRateResponseDto) decode\nboth keys as required strings, and both abort checkout when the decode\nfails, so neither may be dropped or null."},"StrandedClaimMoney":{"properties":{"token_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token Id"},"campaign_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Id"},"claimed_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimed By"},"claimed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimed At","description":"ISO 8601"},"holder_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Holder Id"},"holder_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Holder Email"},"stranded":{"type":"number","title":"Stranded"}},"type":"object","required":["stranded"],"title":"StrandedClaimMoney"},"StreakStats":{"properties":{"current_streak_weeks":{"type":"integer","title":"Current Streak Weeks","description":"Current streak in weeks","default":0},"longest_streak_weeks":{"type":"integer","title":"Longest Streak Weeks","description":"Longest streak in weeks","default":0},"active_days":{"type":"integer","title":"Active Days","description":"Total unique days with donations","default":0},"active_weeks":{"type":"integer","title":"Active Weeks","description":"Total unique weeks with donations","default":0}},"type":"object","title":"StreakStats","description":"Donation streak statistics"},"StripeAccountCheck":{"properties":{"has_account":{"type":"boolean","title":"Has Account"},"account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id","description":"Stripe account id; absent without an account"},"onboarding_complete":{"type":"boolean","title":"Onboarding Complete"},"can_receive_payments":{"type":"boolean","title":"Can Receive Payments","description":"Stripe's charges_enabled"},"can_receive_payouts":{"type":"boolean","title":"Can Receive Payouts","description":"Stripe's payouts_enabled"},"test_mode":{"type":"boolean","title":"Test Mode"},"supported_countries":{"items":{"type":"string"},"type":"array","title":"Supported Countries","description":"The countries, as ISO 3166-1 alpha-2, whose sellers can connect Stripe to be paid for card sales. Today [\"US\"]. Buyers can pay any seller by card; a card sale for a seller anywhere else is held for them and paid when they ask support for it.","examples":[["US"]]},"payout_country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Country","description":"The country the seller said they're paid in, as ISO 3166-1 alpha-2, or null if they haven't said. Set with PUT /stripe/connect/payout-country, or by the country sent to onboarding-link or create-account.","examples":["US"]},"card_payouts":{"type":"string","enum":["not_stated","paypal_only","not_connected","setting_up","connected"],"title":"Card Payouts","description":"Where the seller's card payouts stand. not_stated: no country and no Stripe account; ask where they're based, then PUT payout-country. paypal_only: they said a country outside supported_countries, so they're never offered Stripe; their card sales are held for them and paid when they ask support for them. not_connected: a supported country and no account; offer to connect (onboarding-link). Their card sales are held for them until they connect, and after CARD_SALE_CONNECT_GRACE_DAYS paid only on request. setting_up: an account that can't be paid yet; offer to finish (onboarding-link). connected: card sales can be paid to the account, whatever country was stated. Offer \"Connect Stripe\" on seller surfaces for not_stated, not_connected and setting_up, and only when sells_for_themselves is true.","examples":["not_connected"]},"sells_for_themselves":{"type":"boolean","title":"Sells For Themselves","description":"Whether any of the seller's listings pays them when it sells (gives the campaign less than 100%), counting listings that aren't deleted or sold. False with no listings. A seller whose every listing gives 100% is paid nothing, so there is nothing for Stripe to receive: don't prompt them to connect."}},"type":"object","required":["has_account","onboarding_complete","can_receive_payments","can_receive_payouts","test_mode","supported_countries","payout_country","card_payouts","sells_for_themselves"],"title":"StripeAccountCheck","description":"GET /stripe/connect/has-account and PUT /stripe/connect/payout-country.\n\nOne answer for where the caller's card payouts stand, so no client works\nit out for itself. iOS (StripeAccountCheck) requires every key but\naccount_id; web reads has_account, onboarding_complete, test_mode and both\ncapabilities. account_id is sent only when there is an account.\n\nWhether to offer \"Connect Stripe\" on a seller surface: offer it when\nsells_for_themselves is true and card_payouts is not_stated,\nnot_connected or setting_up. Don't offer it for connected or\npaypal_only, or when sells_for_themselves is false."},"StripeConfig":{"properties":{"publishable_key":{"type":"string","title":"Publishable Key","description":"Stripe publishable key for frontend SDK"},"platform_fee_percentage":{"type":"number","title":"Platform Fee Percentage","description":"Platform fee percentage"},"currency":{"type":"string","title":"Currency","description":"Default currency","default":"USD"},"test_mode":{"type":"boolean","title":"Test Mode","description":"Whether using test mode","default":false},"card_payments_enabled":{"type":"boolean","title":"Card Payments Enabled","description":"Whether card charges can currently succeed. False while the Stripe account cannot accept charges, so clients hide the card form.","default":true}},"type":"object","required":["publishable_key","platform_fee_percentage"],"title":"StripeConfig","description":"Stripe public configuration for frontend"},"StripeEscrowCoverage":{"properties":{"problem":{"type":"string","title":"Problem","description":"payouts_not_manual: Stripe pays the balance out on a schedule while card money is owed out of it. balance_short: the live balance is less than the card money still to be transferred."},"held_sales":{"type":"integer","title":"Held Sales","description":"Sales whose escrow is still held"},"held_shares":{"type":"integer","title":"Held Shares","description":"Released shares held for a recipient who can't receive them yet","default":0},"owed":{"type":"number","title":"Owed","description":"Card money still to transfer out of the live balance, USD"},"payout_interval":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Interval"},"balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Balance","description":"Live available + pending, USD"},"short":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Short"},"detail":{"type":"string","title":"Detail"}},"type":"object","required":["problem","held_sales","owed","detail"],"title":"StripeEscrowCoverage"},"StripeWebhookReceipt":{"properties":{"status":{"type":"string","title":"Status","description":"Always 'success'"},"event_type":{"type":"string","title":"Event Type","description":"The Stripe event's type"},"duplicate":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Duplicate"}},"type":"object","required":["status","event_type"],"title":"StripeWebhookReceipt","description":"What POST /stripe/webhook tells Stripe. `duplicate` is sent only for\nan event already processed."},"SuccessMessage":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"message":{"type":"string","title":"Message","description":"What happened, in English"}},"type":"object","required":["success","message"],"title":"SuccessMessage","description":"{\"success\": true, \"message\": ...}"},"SuggestedAddress":{"properties":{"street1":{"type":"string","title":"Street1","default":""},"street2":{"type":"string","title":"Street2","default":""},"district":{"type":"string","title":"District","default":""},"city":{"type":"string","title":"City","default":""},"region":{"type":"string","title":"Region","default":""},"postal_code":{"type":"string","title":"Postal Code","default":""},"country_code":{"type":"string","title":"Country Code","default":""}},"type":"object","title":"SuggestedAddress","description":"A picked suggestion, in the field names every surface already uses."},"SuggestionStatus":{"type":"string","enum":["pending","approved","rejected","implemented"],"title":"SuggestionStatus"},"SuggestionType":{"type":"string","enum":["campaign","product"],"title":"SuggestionType"},"TestNotificationRequest":{"properties":{"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Custom test message","default":"This is a test notification from OpenGiving!"},"notification_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notification Type","description":"Type of test notification","default":"test"}},"type":"object","title":"TestNotificationRequest","description":"Schema for sending test notifications."},"TipAnalytics":{"properties":{"total_tips":{"type":"number","title":"Total Tips"},"tips_from_donations":{"type":"number","title":"Tips From Donations"},"tips_from_purchases":{"type":"number","title":"Tips From Purchases"},"total_tip_transactions":{"type":"integer","title":"Total Tip Transactions"},"donation_tip_count":{"type":"integer","title":"Donation Tip Count"},"purchase_tip_count":{"type":"integer","title":"Purchase Tip Count"},"average_tip_amount":{"type":"number","title":"Average Tip Amount"},"average_tip_percentage":{"type":"number","title":"Average Tip Percentage"},"tips_by_day":{"items":{},"type":"array","title":"Tips By Day"},"tips_by_week":{"items":{},"type":"array","title":"Tips By Week"},"top_tippers":{"items":{},"type":"array","title":"Top Tippers"}},"type":"object","required":["total_tips","tips_from_donations","tips_from_purchases","total_tip_transactions","donation_tip_count","purchase_tip_count","average_tip_amount","average_tip_percentage","tips_by_day","tips_by_week","top_tippers"],"title":"TipAnalytics"},"TipSummary":{"properties":{"today":{"$ref":"#/components/schemas/TipTotals"},"this_month":{"$ref":"#/components/schemas/TipTotals"},"all_time":{"$ref":"#/components/schemas/TipTotals"}},"type":"object","required":["today","this_month","all_time"],"title":"TipSummary","description":"GET /admin/analytics/tips/summary. Web's tip-analytics page reads all nine figures."},"TipTotals":{"properties":{"total":{"type":"number","title":"Total"},"donations":{"type":"number","title":"Donations"},"purchases":{"type":"number","title":"Purchases"}},"type":"object","required":["total","donations","purchases"],"title":"TipTotals"},"TotalRow":{"properties":{"kind":{"type":"string","enum":["total_charge","total_by_card","total_with_paypal"],"title":"Kind","description":"total_charge: the one total. total_by_card / total_with_paypal: that rail's total, beside another rail's"},"amount_cents":{"type":"integer","title":"Amount Cents"}},"type":"object","required":["kind","amount_cents"],"title":"TotalRow","description":"A total row, named as it's drawn."},"TrackingEvent":{"properties":{"status":{"type":"string","title":"Status","description":"Event status"},"status_details":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Details","description":"Detailed status description"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date","description":"Event timestamp"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Event location (city, state)"}},"type":"object","required":["status"],"title":"TrackingEvent","description":"A single tracking event in shipment history"},"TrackingResponse":{"properties":{"carrier":{"type":"string","title":"Carrier","description":"Carrier name"},"tracking_number":{"type":"string","title":"Tracking Number","description":"Tracking number"},"status":{"type":"string","title":"Status","description":"Current status (e.g., 'TRANSIT', 'DELIVERED')"},"status_details":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Details","description":"Detailed status"},"status_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Date","description":"Last status update time"},"eta":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Eta","description":"Estimated delivery date"},"history":{"items":{"$ref":"#/components/schemas/TrackingEvent"},"type":"array","title":"History","description":"Tracking event history"}},"type":"object","required":["carrier","tracking_number","status"],"title":"TrackingResponse","description":"Tracking information for a shipment"},"Transaction":{"properties":{"product_id":{"type":"string","format":"uuid","title":"Product Id","description":"Unique identifier of the product"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Unique identifier of the campaign"},"total_amount":{"type":"number","title":"Total Amount","description":"Total amount of the transaction"},"campaign_amount":{"type":"number","title":"Campaign Amount","description":"Amount of the transaction for the campaign"},"seller_amount":{"type":"number","title":"Seller Amount","description":"Amount of the transaction for the seller"},"platform_tip":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Platform Tip","description":"Optional tip to OpenGiving platform","default":0},"buyer_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Buyer Fee","description":"Flat fee billed to the buyer above the list price","default":0},"status":{"type":"string","title":"Status","description":"Status of the transaction"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address","description":"Shipping address of the transaction (None for non-shippable items)"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"id_transaction":{"type":"string","format":"uuid","title":"Id Transaction","description":"Unique identifier of the transaction"},"buyer_id":{"type":"string","format":"uuid","title":"Buyer Id","description":"Unique identifier of the buyer"},"payment_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Status","description":"Payment status"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At","description":"Payment timestamp"},"delivery_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Status","description":"Delivery status: pending, shipped, delivered","default":"pending"},"escrow_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Escrow Status","description":"Escrow status: hold_pending, held, released, release_pending"},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider","description":"Which rail took the money: paypal or stripe. Null on a row older than the column, which was a card sale"},"escrow_released":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Escrow Released","description":"Whether this sale's escrow has been paid out to the seller and the campaign"},"escrow_released_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Escrow Released At","description":"When the escrow was paid out"},"refunded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Refunded At","description":"When the buyer was refunded in full. A sale refunded before this was stamped says so in status alone"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number","description":"Tracking number for shipment"},"delivery_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Method","description":"Delivery method: shipping, pickup, digital or service"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At","description":"Shipment timestamp"},"delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At","description":"Delivery timestamp"},"delivery_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Notes","description":"Additional delivery notes"},"shipping_address_json":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Shipping Address Json","description":"Structured record of where this order was sent"},"shipping_carrier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Carrier","description":"Carrier name (USPS, UPS, FedEx)"},"shipping_rate_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Shipping Rate Cents","description":"Shipping cost in cents"},"shipping_label_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Label Url","description":"URL to label PDF"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url","description":"Carrier tracking URL"},"shippo_transaction_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shippo Transaction Id","description":"Shippo label transaction ID"},"shippo_shipment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shippo Shipment Id","description":"Shippo shipment ID"},"shippo_rate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shippo Rate Id","description":"Shippo rate ID for label purchase"},"delivery_confirmation_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Confirmation Code","description":"4-digit delivery confirmation code. Sent to the transaction's buyer only; null for everyone else"},"code_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Code Expires At","description":"Code expiry timestamp"},"code_attempts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Code Attempts","description":"Number of code verification attempts","default":0},"code_verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Code Verified At","description":"Code verification timestamp"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["product_id","seller_id","campaign_id","total_amount","campaign_amount","seller_amount","status","id_transaction","buyer_id"],"title":"Transaction"},"TransactionCreate":{"properties":{"product_id":{"type":"string","format":"uuid","title":"Product Id","description":"Unique identifier of the product"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Campaign Id","description":"The campaign the buyer chose. Omit for a listing that names its own"},"total_amount":{"type":"number","title":"Total Amount","description":"Total amount of the transaction"},"campaign_amount":{"type":"number","title":"Campaign Amount","description":"Amount of the transaction for the campaign"},"seller_amount":{"type":"number","title":"Seller Amount","description":"Amount of the transaction for the seller"},"platform_tip":{"anyOf":[{"type":"number","maximum":10000.0,"minimum":0.0},{"type":"null"}],"title":"Platform Tip","description":"Optional tip to OpenGiving platform","default":0},"buyer_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Buyer Fee","description":"Flat fee billed to the buyer above the list price","default":0},"status":{"type":"string","title":"Status","description":"Status of the transaction"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address","description":"Shipping address of the transaction (None for non-shippable items)"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"donation_pct":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Donation Pct","description":"The share of the price the buyer chose to give, for a listing that names none"},"anonymous":{"type":"boolean","title":"Anonymous","description":"Keep the buyer's name off the campaign's public donor list","default":false},"offer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Offer Id","description":"An accepted offer to buy this listing at"}},"type":"object","required":["product_id","seller_id","total_amount","campaign_amount","seller_amount","status"],"title":"TransactionCreate"},"TransactionRefundStatus":{"properties":{"has_refund":{"type":"boolean","title":"Has Refund"},"transaction_id":{"type":"string","title":"Transaction Id"},"refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refund Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"refund_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Refund Amount"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"reviewed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reviewed At"},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At"}},"type":"object","required":["has_refund","transaction_id"],"title":"TransactionRefundStatus","description":"GET /refunds/transactions/{id}/refund-status. With no refund, only\nhas_refund and transaction_id are sent. No client calls it."},"TransactionSyncStatus":{"properties":{"message":{"type":"string","title":"Message","description":"What the sync did, in English"},"status":{"type":"string","title":"Status","description":"The transaction's payment status after the sync"}},"type":"object","required":["message","status"],"title":"TransactionSyncStatus","description":"POST /transactions/{id}/sync-status. iOS and Android decode both keys as\nrequired strings; web reads neither."},"TransactionWithDetails":{"properties":{"product_id":{"type":"string","format":"uuid","title":"Product Id","description":"Unique identifier of the product"},"seller_id":{"type":"string","format":"uuid","title":"Seller Id","description":"Unique identifier of the seller"},"campaign_id":{"type":"string","format":"uuid","title":"Campaign Id","description":"Unique identifier of the campaign"},"total_amount":{"type":"number","title":"Total Amount","description":"Total amount of the transaction"},"campaign_amount":{"type":"number","title":"Campaign Amount","description":"Amount of the transaction for the campaign"},"seller_amount":{"type":"number","title":"Seller Amount","description":"Amount of the transaction for the seller"},"platform_tip":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Platform Tip","description":"Optional tip to OpenGiving platform","default":0},"buyer_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Buyer Fee","description":"Flat fee billed to the buyer above the list price","default":0},"status":{"type":"string","title":"Status","description":"Status of the transaction"},"shipping_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Address","description":"Shipping address of the transaction (None for non-shippable items)"},"shipping_address_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Shipping Address Id"},"id_transaction":{"type":"string","format":"uuid","title":"Id Transaction","description":"Unique identifier of the transaction"},"buyer_id":{"type":"string","format":"uuid","title":"Buyer Id","description":"Unique identifier of the buyer"},"payment_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Status","description":"Payment status"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At","description":"Payment timestamp"},"delivery_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Status","description":"Delivery status: pending, shipped, delivered","default":"pending"},"escrow_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Escrow Status","description":"Escrow status: hold_pending, held, released, release_pending"},"payment_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Provider","description":"Which rail took the money: paypal or stripe. Null on a row older than the column, which was a card sale"},"escrow_released":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Escrow Released","description":"Whether this sale's escrow has been paid out to the seller and the campaign"},"escrow_released_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Escrow Released At","description":"When the escrow was paid out"},"refunded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Refunded At","description":"When the buyer was refunded in full. A sale refunded before this was stamped says so in status alone"},"tracking_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Number","description":"Tracking number for shipment"},"delivery_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Method","description":"Delivery method: shipping, pickup, digital or service"},"shipped_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Shipped At","description":"Shipment timestamp"},"delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At","description":"Delivery timestamp"},"delivery_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Notes","description":"Additional delivery notes"},"shipping_address_json":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Shipping Address Json","description":"Structured record of where this order was sent"},"shipping_carrier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Carrier","description":"Carrier name (USPS, UPS, FedEx)"},"shipping_rate_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Shipping Rate Cents","description":"Shipping cost in cents"},"shipping_label_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shipping Label Url","description":"URL to label PDF"},"tracking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracking Url","description":"Carrier tracking URL"},"shippo_transaction_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shippo Transaction Id","description":"Shippo label transaction ID"},"shippo_shipment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shippo Shipment Id","description":"Shippo shipment ID"},"shippo_rate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shippo Rate Id","description":"Shippo rate ID for label purchase"},"delivery_confirmation_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Confirmation Code","description":"4-digit delivery confirmation code. Sent to the transaction's buyer only; null for everyone else"},"code_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Code Expires At","description":"Code expiry timestamp"},"code_attempts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Code Attempts","description":"Number of code verification attempts","default":0},"code_verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Code Verified At","description":"Code verification timestamp"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp"},"product_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Title","description":"Product title"},"product_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Description","description":"Product description"},"product_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Image Url","description":"Product image URL"},"campaign_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Title","description":"Campaign title"},"campaign_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign Slug","description":"Campaign slug"},"seller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Name","description":"Seller full name"},"buyer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Name","description":"Buyer full name"},"buyer_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Email","description":"The buyer's email. Sent to the transaction's buyer only; null for everyone else"},"refund_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refund Status","description":"Refund status"},"refund_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refund Id","description":"Refund ID"},"refund_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Refund Amount","description":"Refund amount"},"total_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Charged","description":"What the buyer was charged for this purchase: the item, the tip, the flat fee, the postage and the processing fee they were billed. A cart item's is its share of the cart's one charge, and a cart's items add up to it. total_amount is the item and, on a single-item purchase, its tip, and leaves the rest out. Sent to the transaction's buyer only, once it's paid; null otherwise"},"payment_breakdown":{"anyOf":[{"$ref":"#/components/schemas/PaymentBreakdown"},{"type":"null"}],"description":"What the buyer paid, as rows to show: the item, the tip, the flat fee, the postage, then the processing fee and the total once paid. Sent to the transaction's buyer only; null for everyone else"},"sale_breakdown":{"anyOf":[{"$ref":"#/components/schemas/SaleBreakdown"},{"type":"null"}],"description":"Where the sale's money goes, as rows to show: the item and its flat fee, then the seller, the campaign, OpenGiving's fee and any processing fee the sale bore. Read from the row's split, which escrow release pays out. Sent to the transaction's seller only; null for everyone else"},"seller_can_be_paid":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Seller Can Be Paid","description":"Whether releasing this sale could pay its seller now: a PayPal sale always can, a card sale when the seller has a connected Stripe account that can be paid (services/card_sellers.sellers_can_be_paid). Sent to the transaction's seller only; null for everyone else"}},"type":"object","required":["product_id","seller_id","campaign_id","total_amount","campaign_amount","seller_amount","status","id_transaction","buyer_id"],"title":"TransactionWithDetails","description":"Transaction with joined product, campaign, and user details"},"UncreditedEscrow":{"properties":{"transaction_id":{"type":"string","title":"Transaction Id"},"escrow_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Escrow Status"},"seller_amount":{"type":"number","title":"Seller Amount"},"campaign_amount":{"type":"number","title":"Campaign Amount"},"released_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Released At","description":"ISO 8601"},"uncredited":{"type":"number","title":"Uncredited"}},"type":"object","required":["transaction_id","seller_amount","campaign_amount","uncredited"],"title":"UncreditedEscrow"},"UpdateImageDetails":{"properties":{"id_image":{"type":"string","title":"Id Image"},"entity_id":{"type":"string","title":"Entity Id","description":"The update's id"},"update_id":{"type":"string","title":"Update Id"},"image_url":{"type":"string","title":"Image Url"},"display_order":{"type":"integer","title":"Display Order"},"is_primary":{"type":"boolean","title":"Is Primary"},"alt_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alt Text"},"file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size"},"file_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Type"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id_image","entity_id","update_id","image_url","display_order","is_primary","created_at","updated_at"],"title":"UpdateImageDetails","description":"One image of a campaign update, as the /images/campaign_update routes\nsend it. Not schemas.campaign_update.CampaignUpdateImage, which has no\nentity_id and would share its openapi name."},"UploadedCampaignImage":{"properties":{"success":{"type":"boolean","title":"Success"},"url":{"type":"string","title":"Url","description":"CloudFront URL of the uploaded image"},"campaign_id":{"type":"string","title":"Campaign Id"},"is_cover":{"type":"boolean","title":"Is Cover","description":"Whether it became the campaign's cover"}},"type":"object","required":["success","url","campaign_id","is_cover"],"title":"UploadedCampaignImage","description":"POST /images/upload/campaign/{campaign_id}."},"UploadedProductImage":{"properties":{"success":{"type":"boolean","title":"Success"},"url":{"type":"string","title":"Url","description":"CloudFront URL of the uploaded image"},"product_id":{"type":"string","title":"Product Id"},"is_main":{"type":"boolean","title":"Is Main","description":"Whether it became the product's primary image"}},"type":"object","required":["success","url","product_id","is_main"],"title":"UploadedProductImage","description":"POST /images/upload/product/{product_id}."},"UploadedProfilePicture":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always true: a failure is an error status"},"url":{"type":"string","title":"Url","description":"CloudFront URL of the new picture"}},"type":"object","required":["success","url"],"title":"UploadedProfilePicture","description":"POST /images/upload/profile-picture.\n\nAndroid (ProfilePictureResponse) decodes both keys as required; iOS and\nweb read `url`."},"User-Input":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email of the user"},"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number","description":"Phone number of the user"},"first_name":{"type":"string","title":"First Name","description":"First name of the user"},"last_name":{"type":"string","title":"Last Name","description":"Last name of the user"},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"Image URL of the user"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the user"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio","description":"Bio of the user"},"preferred_locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Locale","description":"BCP-47 tag of the user's chosen language (None = follow the client). Server-rendered surfaces — emails, push — should read this."},"id_user":{"type":"string","format":"uuid","title":"Id User","description":"Unique identifier of the user"},"role":{"$ref":"#/components/schemas/UserRole","description":"User role (user or admin)","default":"user"},"is_verified":{"type":"boolean","title":"Is Verified","description":"Whether the user is verified","default":false},"verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Verified At","description":"When the user was verified"},"location_latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the saved location preference, if known"},"location_longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the saved location preference, if known"}},"type":"object","required":["first_name","last_name","id_user"],"title":"User","description":"Full user schema with ID"},"User-Output":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email of the user"},"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number","description":"Phone number of the user"},"first_name":{"type":"string","title":"First Name","description":"First name of the user"},"last_name":{"type":"string","title":"Last Name","description":"Last name of the user"},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"Image URL of the user"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the user"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio","description":"Bio of the user"},"preferred_locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Locale","description":"BCP-47 tag of the user's chosen language (None = follow the client). Server-rendered surfaces — emails, push — should read this."},"id_user":{"type":"string","format":"uuid","title":"Id User","description":"Unique identifier of the user"},"role":{"$ref":"#/components/schemas/UserRole","description":"User role (user or admin)","default":"user"},"is_verified":{"type":"boolean","title":"Is Verified","description":"Whether the user is verified","default":false},"verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Verified At","description":"When the user was verified"},"location_latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Location Latitude","description":"Latitude of the saved location preference, if known"},"location_longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Location Longitude","description":"Longitude of the saved location preference, if known"},"needs_name":{"type":"boolean","title":"Needs Name","description":"True while the profile still has the provisioning placeholder instead of a name the person gave. Clients ask for one.","readOnly":true}},"type":"object","required":["first_name","last_name","id_user","needs_name"],"title":"User","description":"Full user schema with ID"},"UserLocationUpdate":{"properties":{"location":{"type":"string","title":"Location","description":"User's preferred location (e.g., 'Boston, MA')"},"latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Latitude","description":"Latitude of that location, if the client could resolve it"},"longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Longitude","description":"Longitude of that location, if the client could resolve it"}},"type":"object","required":["location"],"title":"UserLocationUpdate","description":"The location a person chose to be treated as theirs.\n\nThe string is what gets shown back to them; the coordinates are what\nanything can actually sort by. They are optional and separate because the\ntwo arrive by different routes: a phone reverse-geocodes its own GPS and\nknows both, while someone picking a city from a list on the web may only\never produce the name. A preference with no coordinates is still a valid\npreference — it just cannot be measured from."},"UserPublic":{"properties":{"id_user":{"type":"string","format":"uuid","title":"Id User","description":"Unique identifier of the user"},"first_name":{"type":"string","title":"First Name","description":"First name of the user"},"last_name":{"type":"string","title":"Last Name","description":"Last name of the user"},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"Image URL of the user"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location of the user"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio","description":"Bio of the user"},"is_verified":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Verified","description":"Whether the user has a verified badge"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active","description":"False once the account has been deleted"}},"type":"object","required":["id_user","first_name","last_name"],"title":"UserPublic","description":"Public user profile - contact PII (email/phone) intentionally omitted."},"UserRole":{"type":"string","enum":["user","admin"],"title":"UserRole","description":"User role enum"},"UserVerificationUpdate":{"properties":{"is_verified":{"type":"boolean","title":"Is Verified","description":"Whether to verify or unverify the user"}},"type":"object","required":["is_verified"],"title":"UserVerificationUpdate","description":"Schema for updating user verification status"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WalletBalanceDrift":{"properties":{"wallet_id":{"type":"string","title":"Wallet Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"cached":{"type":"number","title":"Cached"},"derived":{"type":"number","title":"Derived"},"drift":{"type":"number","title":"Drift"}},"type":"object","required":["wallet_id","cached","derived","drift"],"title":"WalletBalanceDrift"},"WalletLifetimeDrift":{"properties":{"wallet_id":{"type":"string","title":"Wallet Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"earned_cached":{"type":"number","title":"Earned Cached"},"earned_derived":{"type":"number","title":"Earned Derived"},"earned_drift":{"type":"number","title":"Earned Drift"},"withdrawn_cached":{"type":"number","title":"Withdrawn Cached"},"withdrawn_derived":{"type":"number","title":"Withdrawn Derived"},"withdrawn_drift":{"type":"number","title":"Withdrawn Drift"}},"type":"object","required":["wallet_id","earned_cached","earned_derived","earned_drift","withdrawn_cached","withdrawn_derived","withdrawn_drift"],"title":"WalletLifetimeDrift"},"WalletResponse":{"properties":{"available_balance":{"type":"number","minimum":0.0,"title":"Available Balance","description":"Available balance for withdrawal"},"total_earned":{"type":"number","minimum":0.0,"title":"Total Earned","description":"Total amount earned"},"total_withdrawn":{"type":"number","minimum":0.0,"title":"Total Withdrawn","description":"Total amount withdrawn"},"merchant_account_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Merchant Account Status","description":"Merchant account status"},"id_wallet":{"type":"string","format":"uuid","title":"Id Wallet"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["available_balance","total_earned","total_withdrawn","id_wallet","user_id","is_active","created_at","updated_at"],"title":"WalletResponse"},"WalletSummary":{"properties":{"available_balance":{"type":"number","title":"Available Balance"},"pending_withdrawals":{"type":"number","title":"Pending Withdrawals"},"recent_transactions":{"items":{"$ref":"#/components/schemas/WalletTransactionResponse"},"type":"array","title":"Recent Transactions"}},"type":"object","required":["available_balance","pending_withdrawals","recent_transactions"],"title":"WalletSummary","description":"Summary of wallet for dashboard display.\n\nNo held balance: escrow is tracked on the transaction (escrow_status),\nnever in the wallet, so nothing could ever hold wallet funds and the\nfigure was structurally always zero."},"WalletTransactionResponse":{"properties":{"transaction_type":{"type":"string","title":"Transaction Type","description":"Type of transaction: deposit, hold, release, withdraw, fee"},"amount":{"type":"number","title":"Amount","description":"Transaction amount (negative for withdrawals)"},"reference_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Type","description":"Type of reference: direct_contribution, marketplace_transaction, withdrawal"},"reference_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reference Id","description":"ID of related transaction/contribution"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Transaction description"},"id_transaction":{"type":"string","format":"uuid","title":"Id Transaction"},"wallet_id":{"type":"string","format":"uuid","title":"Wallet Id"},"status":{"type":"string","title":"Status"},"transaction_metadata":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transaction Metadata"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["transaction_type","amount","id_transaction","wallet_id","status","created_at","updated_at"],"title":"WalletTransactionResponse"},"WithdrawalRequest":{"properties":{"amount":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount","description":"Amount to withdraw (at least MINIMUM_WITHDRAWAL_AMOUNT)"},"paypal_email":{"type":"string","maxLength":254,"minLength":3,"title":"Paypal Email","description":"PayPal account that should receive the payout"}},"type":"object","required":["amount","paypal_email"],"title":"WithdrawalRequest"},"WithdrawalResponse":{"properties":{"withdrawal_id":{"type":"string","title":"Withdrawal Id"},"amount":{"type":"number","title":"Amount"},"status":{"type":"string","title":"Status"},"automatic":{"type":"boolean","title":"Automatic","description":"True when the payout sweep sends this withdrawal to PayPal with nobody reviewing it (usually within minutes). False when a person reviews it first: it's over the review threshold in /app/config, or automatic payouts are off"},"message":{"type":"string","title":"Message","description":"What happens next, in the caller's language (en-US or pt-BR)"}},"type":"object","required":["withdrawal_id","amount","status","automatic","message"],"title":"WithdrawalResponse","description":"POST /wallet/withdraw.\n\n`automatic` is what a client words its own confirmation from. `message`\nsays the same thing in the caller's language, for a client that shows\nit as it comes; none of the three apps does today."},"XPAwardResult":{"properties":{"newly_earned_xp":{"type":"integer","title":"Newly Earned Xp","description":"XP just awarded"},"reason":{"type":"string","title":"Reason","description":"Reason for XP award"},"total_xp":{"type":"integer","title":"Total Xp","description":"Total XP after award"},"old_level":{"type":"integer","title":"Old Level","description":"Level before award"},"new_level":{"type":"integer","title":"New Level","description":"Level after award"},"leveled_up":{"type":"boolean","title":"Leveled Up","description":"Whether user leveled up"},"levels_gained":{"type":"integer","title":"Levels Gained","description":"Number of levels gained"},"xp_to_next_level":{"type":"integer","title":"Xp To Next Level","description":"XP remaining to next level"},"next_level_xp_required":{"type":"integer","title":"Next Level Xp Required","description":"Total XP required for next level"},"progress_to_next_level":{"type":"number","title":"Progress To Next Level","description":"Progress percentage to next level (0-100)"},"new_tier":{"additionalProperties":true,"type":"object","title":"New Tier","description":"New tier information (name, color)"}},"type":"object","required":["newly_earned_xp","reason","total_xp","old_level","new_level","leveled_up","levels_gained","xp_to_next_level","next_level_xp_required","progress_to_next_level","new_tier"],"title":"XPAwardResult","description":"Result of awarding XP to a user"},"XPCalculation":{"properties":{"action":{"type":"string","title":"Action","description":"Action type"},"xp_amount":{"type":"integer","title":"Xp Amount","description":"XP that would be earned"},"description":{"type":"string","title":"Description","description":"Description of the action"}},"type":"object","required":["action","xp_amount","description"],"title":"XPCalculation","description":"XP calculation for a specific action"},"XPRewardValues":{"properties":{"donation_per_10_dollars":{"type":"integer","title":"Donation Per 10 Dollars","description":"XP per $10 donated"},"donation_max":{"type":"integer","title":"Donation Max","description":"Most XP one donation earns"},"streak_daily":{"type":"integer","title":"Streak Daily","description":"XP for keeping a daily streak"},"complete_bio":{"type":"integer","title":"Complete Bio","description":"One-time XP for completing the profile bio"},"support_new_campaign":{"type":"integer","title":"Support New Campaign","description":"XP for supporting a new campaign"},"share_profile":{"type":"integer","title":"Share Profile","description":"XP for sharing a profile"},"create_campaign":{"type":"integer","title":"Create Campaign","description":"XP for creating a campaign"},"marketplace_purchase":{"type":"integer","title":"Marketplace Purchase","description":"XP for a marketplace purchase"}},"type":"object","required":["donation_per_10_dollars","donation_max","streak_daily","complete_bio","support_new_campaign","share_profile","create_campaign","marketplace_purchase"],"title":"XPRewardValues","description":"The XP each action earns: XPService.XP_REWARDS, one field per key. A\ntest keeps the two the same, so a new reward can't be dropped here."},"XPRewards":{"properties":{"rewards":{"$ref":"#/components/schemas/XPRewardValues"},"level_tiers":{"additionalProperties":{"$ref":"#/components/schemas/LevelTier"},"type":"object","title":"Level Tiers","description":"Keyed by the band of levels, e.g. '1-5'"}},"type":"object","required":["rewards","level_tiers"],"title":"XPRewards","description":"GET /xp/rewards. Web wraps it; no screen calls it."},"ZipCodePlace":{"properties":{"city":{"type":"string","title":"City"},"state":{"type":"string","title":"State"},"zip_code":{"type":"string","title":"Zip Code"}},"type":"object","required":["city","state","zip_code"],"title":"ZipCodePlace","description":"GET /geography/zip-lookup. No client calls it."},"schemas__referral__LeaderboardEntry":{"properties":{"rank":{"type":"integer","title":"Rank","description":"Position in leaderboard"},"code":{"type":"string","title":"Code","description":"Referral code"},"owner_name":{"type":"string","title":"Owner Name","description":"Code owner name"},"owner_type":{"type":"string","title":"Owner Type","description":"Type of owner"},"total_clicks":{"type":"integer","title":"Total Clicks","description":"Total clicks","default":0},"unique_visitors":{"type":"integer","title":"Unique Visitors","description":"Unique visitors","default":0},"conversions":{"type":"integer","title":"Conversions","description":"Total conversions","default":0},"conversion_rate":{"type":"number","title":"Conversion Rate","description":"Conversion rate percentage","default":0.0}},"type":"object","required":["rank","code","owner_name","owner_type"],"title":"LeaderboardEntry","description":"Leaderboard entry for referral competition"},"schemas__xp__LeaderboardEntry":{"properties":{"rank":{"type":"integer","title":"Rank","description":"Rank on leaderboard"},"user_id":{"type":"string","title":"User Id","description":"User ID"},"user_name":{"type":"string","title":"User Name","description":"User's full name"},"level":{"type":"integer","title":"Level","description":"User's level"},"total_xp":{"type":"integer","title":"Total Xp","description":"User's total XP"},"tier_name":{"type":"string","title":"Tier Name","description":"User's tier name"},"tier_color":{"type":"string","title":"Tier Color","description":"User's tier color"}},"type":"object","required":["rank","user_id","user_name","level","total_xp","tier_name","tier_color"],"title":"LeaderboardEntry","description":"Entry in the level leaderboard"}}}}