{"id":19463270,"url":"https://github.com/slipbey/slipyme-api","last_synced_at":"2026-04-05T08:33:35.449Z","repository":{"id":223346826,"uuid":"760066958","full_name":"SlipBey/slipyme-api","owner":"SlipBey","description":"Secure HTTPS REST API for Slipyme — handles contact forms, job applications, email subscriptions, and real-time social media stats with Discord notifications and JSON persistence.","archived":false,"fork":false,"pushed_at":"2025-11-04T08:26:25.000Z","size":106,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-04T10:17:23.091Z","etag":null,"topics":["bearer-auth","discord-bot","express","facebook-graph","https-server","instagram-api","json-storage","nodejs","rest-api","slipyme","social-media-api","typescript","youtube-api"],"latest_commit_sha":null,"homepage":"https://api.slipyme.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SlipBey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-19T18:11:07.000Z","updated_at":"2025-11-04T08:43:06.000Z","dependencies_parsed_at":"2024-02-19T20:04:13.773Z","dependency_job_id":"82746b92-faa9-4bc5-b561-a05719bee025","html_url":"https://github.com/SlipBey/slipyme-api","commit_stats":null,"previous_names":["slipbey/slipyme-api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SlipBey/slipyme-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlipBey%2Fslipyme-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlipBey%2Fslipyme-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlipBey%2Fslipyme-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlipBey%2Fslipyme-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SlipBey","download_url":"https://codeload.github.com/SlipBey/slipyme-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlipBey%2Fslipyme-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31430009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T08:13:15.228Z","status":"ssl_error","status_checked_at":"2026-04-05T08:13:11.839Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bearer-auth","discord-bot","express","facebook-graph","https-server","instagram-api","json-storage","nodejs","rest-api","slipyme","social-media-api","typescript","youtube-api"],"created_at":"2024-11-10T18:09:18.743Z","updated_at":"2026-04-05T08:33:35.427Z","avatar_url":"https://github.com/SlipBey.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Slipyme API (`api.slipyme.com`)\n\nHTTPS Express API — contact, job applications, email subscriptions, social stats/feeds **and Spotify music releases**.  \nSends structured **Discord embeds** and persists data in simple **JSON files**.\n\n\u003e **Stack:** Node.js • TypeScript • Express • HTTPS • Bearer Auth • discord.js • axios • dotenv • cors  \n\u003e **Social Integrations:** YouTube Data API v3, Instagram/Facebook Graph API, Spotify Web API\n\n---\n\n## ✨ Features\n\n- 🔒 **Bearer Token** required for all `/api` endpoints\n- 🌐 **HTTPS** server + **HTTP→HTTPS** redirect (ports 9128 / 8080)\n- 🗂️ **JSON file** storage in `jsons/` (no RDBMS)\n- ♻️ **Caching \u0026 Cron**: daily refresh for social stats/feeds\n- 🔔 **Discord** notifications via rich embeds\n- 🎵 **Spotify artist releases endpoint** (`/api/music/spotify`)\n- 🧰 Clean layering: Routes → Controllers → Repositories → Libs/Models\n\n---\n\n## 🧭 Table of Contents\n\n- [Architecture \u0026 Structure](#-architecture--structure) \n- [Installation](#-installation)\n- [Environment Variables](#-environment-variables)\n- [Running](#-running)\n- [API Reference](#-api-reference)\n- [Security Notes](#-security-notes)\n- [Logging \u0026 Rate Limiting](#-logging--rate-limiting)\n- [Docker / PM2](#-docker--pm2)\n- [Contributing \u0026 Roadmap](#-contributing--roadmap)\n- [License](#-license)\n\n---\n\n## 🏗️ Architecture \u0026 Structure\n\n```text\nsrc/\n  app.ts                 # App entry: HTTPS server, auth, HSTS, cron, router mount\n  routes/\n    SocialRoutes.ts      # GET /api/social/stats, GET /api/social/feeds\n    MailAddRoutes.ts     # POST /api/mail\n    JobApplicationRoutes.ts # POST /api/job\n    ContactRoutes.ts     # POST /api/contact\n    MusicRoutes.ts       # GET /api/music/spotify\n  controllers/\n    SocialController.ts\n    MailAddController.ts\n    JobApplicationController.ts\n    ContactController.ts\n    MusicController.ts\n  repositories/\n    SocialRepository.ts  # IG/YT fetch + JSON cache (social.json, feeds.json)\n    MailAddRepository.ts # jsons/mails.json + Discord embed\n    JobApplicationRepository.ts # jsons/applications.json + Discord embed\n    ContactRepository.ts # jsons/contact.json + Discord embed\n    MusicRepository.ts   # Spotify fetch + JSON cache (spotify.json)\n  models/\n    Socials.ts           # SocialSnapshot, MediaItem, IgStats\n    Mail.ts              # Mail\n    JobApplication.ts    # JobApplication, Job, Education\n    Contact.ts           # Contact\n    Spotify.ts           # Spotify releases typings (artist, albums, items)\n  middlewares/\n    loggerMiddleware.ts  # Append request logs to jsons/logs.json\n    rateLimitMiddleware.ts # In-memory helper (wire per-route)\n  libs/\n    config.ts            # ENV loader\n    validateModel.ts     # required field checks\n    fileHandler.ts       # append/read JSON utilities\n    date.ts              # date helpers\n    sendEmbed.ts         # Discord embed utility\n    social/\n      instagram.ts, youtube.ts, fbToken.ts, tokens.ts\n    music/\n      spotify.ts         # fetchSpotifyReleases + Spotify auth helper\n  cr/\n    certificate.crt      # TLS certificate\n    private.key          # TLS private key\njsons/                    # runtime data: social.json, feeds.json, mails.json, \n                          # applications.json, contact.json, logs.json, ig_tokens.json,\n                          # spotify.json\nstart.bat                 # Windows bootstrap\n```\n\n**Flow:** `Routes → Controllers → Repositories → (Files / External services)`  \nControllers validate payloads and call repos; repos persist JSON and notify Discord. Social repo fetches IG/YT and caches results; music repo fetches Spotify artist releases and caches them.\n\n---\n\n## ⚙️ Installation\n\nPrerequisites:\n- Node.js LTS\n- Valid TLS keypair at `src/cr/certificate.crt` and `src/cr/private.key`\n- `.env` file (see below)\n\nInstall:\n```bash\nnpm install\n```\n\nWindows helper:\n```bat\nstart.bat\n```\n\n\u003e `start.bat` loads `.env`, verifies TLS files, ensures ts-node, then starts the app.\n\n---\n\n## 🔐 Environment Variables\n\nCreate a `.env` from `.env.example`:\n\n```ini\n# Core\nAPI_KEY=changeme                       # Bearer Token for all /api routes\nLOG_LEVEL=info                         # debug|info|warn|error\nLOG_PRETTY=1                           # 1 to pretty-print logs\n\n# Discord\nBOT_TOKEN=your-discord-bot-token\n\n# YouTube\nYT_API_KEY=your-youtube-api-key\nYT_CHANNEL_ID=UCxxxxxxxxxxxxxxxx\n\n# Instagram / Facebook\nIG_USER_ID=1784xxxxxxxxxxxxxx\nIG_ACCESS_TOKEN=your-instagram-access-token\nFB_APP_ID=xxxxxxxx\nFB_APP_SECRET=xxxxxxxx\nSYSTEM_USER_TOKEN=prefer-stable-long-lived-token\nPAGE_ACCESS_TOKEN=optional-page-access-token\n\n# Spotify\nSPOTIFY_CLIENT_ID=your-spotify-client-id\nSPOTIFY_CLIENT_SECRET=your-spotify-client-secret\nSPOTIFY_ARTIST_ID=your-spotify-artist-id\n```\n\n\u003e **Ports (hardcoded):** HTTPS **9128**, HTTP redirect **8080**.  \n\u003e **TLS files:** `src/cr/certificate.crt`, `src/cr/private.key`.\n\n---\n\n## ▶️ Running\n\nDevelopment:\n```bash\nnpm run start\n# ts-node src/app.ts\n```\n\nProduction (example):\n```bash\nNODE_ENV=production npm run start\n```\n\nBase URL:\n```text\nHTTPS: https://\u003chost\u003e:9128\nAll routes live under /api\n```\n\n---\n\n## 📚 API Reference\n\n**Auth:** Include `Authorization: Bearer \u003cAPI_KEY\u003e` on every request. Otherwise: `401`.\n\n### GET `/api/social/stats`\n\nReturns IG followers/media count and YT subscribers/views (cached; auto-refreshed daily).\n\n```bash\ncurl -k -H \"Authorization: Bearer $API_KEY\"   \"https://localhost:9128/api/social/stats\"\n```\n\n**200 Example**\n```json\n{\n  \"instagram\": { \"followers\": 12345, \"mediaCount\": 678 },\n  \"youtube\":   { \"subs\": 54321, \"views\": 987654 },\n  \"updatedAt\": \"2024-01-01T10:00:00.000Z\"\n}\n```\n\n**401**\n```json\n{ \"status\": \"error\", \"message\": \"Unauthorized: Invalid token\" }\n```\n\n### GET `/api/social/feeds?igLimit=6\u0026ytMax=6\u0026ytChannelId=...`\n\nRecent IG posts and YT videos.\n\n```bash\ncurl -k -H \"Authorization: Bearer $API_KEY\"   \"https://localhost:9128/api/social/feeds?igLimit=6\u0026ytMax=6\"\n```\n\n**200 (success)**\n```json\n{\n  \"data\": {\n    \"instagram\": [\n      {\n        \"id\": \"123\",\n        \"media_type\": \"IMAGE\",\n        \"media_url\": \"https://...\",\n        \"permalink\": \"https://instagram.com/p/...\",\n        \"caption\": \"Post caption\",\n        \"timestamp\": \"2024-01-01T09:00:00.000Z\"\n      }\n    ],\n    \"youtube\": [\n      {\n        \"id\": \"abc123\",\n        \"title\": \"Video title\",\n        \"publishedAt\": \"2024-01-01T08:00:00.000Z\",\n        \"thumbnail\": \"https://i.ytimg.com/...\",\n        \"views\": 1000,\n        \"likes\": 50,\n        \"comments\": 10\n      }\n    ]\n  }\n}\n```\n\n**200 (fallback on upstream error)**\n```json\n{ \"data\": { \"instagram\": [], \"youtube\": [] } }\n```\n\n### GET `/api/music/spotify?limit=20`\n\nReturns recent Spotify releases (albums/singles) for the configured artist.\n\n- Reads `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`, `SPOTIFY_ARTIST_ID` from env\n- Fetches artist releases via Spotify Web API\n- Applies simple de-duplication on item IDs\n- Persists the latest snapshot into `jsons/spotify.json`\n- Uses a short cache window to avoid hammering Spotify on every request\n\n```bash\ncurl -k -H \"Authorization: Bearer $API_KEY\"   \"https://localhost:9128/api/music/spotify?limit=20\"\n```\n\n**200 Example**\n```json\n{\n  \"items\": [\n    {\n      \"id\": \"album_or_single_id\",\n      \"name\": \"Release name\",\n      \"type\": \"album\",\n      \"release_date\": \"2025-01-01\",\n      \"total_tracks\": 4,\n      \"external_urls\": { \"spotify\": \"https://open.spotify.com/album/...\" },\n      \"images\": [\n        { \"url\": \"https://i.scdn.co/image/...\", \"width\": 640, \"height\": 640 }\n      ]\n    }\n  ],\n  \"updatedAt\": \"2025-01-01T12:00:00.000Z\"\n}\n```\n\n**500 (upstream or config error)**\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Spotify fetch failed. Check credentials and artist id.\"\n}\n```\n\n### POST `/api/contact`\n\n```bash\ncurl -k -X POST \"https://localhost:9128/api/contact\"   -H \"Authorization: Bearer $API_KEY\"   -H \"Content-Type: application/json\"   -d '{\n    \"name\":\"Jane Doe\",\n    \"email\":\"jane@example.com\",\n    \"subject\":\"Partnership\",\n    \"message\":\"We would love to collaborate.\",\n    \"channel\":\"website\",\n    \"phone\":\"+1-555-555-5555\"\n  }'\n```\n\n**200**\n```json\n{ \"message\": \"İletişim bilgileri başarıyla gönderildi.\" }\n```\n\n**400 (missing field)**\n```json\n{ \"error\": \"Lütfen zorunlu alanları doldurun.\" }\n```\n\n### POST `/api/mail`\n\nSubscribe an email; persists and notifies Discord.\n\n```bash\ncurl -k -X POST \"https://localhost:9128/api/mail\"   -H \"Authorization: Bearer $API_KEY\"   -H \"Content-Type: application/json\"   -d '{ \"email\":\"test@example.com\" }'\n```\n\n### POST `/api/job`\n\nCreates a job application; appends to `jsons/applications.json` and sends a Discord embed.\n\n```bash\ncurl -k -X POST \"https://localhost:9128/api/job\"   -H \"Authorization: Bearer $API_KEY\"   -H \"Content-Type: application/json\"   -d '{\n    \"name\":\"John\",\n    \"email\":\"john@example.com\",\n    \"jobs\":[{ \"company\":\"X\", \"title\":\"Dev\", \"start\":\"2022-01-01\" }],\n    \"educations\":[{ \"school\":\"Y\", \"degree\":\"BS\", \"gradYear\":2020 }]\n  }'\n```\n\n\u003e **Note:** Actual response messages are in **Turkish** in the codebase.\n\n---\n\n## 🛡️ Security Notes\n\n- **Bearer Token** is mandatory; do not expose it on the client.\n- **HSTS** header and **HTTP→HTTPS** redirect are enabled.\n- Ensure proper **Discord channel permissions**.\n- **Do not commit TLS keys**; mount or inject via secrets in deployment.\n\n---\n\n## 📝 Logging \u0026 Rate Limiting\n\n- Each request is appended to `jsons/logs.json` via `loggerMiddleware`.\n- `rateLimitMiddleware` exists but must be **wired per-route**:\n  ```ts\n  router.post(\"/\", rateLimit(3, 300000), handler);\n  ```\n\n\u003e Currently only write-heavy routes (`/api/contact`, `/api/mail`, `/api/job`) use `rateLimitMiddleware`. Social and music routes rely on upstream quotas and internal caching.\n\n---\n\n## 🐳 Docker / PM2\n\n**Dockerfile** and **docker-compose.yml** are provided. Mount TLS files and `jsons/` as volumes.\n\n```bash\ndocker compose up -d --build\n```\n\n**PM2** (example):\n```bash\nnpm i -g pm2\npm2 start \"npm -- run start\" --name slipyme-api\npm2 save \u0026\u0026 pm2 startup\n```\n\n---\n\n## 🤝 Contributing \u0026 Roadmap\n\n**Contributing**\n- When adding a route, export `export default { name: \"/path\", router }` from the module; `src/app.ts` will auto-mount it.\n- For persistence, use `jsons/` via `fileHandler.ts`.\n- Wire `rateLimit()` on write-heavy routes (`/mail`, `/contact`, `/job`).\n\n**Roadmap**\n- Optional per-route rate limiting for social/music endpoints\n- Extended Spotify metadata shaping (e.g. track-level responses)\n\n---\n\n## 📜 License\n\n**GPL-3.0** © 2025 — Slipyme / SlipBey.  \nYou may use, modify, and distribute under the terms of the GPLv3 license.\nSee [`LICENSE`](./LICENSE) for details.\n\n---\n\n## 👨‍💻 Author\n\n**SlipBey**  \n[Discord](https://slip.slipyme.com/discord) • [LinkedIn](https://slip.slipyme.com/linkedin) • [Website](https://slip.slipyme.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslipbey%2Fslipyme-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslipbey%2Fslipyme-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslipbey%2Fslipyme-api/lists"}