{"openapi":"3.1.0","info":{"title":"Make Me Look","version":"1.0.0","description":"Restyle a photo of a person from a text prompt: same face, any style. One 1024px PNG, no account needed. Each generation costs 0.03 USD in USDC on Base, paid per request with x402 v2. Animate a photo of a person, or a paid generation, into a short looping GIF from a motion prompt, no account needed, for 0.15 USD. Asynchronous: the paid POST answers 202 with a job, and the result is fetched from its free status URL. The payment is settled only once the picture exists. See /llms.txt for an agent guide.","contact":{"name":"Make Me Look","email":"contact@xpfarmstudio.com","url":"https://makemelook.app/"},"x-guidance":"POST /x402/generations with {\"prompt\": \"a viking warrior\", \"image\": \"<base64 photo of a face>\"}. Without payment it answers 402 with x402 payment requirements; sign them and repeat the POST with the PAYMENT-SIGNATURE header. You get 202 and a status_url: GET it every 5 seconds until status is succeeded, then download result.image_url (a 1024px PNG). To animate it, POST /x402/gifs with {\"prompt\": \"waves hello\", \"generation_id\": \"<that id>\"} the same way (or \"image\" instead of the id). No account or API key. Failed generations are never charged. The full guide is /llms.txt."},"servers":[{"url":"https://makemelook.app"}],"tags":[{"name":"generations"},{"name":"gifs"},{"name":"public"}],"paths":{"/x402/generations":{"post":{"tags":["generations"],"operationId":"createPaidGeneration","summary":"Restyle a photo from a prompt, paid per generation with x402: no account or API key","x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.03"},"protocols":[{"x402":{}}]},"description":"Without a payment the answer is 402 with a PaymentRequired (body and base64 `PAYMENT-REQUIRED` header), before the body is looked at. Repeat with `PAYMENT-SIGNATURE` (x402 v2, exact, USDC): the payment is verified and reserved, and the answer is 202 with a job. It is settled once the picture exists; the settlement comes back as `PAYMENT-RESPONSE` on the status poll. Invalid input is 400 and never charged.","security":[],"parameters":[{"name":"PAYMENT-SIGNATURE","in":"header","required":false,"schema":{"type":"string"},"description":"Base64 x402 PaymentPayload (`X-PAYMENT` is accepted too)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationRequest"}}}},"responses":{"202":{"description":"Paid and queued. Poll `status_url`.","headers":{"Location":{"schema":{"type":"string"}},"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"400":{"description":"Invalid input or payment encoding (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required, or the payment was refused. Nothing was charged.","headers":{"PAYMENT-REQUIRED":{"schema":{"type":"string"},"description":"Base64 of the same PaymentRequired"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"413":{"description":"`image` is too large (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"`image` is not a PNG, JPEG or WebP (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"`payments_not_configured` or `facilitator_unavailable` (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["generations"],"operationId":"probePaidGeneration","summary":"The price: always 402 without a payment, for clients that only GET","security":[],"responses":{"402":{"description":"Payment required, or the payment was refused. Nothing was charged.","headers":{"PAYMENT-REQUIRED":{"schema":{"type":"string"},"description":"Base64 of the same PaymentRequired"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"405":{"description":"A paid request must be a POST","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/x402/generations/{id}":{"get":{"tags":["generations"],"operationId":"getPaidGeneration","summary":"Status and result of a paid generation. Free.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The job. `Retry-After` while it is still running.","headers":{"PAYMENT-RESPONSE":{"schema":{"type":"string"},"description":"Base64 x402 SettlementResponse, once settled"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"404":{"description":"No such generation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/x402/gifs":{"post":{"tags":["gifs"],"operationId":"createPaidGif","summary":"Animate a photo or a paid generation into a looping GIF, paid per GIF with x402","x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.15"},"protocols":[{"x402":{}}]},"description":"The same flow as POST /x402/generations, at its own price and with a 30-minute authorization window: a GIF usually takes about a minute and occasionally ten or more. Send `generation_id` (a succeeded paid generation) or `image`, not both. Poll `status_url`; the result is an image/gif.","security":[],"parameters":[{"name":"PAYMENT-SIGNATURE","in":"header","required":false,"schema":{"type":"string"},"description":"Base64 x402 PaymentPayload (`X-PAYMENT` is accepted too)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GifRequest"}}}},"responses":{"202":{"description":"Paid and queued. Poll `status_url`.","headers":{"Location":{"schema":{"type":"string"}},"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"400":{"description":"Invalid input or payment encoding (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required, or the payment was refused. Nothing was charged.","headers":{"PAYMENT-REQUIRED":{"schema":{"type":"string"},"description":"Base64 of the same PaymentRequired"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"404":{"description":"`generation_not_found` (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`generation_not_ready`: that generation has not succeeded (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`image` is too large (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"`image` is not a PNG, JPEG or WebP (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"`payments_not_configured`, `facilitator_unavailable` or `unavailable` (nothing charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["gifs"],"operationId":"probePaidGif","summary":"The price: always 402 without a payment, for clients that only GET","security":[],"responses":{"402":{"description":"Payment required, or the payment was refused. Nothing was charged.","headers":{"PAYMENT-REQUIRED":{"schema":{"type":"string"},"description":"Base64 of the same PaymentRequired"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"405":{"description":"A paid request must be a POST","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/x402/gifs/{id}":{"get":{"tags":["gifs"],"operationId":"getPaidGif","summary":"Status and result of a paid GIF. Free.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The job. `Retry-After` while it is still running.","headers":{"PAYMENT-RESPONSE":{"schema":{"type":"string"},"description":"Base64 x402 SettlementResponse, once settled"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"404":{"description":"No such GIF","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/llms.txt":{"get":{"tags":["public"],"summary":"Agent guide","security":[],"responses":{"200":{"description":"Text"}}}},"/health":{"get":{"tags":["public"],"summary":"Liveness check","security":[],"responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"GenerationRequest":{"type":"object","required":["prompt","image"],"properties":{"prompt":{"type":"string","maxLength":1000,"description":"What the person in the photo should become","example":"a viking warrior with a fur cloak"},"image":{"type":"string","description":"The reference photo as base64 or a data URL: PNG, JPEG or WebP, at most 4MB decoded. URLs are not accepted."}}},"GifRequest":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":1000,"description":"How the picture should move","example":"waves hello and laughs"},"generation_id":{"type":"string","format":"uuid","description":"A succeeded paid generation to animate. Send this or `image`."},"image":{"type":"string","description":"A photo of a person as base64 or a data URL: PNG, JPEG or WebP, at most 4MB. Square works best."}},"oneOf":[{"required":["generation_id"]},{"required":["image"]}]},"Generation":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","processing","succeeded","failed"]},"status_url":{"type":"string","description":"On the 202 only"},"prompt":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"result":{"type":"object","description":"Once succeeded","properties":{"image_url":{"type":"string","description":"A 1024x1024 PNG, or the GIF; the link lasts an hour, poll for a fresh one"},"expires_at":{"type":"string","format":"date-time"},"media_type":{"type":"string","enum":["image/png","image/gif"]}}},"error":{"$ref":"#/components/schemas/ErrorBody"},"payment":{"type":"object","properties":{"status":{"type":"string","enum":["authorized","settled","unconfirmed","not_charged"],"description":"authorized: verified, not yet charged. settled: charged, see transaction. unconfirmed: the picture was delivered but settlement did not answer. not_charged: the job failed."},"network":{"type":"string","example":"eip155:8453"},"amount":{"type":"string","description":"Atomic units (USDC has 6 decimals)","example":"30000"},"asset":{"type":"string"},"transaction":{"type":"string"},"payer":{"type":"string"}}}}},"ErrorBody":{"type":"object","properties":{"code":{"type":"string","example":"generation_failed"},"message":{"type":"string"}}},"Error":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorBody"}}},"PaymentRequired":{"type":"object","description":"x402 v2 PaymentRequired","required":["x402Version","resource","accepts"],"properties":{"x402Version":{"const":2},"error":{"type":"string"},"resource":{"type":"object","properties":{"url":{"type":"string"},"description":{"type":"string"},"mimeType":{"type":"string"},"serviceName":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"iconUrl":{"type":"string"}}},"accepts":{"type":"array","items":{"type":"object","properties":{"scheme":{"const":"exact"},"network":{"type":"string","example":"eip155:8453"},"amount":{"type":"string","description":"Atomic units (USDC has 6 decimals)","example":"30000"},"asset":{"type":"string","description":"USDC contract address"},"payTo":{"type":"string"},"maxTimeoutSeconds":{"type":"integer"},"extra":{"type":"object","description":"EIP-712 domain of the token: name, version"}}}},"extensions":{"type":"object","description":"Echo these in the PaymentPayload (bazaar)"}}}}}}