My Video Gift

API

Errors

Errors are JSON with a coarse error code and an HTTP status. Codes are intentionally coarse — precise internal detail stays server-side. Some responses add context fields (issues, photo_count, balance_cents, price_cents, index). All error responses are Cache-Control: no-store.

Shape

code
{ "error": "insufficient_credits", "balance_cents": 800, "price_cents": 2500 }

Status codes

HTTPerrorMeaning
400invalid_jsonBody was not valid JSON.
400invalid_requestA field failed validation; see issues.
400invalid_idempotency_keyMalformed Idempotency-Key header.
400consent_requiredconsent: true missing on render.
400photo_limitBatch would exceed 30 photos per gift.
400invalid_photo_urlA photo URL could not be fetched (blocked/failed/redirects).
400invalid_photo_dataInline base64 photo was empty or unreadable.
401unauthorizedMissing, malformed, unknown, or revoked key.
402insufficient_creditsBalance below the tier price; includes balance_cents, price_cents.
403test_key_cannot_renderTest key used to render; test keys are a free sandbox. Use a live key.
404not_foundUnknown gift, a gift another key owns, or the API is disabled.
409order_lockedGift is past the content stage; photos no longer accepted.
409already_deliveredFilm already rendered; read URLs from status.
409not_readyRender requested with no reservation or zero photos.
411length_requiredMissing Content-Length (chunked bodies are rejected).
413payload_too_largePhoto or request body over the size cap.
415unsupported_media_typeBytes were not a supported image (JPEG/PNG/WebP).
429rate_limitedRate limit exceeded; includes retryAfter and a Retry-After header.
502trigger_failedRender could not be started after the debit; charge auto-refunded.
503store_unavailableTransient storage failure; retry.
503unavailableRender backend not configured or a transient failure.

Refunds — pay per delivery

The one paid call is render, and you are charged for a delivered film, not an attempt. If a render ends held (the content gate needs more or better photos) or failed, the debit is automatically refunded to your prepaid balance and the gift re-opens so you can add photos and render again.

Refunds happen two ways, both automatic: lazily the next time you poll GET /v1/gifts/{id}, and by a reconciliation job that sweeps stranded charges if you never poll. A refund restores balance_cents and reverses lifetime spend; the status then shows refunded_cents and a status_detail of held_refunded or failed_refunded.

If the render could not even be started after the debit (502 trigger_failed), the charge is refunded before the response returns.

External billing (pay.sh)

Gifts billed through an external gateway (pay.sh / USDC) are not charged against internal credits, so a failed delivery is made good with a free re-render rather than an internal refund. See Payments.

Last updated 2026-07-11.