{"openapi":"3.1.0","info":{"title":"VideoTestimonials API","version":"1.0.0","summary":"Read and manage testimonials and spaces in a VideoTestimonials account.","description":"REST API for VideoTestimonials, a platform for collecting video and text testimonials. Use it to pull approved testimonials into your own site or app, push testimonials in from another system, moderate in bulk, and manage spaces.\n\nEvery request needs an API key (see `bearerAuth`). Each account may make 1,000 requests per hour; successful responses carry `X-RateLimit-*` headers. Errors share one shape: `{\"error\": {\"code\", \"message\", \"details\"?}}`.\n\nHuman-readable reference: https://videotestimonials.video/docs/api","termsOfService":"https://videotestimonials.video/terms","contact":{"name":"VideoTestimonials support","email":"support@videotestimonials.video","url":"https://videotestimonials.video/docs/api"}},"externalDocs":{"description":"API reference","url":"https://videotestimonials.video/docs/api"},"servers":[{"url":"https://app.videotestimonials.video/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Testimonials","description":"Read, create, moderate and delete testimonials."},{"name":"Batch","description":"Moderate or delete up to 100 testimonials in one request."},{"name":"Spaces","description":"A space groups one brand's collection forms, testimonials and Wall of Love."}],"paths":{"/testimonials":{"get":{"operationId":"listTestimonials","tags":["Testimonials"],"summary":"List testimonials","description":"Testimonials across every space the account owns, newest first unless `sort_by`/`sort_order` say otherwise.","security":[{"bearerAuth":["read"]}],"parameters":[{"name":"space_id","in":"query","required":false,"description":"Only testimonials in this space.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"name":"status","in":"query","required":false,"description":"Only testimonials with this moderation status.","schema":{"type":"string","enum":["pending","approved","rejected"]}},{"name":"type","in":"query","required":false,"description":"Only text or only video testimonials.","schema":{"type":"string","enum":["text","video"]}},{"name":"rating","in":"query","required":false,"description":"Only testimonials with exactly this star rating.","schema":{"type":"integer","minimum":1,"maximum":5}},{"name":"search","in":"query","required":false,"description":"Case-insensitive substring match on `text_content`.","schema":{"type":"string"}},{"name":"date_from","in":"query","required":false,"description":"Only testimonials created at or after this time. ISO 8601 in UTC with a `Z` suffix, e.g. `2026-01-01T00:00:00Z`.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},{"name":"date_to","in":"query","required":false,"description":"Only testimonials created at or before this time. ISO 8601 in UTC with a `Z` suffix.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},{"name":"limit","in":"query","required":false,"description":"Number of items to return.","schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"description":"Number of items to skip, for paging.","schema":{"default":0,"type":"integer","minimum":0}},{"name":"sort_by","in":"query","required":false,"description":"Column to sort by. Defaults to `created_at`.","schema":{"type":"string","enum":["created_at","updated_at","rating","shares"]}},{"name":"sort_order","in":"query","required":false,"description":"Sort direction.","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"A page of testimonials.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Testimonial"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"example":{"data":[{"id":"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","type":"text","status":"approved","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","submitter_role":"Head of Marketing","submitter_avatar_url":null,"text_content":"We collected twelve video testimonials in our first week.","video_url":null,"video_thumbnail_url":null,"rating":5,"created_at":"2026-10-01T09:30:00.123456+00:00"}],"pagination":{"total":1,"limit":50,"offset":0,"has_more":false}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl \"https://app.videotestimonials.video/api/v1/testimonials?status=approved&limit=10\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\""}]},"post":{"operationId":"createTestimonial","tags":["Testimonials"],"summary":"Create a testimonial","description":"Adds a testimonial to one of the account's spaces and fires the `testimonial.created` webhook. For a `video` testimonial with a `video_url`, the request also transcribes the video before it responds; on success the transcript is saved to `ai_transcript` and `text_content`. The response is the row as inserted, before transcription.","security":[{"bearerAuth":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestimonialCreate"},"example":{"space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","type":"text","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","text_content":"We collected twelve video testimonials in our first week.","rating":5,"status":"approved"}}}},"responses":{"201":{"description":"The created testimonial.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Testimonial"}}},"example":{"data":{"id":"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","type":"text","status":"approved","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","submitter_role":"Head of Marketing","submitter_avatar_url":null,"text_content":"We collected twelve video testimonials in our first week.","video_url":null,"video_thumbnail_url":null,"rating":5,"created_at":"2026-10-01T09:30:00.123456+00:00"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"`space_id` is not a space this account owns.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"SPACE_NOT_FOUND":{"value":{"error":{"code":"SPACE_NOT_FOUND","message":"Space not found or you do not have access to it"}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"https://app.videotestimonials.video/api/v1/testimonials\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"space_id\":\"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b\",\"type\":\"text\",\"submitter_name\":\"Jane Doe\",\"submitter_email\":\"jane@example.com\",\"submitter_company\":\"Example Co\",\"text_content\":\"We collected twelve video testimonials in our first week.\",\"rating\":5,\"status\":\"approved\"}'"}]}},"/testimonials/{id}":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"operationId":"getTestimonial","tags":["Testimonials"],"summary":"Get a testimonial","security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"The testimonial.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Testimonial"}}},"example":{"data":{"id":"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","type":"text","status":"approved","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","submitter_role":"Head of Marketing","submitter_avatar_url":null,"text_content":"We collected twelve video testimonials in our first week.","video_url":null,"video_thumbnail_url":null,"rating":5,"created_at":"2026-10-01T09:30:00.123456+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No testimonial with that id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"TESTIMONIAL_NOT_FOUND":{"value":{"error":{"code":"TESTIMONIAL_NOT_FOUND","message":"Testimonial not found or you do not have access to it"}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl \"https://app.videotestimonials.video/api/v1/testimonials/c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\""}]},"patch":{"operationId":"updateTestimonial","tags":["Testimonials"],"summary":"Update a testimonial","description":"Changes status, text, rating, company or role. A status change to `approved` or `rejected` fires `testimonial.approved` or `testimonial.rejected`.","security":[{"bearerAuth":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestimonialUpdate"},"example":{"status":"approved"}}}},"responses":{"200":{"description":"The updated testimonial.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Testimonial"}}},"example":{"data":{"id":"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","type":"text","status":"approved","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","submitter_role":"Head of Marketing","submitter_avatar_url":null,"text_content":"We collected twelve video testimonials in our first week.","video_url":null,"video_thumbnail_url":null,"rating":5,"created_at":"2026-10-01T09:30:00.123456+00:00"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No testimonial with that id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"TESTIMONIAL_NOT_FOUND":{"value":{"error":{"code":"TESTIMONIAL_NOT_FOUND","message":"Testimonial not found or you do not have access to it"}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X PATCH \"https://app.videotestimonials.video/api/v1/testimonials/c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"status\":\"approved\"}'"}]},"delete":{"operationId":"deleteTestimonial","tags":["Testimonials"],"summary":"Delete a testimonial","description":"Deletes the testimonial, fires `testimonial.deleted`, and removes its uploaded avatar, video and thumbnail files from storage.","security":[{"bearerAuth":["delete"]}],"responses":{"204":{"description":"Deleted. No body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No testimonial with that id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"TESTIMONIAL_NOT_FOUND":{"value":{"error":{"code":"TESTIMONIAL_NOT_FOUND","message":"Testimonial not found or you do not have access to it"}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X DELETE \"https://app.videotestimonials.video/api/v1/testimonials/c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\""}]}},"/testimonials/batch/update":{"post":{"operationId":"batchUpdateTestimonials","tags":["Batch"],"summary":"Set the status of up to 100 testimonials","description":"Sets one status on every listed testimonial the account owns. Setting `approved` or `rejected` fires the matching webhook once per testimonial.","security":[{"bearerAuth":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestimonialBatchUpdate"},"example":{"testimonial_ids":["c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","d2e3f4a5-6b7c-4d8e-8f9a-0b1c2d3e4f5a"],"status":"approved"}}}},"responses":{"200":{"description":"The updated testimonials and how many changed.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","updated"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Testimonial"}},"updated":{"type":"integer"}}},"example":{"data":[{"id":"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","type":"text","status":"approved","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","submitter_role":"Head of Marketing","submitter_avatar_url":null,"text_content":"We collected twelve video testimonials in our first week.","video_url":null,"video_thumbnail_url":null,"rating":5,"created_at":"2026-10-01T09:30:00.123456+00:00"}],"updated":1}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"https://app.videotestimonials.video/api/v1/testimonials/batch/update\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"testimonial_ids\":[\"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d\",\"d2e3f4a5-6b7c-4d8e-8f9a-0b1c2d3e4f5a\"],\"status\":\"approved\"}'"}]}},"/testimonials/batch/delete":{"post":{"operationId":"batchDeleteTestimonials","tags":["Batch"],"summary":"Delete up to 100 testimonials","description":"Deletes every listed testimonial the account owns and fires `testimonial.deleted` once per testimonial. Unlike the single delete, uploaded files are not removed from storage.","security":[{"bearerAuth":["delete"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestimonialBatchDelete"},"example":{"testimonial_ids":["c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","d2e3f4a5-6b7c-4d8e-8f9a-0b1c2d3e4f5a"]}}}},"responses":{"200":{"description":"How many testimonials were deleted.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer"}}},"example":{"deleted":2}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"https://app.videotestimonials.video/api/v1/testimonials/batch/delete\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"testimonial_ids\":[\"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d\",\"d2e3f4a5-6b7c-4d8e-8f9a-0b1c2d3e4f5a\"]}'"}]}},"/spaces":{"get":{"operationId":"listSpaces","tags":["Spaces"],"summary":"List spaces","description":"Spaces the account owns, newest first unless `sort_by`/`sort_order` say otherwise.","security":[{"bearerAuth":["read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Number of items to return.","schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"description":"Number of items to skip, for paging.","schema":{"default":0,"type":"integer","minimum":0}},{"name":"sort_by","in":"query","required":false,"description":"Column to sort by. Defaults to `created_at`.","schema":{"type":"string","enum":["created_at","updated_at","rating","shares"]}},{"name":"sort_order","in":"query","required":false,"description":"Sort direction.","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"A page of spaces.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Space"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"example":{"data":[{"id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","name":"Example Co","slug":"example-co","description":"Tell us how Example Co helped you.","logo_url":null,"primary_color":"#7C3AED","custom_questions":["What problem did we solve for you?","What result did you get?"],"created_at":"2026-09-15T12:00:00.000000+00:00"}],"pagination":{"total":1,"limit":50,"offset":0,"has_more":false}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl \"https://app.videotestimonials.video/api/v1/spaces\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\""}]},"post":{"operationId":"createSpace","tags":["Spaces"],"summary":"Create a space","security":[{"bearerAuth":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceCreate"},"example":{"name":"Example Co","primary_color":"#7C3AED"}}}},"responses":{"201":{"description":"The created space.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Space"}}},"example":{"data":{"id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","name":"Example Co","slug":"example-co","description":"Tell us how Example Co helped you.","logo_url":null,"primary_color":"#7C3AED","custom_questions":["What problem did we solve for you?","What result did you get?"],"created_at":"2026-09-15T12:00:00.000000+00:00"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"https://app.videotestimonials.video/api/v1/spaces\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Example Co\",\"primary_color\":\"#7C3AED\"}'"}]}},"/spaces/{id}":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"operationId":"getSpace","tags":["Spaces"],"summary":"Get a space","security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"The space.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Space"}}},"example":{"data":{"id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","name":"Example Co","slug":"example-co","description":"Tell us how Example Co helped you.","logo_url":null,"primary_color":"#7C3AED","custom_questions":["What problem did we solve for you?","What result did you get?"],"created_at":"2026-09-15T12:00:00.000000+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No space with that id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"SPACE_NOT_FOUND":{"value":{"error":{"code":"SPACE_NOT_FOUND","message":"Space not found or you do not have access to it"}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl \"https://app.videotestimonials.video/api/v1/spaces/8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\""}]},"patch":{"operationId":"updateSpace","tags":["Spaces"],"summary":"Update a space","security":[{"bearerAuth":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceUpdate"},"example":{"name":"Example Co — Customers"}}}},"responses":{"200":{"description":"The updated space.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Space"}}},"example":{"data":{"id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","name":"Example Co","slug":"example-co","description":"Tell us how Example Co helped you.","logo_url":null,"primary_color":"#7C3AED","custom_questions":["What problem did we solve for you?","What result did you get?"],"created_at":"2026-09-15T12:00:00.000000+00:00"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No space with that id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"SPACE_NOT_FOUND":{"value":{"error":{"code":"SPACE_NOT_FOUND","message":"Space not found or you do not have access to it"}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X PATCH \"https://app.videotestimonials.video/api/v1/spaces/8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Example Co — Customers\"}'"}]},"delete":{"operationId":"deleteSpace","tags":["Spaces"],"summary":"Delete a space","description":"Deletes the space if the account owns it. An id that matches no space of this account also returns 204.","security":[{"bearerAuth":["delete"]}],"responses":{"204":{"description":"Deleted, or nothing matched. No body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}},"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X DELETE \"https://app.videotestimonials.video/api/v1/spaces/8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b\" \\\n  -H \"Authorization: Bearer $VT_API_KEY\""}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_<64 hex characters>","description":"Create a key in the dashboard under Settings → API Keys. The full key is shown once. Send it as `Authorization: Bearer sk_live_…` (the `Bearer ` prefix is optional). Each key carries scopes — `read`, `write`, `delete` — and acts for the account that created it."}},"headers":{"X-RateLimit-Limit":{"description":"Requests allowed per hour for this account.","schema":{"type":"string","example":"1000"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"string","example":"999"}},"X-RateLimit-Reset":{"description":"When the current window ends, as a Unix timestamp in milliseconds.","schema":{"type":"string","example":"1791462600000"}}},"parameters":{"id":{"name":"id","in":"path","required":true,"description":"Resource id (UUID).","schema":{"type":"string","format":"uuid"}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["UNAUTHORIZED","INVALID_API_KEY","API_KEY_DISABLED","API_KEY_EXPIRED","INSUFFICIENT_SCOPE","RATE_LIMIT_EXCEEDED","VALIDATION_ERROR","TESTIMONIAL_NOT_FOUND","SPACE_NOT_FOUND","INVALID_ENDPOINT","INTERNAL_ERROR"],"x-enumDescriptions":{"UNAUTHORIZED":"No `Authorization` header was sent (401).","INVALID_API_KEY":"The key is not `sk_live_…`/`sk_test_…` shaped, or no key with that value exists (401).","API_KEY_DISABLED":"The key was switched off in the dashboard (403).","API_KEY_EXPIRED":"The key is past its expiry date (403).","INSUFFICIENT_SCOPE":"The key lacks the scope this operation needs: `read`, `write` or `delete` (403).","RATE_LIMIT_EXCEEDED":"More than 1,000 requests in the current hour (429).","VALIDATION_ERROR":"A query parameter or body field failed validation (400).","TESTIMONIAL_NOT_FOUND":"No testimonial with that id belongs to this account (404).","SPACE_NOT_FOUND":"No space with that id belongs to this account (404).","INVALID_ENDPOINT":"The batch operation is neither `update` nor `delete` (404).","INTERNAL_ERROR":"Anything else, including a request body that is not valid JSON (500)."}},"message":{"type":"string","description":"Human-readable explanation."},"details":{"description":"Present on `UNAUTHORIZED` (`{\"header\": \"Authorization: Bearer sk_live_...\"}`) and `RATE_LIMIT_EXCEEDED` (`{\"limit\": number, \"reset\": string}`). `VALIDATION_ERROR` responses do not say which field failed."}}}}},"Pagination":{"type":"object","required":["total","limit","offset","has_more"],"properties":{"total":{"type":"integer","description":"Items matching the filters, across all pages."},"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean","description":"True when `offset + limit < total`."}}},"Testimonial":{"type":"object","description":"A testimonial as stored. Responses return the whole row, so fields beyond those listed here (for example AI analysis fields) can appear; treat unknown fields as optional.","additionalProperties":true,"required":["id","space_id","type","status","submitter_name","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"space_id":{"type":"string","format":"uuid"},"user_id":{"type":["string","null"],"format":"uuid","description":"Account that owns the testimonial."},"type":{"type":"string","enum":["text","video"]},"status":{"type":"string","description":"Moderation status. The API filters and writes `pending`, `approved` and `rejected`."},"submitter_name":{"type":"string"},"submitter_email":{"type":["string","null"]},"submitter_company":{"type":["string","null"]},"submitter_role":{"type":["string","null"]},"submitter_avatar_url":{"type":["string","null"]},"text_content":{"type":["string","null"]},"video_url":{"type":["string","null"]},"video_thumbnail_url":{"type":["string","null"]},"rating":{"type":["integer","null"],"minimum":1,"maximum":5},"ai_transcript":{"type":["string","null"],"description":"Transcript of a video testimonial, once transcribed."},"created_at":{"type":"string","format":"date-time"}},"example":{"id":"c7d1a2b3-5e6f-4a8b-9c0d-1e2f3a4b5c6d","space_id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","type":"text","status":"approved","submitter_name":"Jane Doe","submitter_email":"jane@example.com","submitter_company":"Example Co","submitter_role":"Head of Marketing","submitter_avatar_url":null,"text_content":"We collected twelve video testimonials in our first week.","video_url":null,"video_thumbnail_url":null,"rating":5,"created_at":"2026-10-01T09:30:00.123456+00:00"}},"Space":{"type":"object","description":"A space groups one brand's collection forms, testimonials and Wall of Love. Responses return the whole row, so fields beyond those listed here (branding, domain and wall settings) can appear.","additionalProperties":true,"required":["id","name","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid","description":"Account that owns the space."},"name":{"type":"string"},"slug":{"type":["string","null"],"description":"Used in the public collection and wall URLs."},"description":{"type":["string","null"]},"logo_url":{"type":["string","null"]},"primary_color":{"type":["string","null"]},"custom_questions":{"type":["array","null"]},"created_at":{"type":"string","format":"date-time"}},"example":{"id":"8b3e2f9a-4c1d-4e5f-9a7b-2c3d4e5f6a7b","user_id":"1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b","name":"Example Co","slug":"example-co","description":"Tell us how Example Co helped you.","logo_url":null,"primary_color":"#7C3AED","custom_questions":["What problem did we solve for you?","What result did you get?"],"created_at":"2026-09-15T12:00:00.000000+00:00"}},"TestimonialCreate":{"type":"object","properties":{"space_id":{"description":"Space to add the testimonial to. Must belong to the account that owns the API key.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"type":{"description":"`text` or `video`.","type":"string","enum":["text","video"]},"submitter_name":{"description":"Name of the person giving the testimonial.","type":"string","minLength":1,"maxLength":100},"submitter_email":{"description":"Email of the person giving the testimonial.","type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"submitter_company":{"description":"Their company.","type":"string","maxLength":100},"submitter_role":{"description":"Their job title or role.","type":"string","maxLength":100},"submitter_avatar_url":{"description":"URL of their photo.","type":"string","format":"uri"},"text_content":{"description":"The testimonial text. For a video testimonial this is replaced by the transcript once transcription succeeds.","type":"string"},"video_url":{"description":"Publicly reachable URL of the video file. When `type` is `video`, the API downloads it and transcribes it before responding.","type":"string","format":"uri"},"video_thumbnail_url":{"description":"URL of a thumbnail image for the video.","type":"string","format":"uri"},"rating":{"description":"Star rating.","type":"integer","minimum":1,"maximum":5},"status":{"description":"Moderation status. Embed widgets only show `approved` testimonials.","default":"pending","type":"string","enum":["pending","approved","rejected"]}},"required":["space_id","type","submitter_name","submitter_email"]},"TestimonialUpdate":{"type":"object","properties":{"status":{"description":"New moderation status. Changing it to `approved` or `rejected` fires the matching webhook.","type":"string","enum":["pending","approved","rejected"]},"text_content":{"description":"Replacement testimonial text.","type":"string"},"rating":{"description":"Star rating.","type":"integer","minimum":1,"maximum":5},"submitter_company":{"description":"Their company.","type":"string","maxLength":100},"submitter_role":{"description":"Their job title or role.","type":"string","maxLength":100}},"minProperties":1,"description":"Send at least one of these fields. Fields not listed are ignored."},"TestimonialBatchUpdate":{"type":"object","properties":{"testimonial_ids":{"description":"Testimonials to update. Ids that do not exist or belong to another account are skipped.","minItems":1,"maxItems":100,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"status":{"description":"Status to set on every listed testimonial.","type":"string","enum":["pending","approved","rejected"]}},"required":["testimonial_ids","status"]},"TestimonialBatchDelete":{"type":"object","properties":{"testimonial_ids":{"description":"Testimonials to delete. Ids that do not exist or belong to another account are skipped.","minItems":1,"maxItems":100,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}},"required":["testimonial_ids"]},"SpaceCreate":{"type":"object","properties":{"name":{"description":"Space name, shown on its collection page.","type":"string","minLength":1,"maxLength":100},"description":{"description":"Short description of the space.","type":"string","maxLength":500},"logo_url":{"description":"URL of the space logo.","type":"string","format":"uri"},"primary_color":{"description":"Brand colour as a 6-digit hex value, e.g. `#7C3AED`.","type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"custom_questions":{"description":"Question strings stored on the space. Collection forms take their questions from the form builder, not from this field.","type":"array","items":{"type":"string"}}},"required":["name"]},"SpaceUpdate":{"type":"object","properties":{"name":{"description":"Space name, shown on its collection page.","type":"string","minLength":1,"maxLength":100},"description":{"description":"Short description of the space.","type":"string","maxLength":500},"logo_url":{"description":"URL of the space logo.","type":"string","format":"uri"},"primary_color":{"description":"Brand colour as a 6-digit hex value, e.g. `#7C3AED`.","type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"custom_questions":{"description":"Question strings stored on the space. Collection forms take their questions from the form builder, not from this field.","type":"array","items":{"type":"string"}}},"minProperties":1,"description":"Send at least one of these fields. Fields not listed are ignored."}},"responses":{"Unauthorized":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"UNAUTHORIZED":{"value":{"error":{"code":"UNAUTHORIZED","message":"Missing API key. Include your API key in the Authorization header.","details":{"header":"Authorization: Bearer sk_live_..."}}}},"INVALID_API_KEY":{"value":{"error":{"code":"INVALID_API_KEY","message":"Invalid API key. Please check your key and try again."}}}}}}},"Forbidden":{"description":"The key is disabled, expired, or lacks the scope this operation needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"INSUFFICIENT_SCOPE":{"value":{"error":{"code":"INSUFFICIENT_SCOPE","message":"This API key does not have write permissions"}}},"API_KEY_DISABLED":{"value":{"error":{"code":"API_KEY_DISABLED","message":"This API key has been disabled. Please generate a new key."}}},"API_KEY_EXPIRED":{"value":{"error":{"code":"API_KEY_EXPIRED","message":"This API key has expired. Please generate a new key."}}}}}}},"RateLimited":{"description":"More than 1,000 requests in the current hour.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"RATE_LIMIT_EXCEEDED":{"value":{"error":{"code":"RATE_LIMIT_EXCEEDED","message":"Too many requests. Please try again later.","details":{"limit":1000,"reset":"1791462600000"}}}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"ValidationError":{"description":"A query parameter or body field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"VALIDATION_ERROR":{"value":{"error":{"code":"VALIDATION_ERROR","message":"Invalid request body"}}}}}}},"InternalError":{"description":"Unexpected failure, or a request body that is not valid JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"INTERNAL_ERROR":{"value":{"error":{"code":"INTERNAL_ERROR","message":"An error occurred while fetching testimonials"}}}}}}}}}}