meme-backend / docs /API_REFERENCE.md
shaileshrv1432's picture
Upload 64 files
d70a48e verified
|
Raw
History Blame Contribute Delete
9.39 kB
# API Reference
Base URL (production): `https://shaileshrv1432-meme-backend.hf.space`
Local: `http://localhost:8000`
Interactive docs are served live by the running app:
- **RapiDoc** β€” `/docs`
- **ReDoc** β€” `/redoc`
## Conventions
- **Auth**: endpoints marked πŸ”’ require a header `Authorization: Bearer <access_token>`.
- **Admin**: endpoints marked πŸ›‘ require header `X-Admin-Secret: <ADMIN_SECRET>` and return `404` when `APP_ENV=production`.
- **Body type**: most write endpoints take `application/x-www-form-urlencoded` (`Form(...)`). A few take JSON (`Body(...)`) β€” noted per endpoint.
- **Tokens**: `access_token` (short-lived, `ACCESS_TTL_SECONDS`) + `refresh_token` (long-lived, `REFRESH_TTL_SECONDS`). Refresh via `POST /auth/refresh`.
---
## Auth β€” `/auth`
### `POST /auth/request-otp`
Send an OTP to a phone number (creates the user if new).
- Form: `phone` (E.164, e.g. `+9172048...`)
- 200: `{ "message": "OTP sent" }`
- 502: SMS provider send failed (invalid key / no wallet balance / KYC incomplete). With `OTP_DEBUG=true` the 502 detail contains the raw provider error.
- Note: if `FAST2SMS_API_KEY` is unset, no SMS is sent β€” the OTP is printed to the server logs (`[DEV SMS] to=… otp=…`) so login still works in dev.
### `GET /auth/sms-check` πŸ›‘
Diagnose OTP/SMS delivery without a real login. Admin secret via header `X-Admin-Secret` **or** `?secret=` (browser-friendly).
- Query: `to` (optional 10-digit number β€” if given, performs a **real** test send)
- 200: `{ fast2sms_key_present, key_prefix, mode, verdict, provider_response? | provider_error?, hint }`
- `verdict`: `no_provider` (key unset) Β· `configured_not_tested` (no `to`) Β· `ok` Β· `send_failed`
### `POST /auth/verify-otp`
Verify an OTP and receive tokens.
- Form: `phone`, `otp`
- 200: `{ access_token, refresh_token, user: {...} }`
- 400: no user / no OTP / expired / invalid
- Guest: if `GUEST_MODE_ENABLED=true` and `phone` == `GUEST_PHONE_NUMBER` with `otp` == `GUEST_OTP_CODE`, returns a guest session (`account_type: "guest"`).
### `POST /auth/set-pin`
Set a login PIN for a phone user.
- Form: `phone`, `pin` (4–6 digits)
- 200: `{ "message": "PIN set" }`
- 422: PIN not 4–6 digits
### `POST /auth/login-pin`
Login with phone + PIN.
- Form: `phone`, `pin`
- 200: `{ access_token, refresh_token }`
- 401: invalid PIN Β· 400: no user / PIN not set
### `POST /auth/refresh`
Exchange a refresh token for a fresh access token.
- Form: `refresh_token`
- 200: `{ access_token }` Β· 401: invalid/expired
### `POST /auth/google`
Verify a Google ID token and issue app tokens.
- Form: `id_token` (Google ID token from the app)
- 200: `{ access_token, refresh_token, user: {...} }`
- 503: `GOOGLE_WEB_CLIENT_ID` not set on the server Β· 401: invalid token
- Users are keyed internally by `google:<sub>`.
### `GET /auth/me` πŸ”’
Current user.
- 200: `{ id, phone_e164, name, email, avatar_url, created_at, is_active }`
### `PATCH /auth/update-profile` πŸ”’
Update profile fields (form-encoded).
- Form (all optional): `name`, `email`, `avatar_url`
- 200: updated user object
### `DELETE /auth/delete-account` πŸ”’
Soft-delete (deactivate) the current account.
- Form: `confirm` (bool, must be true)
- 200: `{ "message": "Account deactivated" }`
### `POST /auth/debug-token` *(dev only)*
Decode a JWT without verifying signature. `404` in production.
---
## Memes β€” `/`
### `POST /upload` πŸ”’
Upload an image; stores it and returns initial GIF suggestions.
- Multipart: `image` (file), `mood` (optional)
- 200: `{ status, uuid, object_key, url, mood, ...suggestions }`
### `POST /suggest` πŸ”’
Re-run suggestions for an already-uploaded image.
- Form: `image_object_key`, `mood` (optional)
- 200: `{ status, object_key, mood, ...suggestions }` Β· 404: key not found
### `POST /compose` πŸ”’
Compose a meme from form fields (single overlay).
- Form: `image_object_key`, `gif_url` | `gif_object_key`, `x`, `y`, `width`, … (overlay placement)
### `POST /compose/layout?output_format=gif|png|mp4` πŸ”’
Compose from a full JSON layout (floating images **and text** over a background). This is what the app's editor uses.
- JSON body: `image_dimensions` =
```jsonc
{
"bgImage": { "source": "<object_key|url>", "width": 0, "height": 0, "applyCoverBlurAndContainImageFilter": false },
"floatingImages": [ { "file_url": "...", "width": 200, "relativeX": 0, "relativeY": 0, "rotation": 0, "z": 0 } ],
"textOverlays": [ { "text": "LOL", "fontSize": 32, "color": "#FFFFFF", "strokeColor": "#000000",
"width": 240, "height": 60, "relativeX": 0, "relativeY": 0, "rotation": 0, "z": 1 } ]
}
```
- Query/body: `output_format` (default `gif`)
- 200: `{ object_key, url, ... }`
- **Layering**: every overlay (image or text) may carry a `z` (integer). All overlays are composited in ascending `z`, so higher `z` = on top. Omitting `z` falls back to input order (images first, then text) β€” fully backward compatible.
- **Rotation**: `rotation` (degrees, clockwise) rotates an overlay about its centre; `relativeX/Y` stay the un-rotated box top-left. Defaults to `0`.
- **Text**: rendered server-side (Pillow) as bold, stroked meme text; `color`/`strokeColor` are hex, `width` enables word-wrap, `width`+`height` define the box the text is centred in.
- Tip: pass image overlay `width` only β€” the backend preserves the source aspect ratio (avoids stretched GIFs).
### `GET /memes?limit&offset` πŸ”’
List the current user's generated memes (latest first).
- 200: `{ items: [{ id, object_key, content_type, created_at, presigned_url, permanent_url }], count, offset, limit }`
### `GET /memes/presign?object_key=…` πŸ”’
Get a 10-minute presigned URL for one owned meme.
### `GET /memes/{object_key}` πŸ”’
Stream the meme bytes through the API (permanent proxy URL, cached 1 year).
---
## Media β€” `/media`
### `POST /media/url` πŸ”’
Presign any media object (JSON body).
- Body: `object_key`, `expires_seconds` (default 600)
- 200: `{ object_key, url, expires_seconds }`
### `POST /media/permanent-url` πŸ”’
Get the permanent proxy URL for an owned media object.
- Body: `object_key`
- 200: `{ object_key, permanent_url, type: "proxy", expires: "never" }`
---
## Profile β€” `/profile`
### `GET /profile` πŸ”’
Current user's profile (from Postgres).
### `PUT /profile` πŸ”’
Update name/email/avatar (JSON body).
- Body (optional): `name`, `email`, `avatar_url`
- 200: `{ "message": "Profile updated" }`
---
## Subscriptions β€” `/subscriptions`
> Requires `RAZORPAY_KEY_ID` + `RAZORPAY_KEY_SECRET` on the server. Plans (paise/INR): `weekly` 5000 / 7d, `monthly` 14000 / 30d, `yearly` 80000 / 365d.
### `POST /subscriptions/order` πŸ”’
Create a Razorpay order.
- Form: `plan` (`weekly|monthly|yearly`)
- 200: `{ order_id, amount, currency, key_id, plan }`
- 400: unknown plan Β· 503: payments not configured / keys rejected (auth) Β· 502: order creation failed
- With `PAYMENTS_DEBUG=true`, the 502 detail contains the raw Razorpay error (for debugging only).
### `POST /subscriptions/verify` πŸ”’
Verify the payment signature, activate the plan, and record a `payments` row (best-effort).
- Form: `razorpay_order_id`, `razorpay_payment_id`, `razorpay_signature`, `plan`
- 200: `{ status: "active", plan, expires_at }`
- 400: verification failed
### `GET /subscriptions/status` πŸ”’
Current subscription (auto-expires past the end date).
- 200: `{ plan, status, active, expires_at, is_premium, usage: { daily_meme_limit, daily_memes_used, daily_memes_remaining, premium_only_formats } }`
### `GET /subscriptions/receipt` πŸ”’
Most recent payment, shaped for the receipt UI.
- 200: `{ id, plan, plan_label, amount, amount_display, currency, status, method, payment_id, order_id, paid_at, expires_at }`
- 404: no payment on record (client falls back to plan-derived data)
### `GET /subscriptions/payments` πŸ”’
Full payment/transaction history, newest first.
- 200: `{ payments: [ <receipt object>, … ] }` (empty list if none / table absent)
### `GET /subscriptions/receipt/{payment_id}.pdf` πŸ”’
Download a specific payment's receipt as a PDF (generated with Pillow). Scoped to the owner.
- 200: `application/pdf` (Content-Disposition attachment)
- 404: receipt not found / not owned
### `GET /subscriptions/config-check` πŸ›‘
Diagnose Razorpay config without a checkout. Header `X-Admin-Secret`.
- 200: `{ key_id_present, key_secret_present, key_mode, key_id_prefix, secret_length, had_whitespace_or_quotes, razorpay_lib_installed, verdict, probe_order_id?, probe_error?, hint }`
- `?probe=false` skips the live β‚Ή1 test order.
---
## Admin β€” `/admin` πŸ›‘ *(404 in production)*
| Method | Path | Purpose |
|---|---|---|
| POST | `/admin/seed-demo-user` | Create a demo user (phone, pin, otp, issue_tokens) |
| POST | `/admin/minio-diagnose` | Check object-storage config |
| POST | `/admin/test-sms` | Test the SMS provider |
| GET | `/admin/users?limit&offset&search` | List users |
| GET | `/admin/users/{id}` | Get one user |
| PUT | `/admin/users/{id}` | Update name/email/is_active |
| DELETE | `/admin/users/{id}` | Soft-delete (deactivate) |
| GET | `/admin/cleanup-guest-data` | Purge expired guest data |
---
## Health & docs
| Method | Path | Purpose |
|---|---|---|
| GET | `/health/deps` | Dependency/health check |
| GET | `/docs` | RapiDoc UI |
| GET | `/redoc` | ReDoc UI |