├── data ├── http-headers.java ├── servers.json └── endpoints.java ├── .gitignore ├── README.md └── openapi.yaml /data/http-headers.java: -------------------------------------------------------------------------------- 1 | public final class C11700b implements InterfaceC4884w { 2 | 3 | /* renamed from: a */ 4 | public final C9987b1 f36430a; 5 | 6 | /* renamed from: b */ 7 | public final String f36431b; 8 | 9 | /* renamed from: c */ 10 | public final C8711c f36432c; 11 | 12 | public C11700b(C9987b1 tokenManager, String correlationId, C8711c applicationConfig) { 13 | Intrinsics.checkNotNullParameter(tokenManager, "tokenManager"); 14 | Intrinsics.checkNotNullParameter(correlationId, "correlationId"); 15 | Intrinsics.checkNotNullParameter(applicationConfig, "applicationConfig"); 16 | this.f36430a = tokenManager; 17 | this.f36431b = correlationId; 18 | this.f36432c = applicationConfig; 19 | } 20 | 21 | @Override // p131dp.InterfaceC4884w 22 | public final C4867i0 intercept(InterfaceC4883v chain) { 23 | String m3924a; 24 | Intrinsics.checkNotNullParameter(chain, "chain"); 25 | C6593g c6593g = (C6593g) chain; 26 | C4861f0 c4861f0 = c6593g.f20252e; 27 | boolean m7549a = Intrinsics.m7549a(c4861f0.f14060c.m10756b("withoutAuthorization"), "true"); 28 | C4859e0 c4859e0 = new C4859e0(c4861f0); 29 | String property = System.getProperty("http.agent"); 30 | c4859e0.m10797b("User-Agent", "TGTG/24.2.1 " + property); 31 | c4859e0.m10797b("Content-Type", "application/json"); 32 | c4859e0.m10797b("X-Correlation-ID", this.f36431b); 33 | C8711c c8711c = this.f36432c; 34 | String string = c8711c.f27090a.getResources().getString(R.string.app_language); 35 | Intrinsics.checkNotNullExpressionValue(string, "getString(...)"); 36 | c4859e0.m10797b("Accept-Language", string); 37 | if (!m7549a && (m3924a = this.f36430a.m3924a()) != null) { 38 | c4859e0.m10797b("Authorization", m3924a); 39 | } 40 | C4882u c4882u = c4861f0.f14058a; 41 | if (!Intrinsics.m7549a(c4882u.f14176d, "meta.apptoogoodtogo.com")) { 42 | Server server = c8711c.f27092c; 43 | C4881t m10740f = c4882u.m10740f(); 44 | m10740f.m10748c(server.getDomain()); 45 | if (server.getPort() != null) { 46 | m10740f.m10746e(server.getPort().intValue()); 47 | } 48 | C4882u url = m10740f.m10750a(); 49 | Intrinsics.checkNotNullParameter(url, "url"); 50 | c4859e0.f14053a = url; 51 | } 52 | return c6593g.m8426b(new C4861f0(c4859e0)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /data/servers.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | { 4 | "name": "Prod (Nearest)", 5 | "domain": "apptoogoodtogo.com", 6 | "production": true 7 | }, 8 | { 9 | "name": "Prod (EU)", 10 | "domain": "euw1.apptoogoodtogo.com", 11 | "production": true 12 | }, 13 | { 14 | "name": "Prod (US)", 15 | "domain": "use1.apptoogoodtogo.com", 16 | "production": true 17 | }, 18 | { 19 | "name": "Staging (Nearest)", 20 | "domain": "backend-staging.apptoogoodtogo.com", 21 | "production": false 22 | }, 23 | { 24 | "name": "Staging (EU)", 25 | "domain": "backend-staging-euw1.apptoogoodtogo.com", 26 | "production": false 27 | }, 28 | { 29 | "name": "Staging (US)", 30 | "domain": "backend-staging-use1.apptoogoodtogo.com", 31 | "production": false 32 | }, 33 | { 34 | "name": "Gold (EU) (Requires VPN)", 35 | "domain": "gold-backend-internal.dev-euw1.tgtg.ninja", 36 | "production": false 37 | }, 38 | { 39 | "name": "Gold (US) (Requires VPN)", 40 | "domain": "gold-backend-internal.dev-use1.tgtg.ninja", 41 | "production": false 42 | }, 43 | { 44 | "name": "Test1 (EU)", 45 | "domain": "backend-test1.apptoogoodtogo.com", 46 | "production": false 47 | }, 48 | { 49 | "name": "Test1 (US)", 50 | "domain": "backend-test1-use1.apptoogoodtogo.com", 51 | "production": false 52 | }, 53 | { 54 | "name": "Test2 (EU)", 55 | "domain": "backend-test2.apptoogoodtogo.com", 56 | "production": false 57 | }, 58 | { 59 | "name": "Test2 (US)", 60 | "domain": "backend-test2-use1.apptoogoodtogo.com", 61 | "production": false 62 | }, 63 | { 64 | "name": "Test3 (EU)", 65 | "domain": "backend-test3.apptoogoodtogo.com", 66 | "production": false 67 | }, 68 | { 69 | "name": "Test3 (US)", 70 | "domain": "backend-test3-use1.apptoogoodtogo.com", 71 | "production": false 72 | }, 73 | { 74 | "name": "Test4 (EU)", 75 | "domain": "backend-test4.apptoogoodtogo.com", 76 | "production": false 77 | }, 78 | { 79 | "name": "Test4 (US)", 80 | "domain": "backend-test4-use1.apptoogoodtogo.com", 81 | "production": false 82 | }, 83 | { 84 | "name": "Test5 (EU)", 85 | "domain": "backend-test5.apptoogoodtogo.com", 86 | "production": false 87 | }, 88 | { 89 | "name": "Test5 (US)", 90 | "domain": "backend-test5-use1.apptoogoodtogo.com", 91 | "production": false 92 | }, 93 | { 94 | "name": "Test6 (EU)", 95 | "domain": "backend-test6.apptoogoodtogo.com", 96 | "production": false 97 | }, 98 | { 99 | "name": "Test6 (US)", 100 | "domain": "backend-test6-use1.apptoogoodtogo.com", 101 | "production": false 102 | }, 103 | { 104 | "name": "Test7 (EU)", 105 | "domain": "backend-test7.apptoogoodtogo.com", 106 | "production": false 107 | }, 108 | { 109 | "name": "Test7 (US)", 110 | "domain": "backend-test7-use1.apptoogoodtogo.com", 111 | "production": false 112 | }, 113 | { 114 | "name": "Test8 (EU)", 115 | "domain": "backend-test8.apptoogoodtogo.com", 116 | "production": false 117 | }, 118 | { 119 | "name": "Test8 (US)", 120 | "domain": "backend-test8-use1.apptoogoodtogo.com", 121 | "production": false 122 | }, 123 | { 124 | "name": "Test9 (EU)", 125 | "domain": "backend-test9.apptoogoodtogo.com", 126 | "production": false 127 | }, 128 | { 129 | "name": "Test9 (US)", 130 | "domain": "backend-test9-use1.apptoogoodtogo.com", 131 | "production": false 132 | } 133 | ] 134 | } 135 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/python,pycharm 2 | # Edit at https://www.gitignore.io/?templates=python,pycharm 3 | 4 | ### PyCharm ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff 9 | .idea/**/workspace.xml 10 | .idea/**/tasks.xml 11 | .idea/**/usage.statistics.xml 12 | .idea/**/dictionaries 13 | .idea/**/shelf 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/modules.xml 36 | # .idea/*.iml 37 | # .idea/modules 38 | # *.iml 39 | # *.ipr 40 | 41 | # CMake 42 | cmake-build-*/ 43 | 44 | # Mongo Explorer plugin 45 | .idea/**/mongoSettings.xml 46 | 47 | # File-based project format 48 | *.iws 49 | 50 | # IntelliJ 51 | out/ 52 | 53 | # mpeltonen/sbt-idea plugin 54 | .idea_modules/ 55 | 56 | # JIRA plugin 57 | atlassian-ide-plugin.xml 58 | 59 | # Cursive Clojure plugin 60 | .idea/replstate.xml 61 | 62 | # Crashlytics plugin (for Android Studio and IntelliJ) 63 | com_crashlytics_export_strings.xml 64 | crashlytics.properties 65 | crashlytics-build.properties 66 | fabric.properties 67 | 68 | # Editor-based Rest Client 69 | .idea/httpRequests 70 | 71 | # Android studio 3.1+ serialized cache file 72 | .idea/caches/build_file_checksums.ser 73 | 74 | ### PyCharm Patch ### 75 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 76 | 77 | # *.iml 78 | # modules.xml 79 | # .idea/misc.xml 80 | # *.ipr 81 | 82 | # Sonarlint plugin 83 | .idea/**/sonarlint/ 84 | 85 | # SonarQube Plugin 86 | .idea/**/sonarIssues.xml 87 | 88 | # Markdown Navigator plugin 89 | .idea/**/markdown-navigator.xml 90 | .idea/**/markdown-navigator/ 91 | 92 | ### Python ### 93 | # Byte-compiled / optimized / DLL files 94 | __pycache__/ 95 | *.py[cod] 96 | *$py.class 97 | 98 | # C extensions 99 | *.so 100 | 101 | # Distribution / packaging 102 | .Python 103 | build/ 104 | develop-eggs/ 105 | downloads/ 106 | eggs/ 107 | .eggs/ 108 | lib/ 109 | lib64/ 110 | parts/ 111 | sdist/ 112 | var/ 113 | wheels/ 114 | pip-wheel-metadata/ 115 | share/python-wheels/ 116 | *.egg-info/ 117 | .installed.cfg 118 | *.egg 119 | MANIFEST 120 | 121 | # PyInstaller 122 | # Usually these files are written by a python script from a template 123 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 124 | *.manifest 125 | *.spec 126 | 127 | # Installer logs 128 | pip-log.txt 129 | pip-delete-this-directory.txt 130 | 131 | # Unit test / coverage reports 132 | htmlcov/ 133 | .tox/ 134 | .nox/ 135 | .coverage 136 | .coverage.* 137 | .cache 138 | nosetests.xml 139 | coverage.xml 140 | *.cover 141 | .hypothesis/ 142 | .pytest_cache/ 143 | 144 | # Translations 145 | *.mo 146 | *.pot 147 | 148 | # Scrapy stuff: 149 | .scrapy 150 | 151 | # Sphinx documentation 152 | docs/_build/ 153 | 154 | # PyBuilder 155 | target/ 156 | 157 | # pyenv 158 | .python-version 159 | 160 | # pipenv 161 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 162 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 163 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 164 | # install all needed dependencies. 165 | #Pipfile.lock 166 | 167 | # celery beat schedule file 168 | celerybeat-schedule 169 | 170 | # SageMath parsed files 171 | *.sage.py 172 | 173 | # Spyder project settings 174 | .spyderproject 175 | .spyproject 176 | 177 | # Rope project settings 178 | .ropeproject 179 | 180 | # Mr Developer 181 | .mr.developer.cfg 182 | .project 183 | .pydevproject 184 | 185 | # mkdocs documentation 186 | /site 187 | 188 | # mypy 189 | .mypy_cache/ 190 | .dmypy.json 191 | dmypy.json 192 | 193 | # Pyre type checker 194 | .pyre/ 195 | 196 | # End of https://www.gitignore.io/api/python,pycharm 197 | 198 | notes/ 199 | data/apk 200 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tgtg-api-wrapper 2 | tgtg-api-wrapper is a wrapper around the [TooGoodToGo](https://toogoodtogo.com/) API. 3 | 4 | ## Work in progress 5 | Currently redacting the API structure in OpenAPI 3 standard. 6 | A Python wrapper will be written next. 7 | 8 | ## List of API servers 9 | 10 | The list of TooGoodToGo's API servers can be found at this address: https://meta.apptoogoodtogo.com/env/v1/list.json 11 | 12 | As of 20 February 2024, the servers are: 13 | 14 | | Name | Public URL | "Hidden" URL | 15 | |-------------------------- |------------------------------------------------- |-------------------------------------------------------------- | 16 | | Production (Nearest) | https://apptoogoodtogo.com | https://nearest-prod-backend-public.pr-be-shared.tgtg.ninja | 17 | | Production (EU) | https://euw1.apptoogoodtogo.com | https://prod-backend-public.prod-eks-1.tgtg.ninja | 18 | | Production (US) | https://use1.apptoogoodtogo.com | https://prod-backend-public.pr-be-use1.tgtg.ninja | 19 | | Staging (Nearest) | https://backend-staging.apptoogoodtogo.com | https://nearest-staging-backend-public.dev-shared.tgtg.ninja | 20 | | Staging (EU) | https://backend-staging-euw1.apptoogoodtogo.com | https://staging-backend-public.dev-euw1.tgtg.ninja | 21 | | Staging (US) | https://backend-staging-use1.apptoogoodtogo.com | https://staging-backend-public.dev-use1.tgtg.ninja | 22 | | Gold (EU) (Requires VPN) | | https://gold-backend-internal.dev-euw1.tgtg.ninja | 23 | | Gold (US) (Requires VPN) | | https://gold-backend-internal.dev-use1.tgtg.ninja | 24 | | Partner (EU) | https://backend-partner-euw1.apptoogoodtogo.com | | 25 | | Partner (US) | https://backend-partner-use1.apptoogoodtogo.com | | 26 | | QA (EU) | https://backend-qa-euw1.apptoogoodtogo.com | | 27 | | QA (US) | https://backend-qa-use1.apptoogoodtogo.com | | 28 | | Test1 (EU) | https://backend-test1.apptoogoodtogo.com | https://test1-backend-public.dev-euw1.tgtg.ninja | 29 | | Test1 (US) | https://backend-test1-use1.apptoogoodtogo.com | https://test1-backend-public.dev-use1.tgtg.ninja | 30 | | Test2 (EU) | https://backend-test2.apptoogoodtogo.com | https://test2-backend-public.dev-euw1.tgtg.ninja | 31 | | Test2 (US) | https://backend-test2-use1.apptoogoodtogo.com | https://test2-backend-public.dev-use1.tgtg.ninja | 32 | | Test3 (EU) | https://backend-test3.apptoogoodtogo.com | https://test3-backend-public.dev-euw1.tgtg.ninja | 33 | | Test3 (US) | https://backend-test3-use1.apptoogoodtogo.com | https://test3-backend-public.dev-use1.tgtg.ninja | 34 | | Test4 (EU) | https://backend-test4.apptoogoodtogo.com | https://test4-backend-public.dev-euw1.tgtg.ninja | 35 | | Test4 (US) | https://backend-test4-use1.apptoogoodtogo.com | https://test4-backend-public.dev-use1.tgtg.ninja | 36 | | Test5 (EU) | https://backend-test5.apptoogoodtogo.com | https://test5-backend-public.dev-euw1.tgtg.ninja | 37 | | Test5 (US) | https://backend-test5-use1.apptoogoodtogo.com | https://test5-backend-public.dev-use1.tgtg.ninja | 38 | | Test6 (EU) | https://backend-test6.apptoogoodtogo.com | https://test6-backend-public.dev-euw1.tgtg.ninja | 39 | | Test6 (US) | https://backend-test6-use1.apptoogoodtogo.com | https://test6-backend-public.dev-use1.tgtg.ninja | 40 | | Test7 (EU) | https://backend-test7.apptoogoodtogo.com | https://test7-backend-public.dev-euw1.tgtg.ninja | 41 | | Test7 (US) | https://backend-test7-use1.apptoogoodtogo.com | https://test7-backend-public.dev-use1.tgtg.ninja | 42 | | Test8 (EU) | https://backend-test8.apptoogoodtogo.com | https://test8-backend-public.dev-euw1.tgtg.ninja | 43 | | Test8 (US) | https://backend-test8-use1.apptoogoodtogo.com | https://test8-backend-public.dev-use1.tgtg.ninja | 44 | | Test9 (EU) | https://backend-test9.apptoogoodtogo.com | https://test9-backend-public.dev-euw1.tgtg.ninja | 45 | | Test9 (US) | https://backend-test9-use1.apptoogoodtogo.com | https://test9-backend-public.dev-use1.tgtg.ninja | 46 | | Test10 (EU) | https://backend-test10.apptoogoodtogo.com | https://test10-backend-public.dev-euw1.tgtg.ninja | 47 | | Test10 (US) | https://backend-test10-use1.apptoogoodtogo.com | https://test10-backend-public.dev-use1.tgtg.ninja | 48 | | Test11 (EU) | https://backend-test11.apptoogoodtogo.com | https://test11-backend-public.dev-euw1.tgtg.ninja | 49 | | Test11 (US) | https://backend-test11-use1.apptoogoodtogo.com | https://test11-backend-public.dev-use1.tgtg.ninja | 50 | | Test12 (EU) | https://backend-test12.apptoogoodtogo.com | https://test12-backend-public.dev-euw1.tgtg.ninja | 51 | | Test12 (US) | https://backend-test12-use1.apptoogoodtogo.com | https://test12-backend-public.dev-use1.tgtg.ninja | 52 | | Test13 (EU) | https://backend-test13.apptoogoodtogo.com | https://test13-backend-public.dev-euw1.tgtg.ninja | 53 | | Test13 (US) | https://backend-test13-use1.apptoogoodtogo.com | https://test13-backend-public.dev-use1.tgtg.ninja | 54 | | Test14 (EU) | https://backend-test14.apptoogoodtogo.com | https://test14-backend-public.dev-euw1.tgtg.ninja | 55 | | Test14 (US) | https://backend-test14-use1.apptoogoodtogo.com | https://test14-backend-public.dev-use1.tgtg.ninja | 56 | | Test15 (EU) | https://backend-test15.apptoogoodtogo.com | https://test15-backend-public.dev-euw1.tgtg.ninja | 57 | | Test15 (US) | https://backend-test15-use1.apptoogoodtogo.com | https://test15-backend-public.dev-use1.tgtg.ninja | 58 | | Test16 (EU) | https://backend-test16.apptoogoodtogo.com | https://test16-backend-public.dev-euw1.tgtg.ninja | 59 | | Test16 (US) | https://backend-test16-use1.apptoogoodtogo.com | https://test16-backend-public.dev-use1.tgtg.ninja | 60 | | Test17 (EU) | https://backend-test17.apptoogoodtogo.com | https://test17-backend-public.dev-euw1.tgtg.ninja | 61 | | Test17 (US) | https://backend-test17-use1.apptoogoodtogo.com | https://test17-backend-public.dev-use1.tgtg.ninja | 62 | | Test18 (EU) | https://backend-test18.apptoogoodtogo.com | https://test18-backend-public.dev-euw1.tgtg.ninja | 63 | | Test18 (US) | https://backend-test18-use1.apptoogoodtogo.com | https://test18-backend-public.dev-use1.tgtg.ninja | 64 | | Test19 (EU) | https://backend-test19.apptoogoodtogo.com | https://test19-backend-public.dev-euw1.tgtg.ninja | 65 | | Test19 (US) | https://backend-test19-use1.apptoogoodtogo.com | https://test19-backend-public.dev-use1.tgtg.ninja | 66 | | Test20 (EU) | https://backend-test20.apptoogoodtogo.com | https://test20-backend-public.dev-euw1.tgtg.ninja | 67 | | Test20 (US) | https://backend-test20-use1.apptoogoodtogo.com | https://test20-backend-public.dev-use1.tgtg.ninja | 68 | | Test21 (EU) | https://backend-test21.apptoogoodtogo.com | https://test21-backend-public.dev-euw1.tgtg.ninja | 69 | | Test21 (US) | https://backend-test21-use1.apptoogoodtogo.com | https://test21-backend-public.dev-use1.tgtg.ninja | 70 | | Test22 (EU) | https://backend-test22.apptoogoodtogo.com | https://test22-backend-public.dev-euw1.tgtg.ninja | 71 | | Test22 (US) | https://backend-test22-use1.apptoogoodtogo.com | https://test22-backend-public.dev-use1.tgtg.ninja | 72 | | Test23 (EU) | https://backend-test23.apptoogoodtogo.com | https://test23-backend-public.dev-euw1.tgtg.ninja | 73 | | Test23 (US) | https://backend-test23-use1.apptoogoodtogo.com | https://test23-backend-public.dev-use1.tgtg.ninja | 74 | | Test24 (EU) | https://backend-test24.apptoogoodtogo.com | https://test24-backend-public.dev-euw1.tgtg.ninja | 75 | | Test24 (US) | https://backend-test24-use1.apptoogoodtogo.com | https://test24-backend-public.dev-use1.tgtg.ninja | 76 | | Test25 (EU) | https://backend-test25.apptoogoodtogo.com | https://test25-backend-public.dev-euw1.tgtg.ninja | 77 | | Test25 (US) | https://backend-test25-use1.apptoogoodtogo.com | https://test25-backend-public.dev-use1.tgtg.ninja | 78 | | Test26 (EU) | https://backend-test26.apptoogoodtogo.com | https://test26-backend-public.dev-euw1.tgtg.ninja | 79 | | Test26 (US) | https://backend-test26-use1.apptoogoodtogo.com | https://test26-backend-public.dev-use1.tgtg.ninja | 80 | | Test27 (EU) | https://backend-test27.apptoogoodtogo.com | https://test27-backend-public.dev-euw1.tgtg.ninja | 81 | | Test27 (US) | https://backend-test27-use1.apptoogoodtogo.com | https://test27-backend-public.dev-use1.tgtg.ninja | 82 | | Test28 (EU) | https://backend-test28.apptoogoodtogo.com | https://test28-backend-public.dev-euw1.tgtg.ninja | 83 | | Test28 (US) | https://backend-test28-use1.apptoogoodtogo.com | https://test28-backend-public.dev-use1.tgtg.ninja | 84 | | Test29 (EU) | https://backend-test29.apptoogoodtogo.com | https://test29-backend-public.dev-euw1.tgtg.ninja | 85 | | Test29 (US) | https://backend-test29-use1.apptoogoodtogo.com | https://test29-backend-public.dev-use1.tgtg.ninja | 86 | | Test30 (EU) | https://backend-test30.apptoogoodtogo.com | https://test30-backend-public.dev-euw1.tgtg.ninja | 87 | | Test30 (US) | https://backend-test30-use1.apptoogoodtogo.com | https://test30-backend-public.dev-use1.tgtg.ninja | 88 | | Pentest (EU) | https://backend-pentest.apptoogoodtogo.com | | 89 | | Pentest (US) | https://backend-pentest-use1.apptoogoodtogo.com | | 90 | | Bounty (EU) | https://backend-bounty.apptoogoodtogo.com | | 91 | | Bounty (US) | https://backend-bounty-use1.apptoogoodtogo.com | | 92 | | Partner (EU) | https://backend-partner.apptoogoodtogo.com | | 93 | | Partner (US) | https://backend-partner-use1.apptoogoodtogo.com | | 94 | | QA (EU) | https://backend-qa.apptoogoodtogo.com | | 95 | | QA (US) | https://backend-qa-use1.apptoogoodtogo.com | | 96 | 97 | 98 | 99 | The base path for the API is `/api/`. 100 | 101 | The documentation seems to be at `/api/api-docs` but is only accessible through their VPN. 102 | 103 | A GET request to `/web` throws a 403 Forbidden error with the message "Invalid CSRF token". 104 | 105 | A GET request to `/logout` redirects (302) to `/login?logout`, which throws a 404 Not Found error. 106 | 107 | A GET request to `/ping` returns `pong` :D 108 | 109 | A GET request to `/api/` on a public URL redirects (302) to `/api/api-docs` on the corresponding "Hidden" server. 110 | 111 | The APIs seem to be built with Spring Boot (clue: the `Whitelabel Error Page`) 112 | -------------------------------------------------------------------------------- /data/endpoints.java: -------------------------------------------------------------------------------- 1 | package td; 2 | 3 | public interface InterfaceC10693a { 4 | 5 | /* app */ 6 | @InterfaceC11753k({"withoutAuthorization: true"}) 7 | @POST("api/app/v1/app_settings") 8 | Object m2721g(@NotNull Continuation> Continuation); 9 | 10 | @POST("api/app/v1/myStoreOnboardingSettings") 11 | Object m2691v(@NotNull Continuation> Continuation); 12 | 13 | @POST("api/app/v1/onStartup") 14 | Object m2714j0(@NotNull Continuation> Continuation); 15 | 16 | @POST("api/app/v1/savePushToken") 17 | Object m2749P(@Body @NotNull PushToken pushToken, @NotNull Continuation> Continuation); 18 | 19 | @POST("api/app/v1/user_settings") 20 | Object m2758K0(@NotNull Continuation> Continuation); 21 | 22 | 23 | /* auth */ 24 | @POST("api/auth/v4/authByRequestPollingId") 25 | Object m2738V(@Body @NotNull AuthByRequestPollingIdRequest authByRequestPollingIdRequest, @NotNull Continuation> Continuation); 26 | 27 | @POST("api/auth/v4/authByRequestToken") 28 | Object m2734Z(@Body @NotNull AuthByRequestTokenRequest authByRequestTokenRequest, @NotNull Continuation> Continuation); 29 | 30 | @POST("api/auth/v4/loginByDirectWebToAppLoginToken") 31 | Object m2690v0(@Body @NotNull DirectWebToAppLoginRequest directWebToAppLoginRequest, @NotNull Continuation> Continuation); 32 | 33 | @POST("api/auth/v4/authByRequestPin") 34 | Object m2697s(@Body @NotNull AuthByRequestPinRequest authByRequestPinRequest, @NotNull Continuation> Continuation); 35 | 36 | @POST("api/auth/v4/signUpByEmail") 37 | Object m2695t(@Body @NotNull SignUpByEmailRequest signUpByEmailRequest, @NotNull Continuation> Continuation); 38 | 39 | @POST("api/auth/v4/authByEmail") 40 | Object m2710l0(@Body @NotNull EmailAuthenticateRequest emailAuthenticateRequest, @NotNull Continuation> Continuation); 41 | 42 | @POST("api/auth/v4/signUpByThirdParty") 43 | Object m2713k(@Body @NotNull SignUpByThirdPartyRequest signUpByThirdPartyRequest, @NotNull Continuation> Continuation); 44 | 45 | @POST("api/auth/v4/loginByThirdParty") 46 | Object m2712k0(@Body @NotNull LoginByThirdPartyRequest loginByThirdPartyRequest, @NotNull Continuation> Continuation); 47 | 48 | @POST("api/auth/v4/logout") 49 | Object m2723f(@NotNull Continuation Continuation); 50 | 51 | 52 | /* discover */ 53 | @POST("api/discover/v1/") 54 | Object m2751O(@Body @NotNull DiscoverAllBucketsRequest discoverAllBucketsRequest, @InterfaceC11751i("X-TimezoneOffset") String str, @InterfaceC11751i("X-24HourFormat") String str2, @NotNull Continuation> Continuation); 55 | 56 | @POST("api/discover/v1/bucket") 57 | Object m2739U(@Body @NotNull DiscoverSingleBucketRequest discoverSingleBucketRequest, @InterfaceC11751i("X-TimezoneOffset") String str, @InterfaceC11751i("X-24HourFormat") String str2, @NotNull Continuation> Continuation); 58 | 59 | 60 | /* gdpr */ 61 | @POST("api/gdpr/v1/{userId}/deleteUser") 62 | Object m2779A(@Path(encoded = true, value = "userId") String str, @Body @NotNull DeleteUserRequest deleteUserRequest, @NotNull Continuation> Continuation); 63 | 64 | @POST("api/gdpr/v1/{userId}/exportUserData") 65 | Object m2767G(@Path(encoded = true, value = "userId") String str, @Body @NotNull ExportUserRequest exportUserRequest, @NotNull Continuation> Continuation); 66 | 67 | 68 | /* hiddenstore */ 69 | @POST("api/hiddenstore/v2/remove") 70 | Object m2756L0(@Body @NotNull RemoveHiddenStoreRequest removeHiddenStoreRequest, @NotNull Continuation> Continuation); 71 | 72 | @POST("api/hiddenstore/v2/unlock") 73 | Object m2693u(@Body @NotNull UnlockHiddenStoreRequest unlockHiddenStoreRequest, @NotNull Continuation> Continuation); 74 | 75 | 76 | /* impact */ 77 | @POST("api/impact/v1/{USER_ID}/moneySaved") 78 | Object m2764H0(@Path(encoded = true, value = "USER_ID") String str, @NotNull Continuation> Continuation); 79 | 80 | @POST("api/impact/v1/{userId}/co2eSaved") 81 | Object m2716i0(@Path(encoded = true, value = "userId") String str, @NotNull Continuation> Continuation); 82 | 83 | 84 | /* invitation */ 85 | @POST("api/invitation/v1/{invitationId}/fulfill") 86 | Object m2777B(@Path(encoded = true, value = "invitationId") @NotNull String str, @Body @NotNull FulfillmentRequest fulfillmentRequest, @NotNull Continuation> Continuation); 87 | 88 | @POST("api/invitation/v1/order/getOrder/{invitationId}") 89 | Object m2776B0(@Path(encoded = true, value = "invitationId") @NotNull String str, @NotNull Continuation> Continuation); 90 | 91 | @POST("api/invitation/v1/order/{orderId}") 92 | Object m2774C0(@Path(encoded = true, value = "orderId") @NotNull String str, @NotNull Continuation> Continuation); 93 | 94 | @POST("api/invitation/v1/order/{orderId}/createOrEnable") 95 | Object m2762I0(@Path(encoded = true, value = "orderId") @NotNull String str, @NotNull Continuation> Continuation); 96 | 97 | @POST("api/invitation/v1/order/fromLink/{invitationExternalId}") 98 | Object m2755M(@Path(encoded = true, value = "invitationExternalId") @NotNull String str, @NotNull Continuation> Continuation); 99 | 100 | @POST("api/invitation/v1/{invitationExternalId}/accept") 101 | Object m2731b(@Path(encoded = true, value = "invitationExternalId") @NotNull String str, @NotNull Continuation> Continuation); 102 | 103 | @POST("api/invitation/v1/{invitationId}/regret") 104 | Object m2728c0(@Path(encoded = true, value = "invitationId") @NotNull String str, @NotNull Continuation> Continuation); 105 | 106 | @POST("api/invitation/v1/{invitationId}/disable") 107 | Object m2708m0(@Path(encoded = true, value = "invitationId") @NotNull String str, @NotNull Continuation> Continuation); 108 | 109 | @POST("api/invitation/v1/order/markNotCollected/{invitationId}") 110 | Object m2705o(@Path(encoded = true, value = "invitationId") @NotNull String str, @NotNull Continuation> Continuation); 111 | 112 | 113 | /* item */ 114 | @POST("api/item/v8/recommendations") 115 | Object m2770E0(@Body @NotNull RecommendationsListRequest recommendationsListRequest, @InterfaceC11751i("X-TimezoneOffset") String str, @InterfaceC11751i("X-24HourFormat") String str2, @NotNull Continuation> Continuation); 116 | 117 | @POST("api/item/v8/{itemId}") 118 | Object m2759K(@Path(encoded = true, value = "itemId") String str, @Body @NotNull ItemRequest itemRequest, @InterfaceC11751i("X-TimezoneOffset") String str2, @InterfaceC11751i("X-24HourFormat") String str3, @NotNull Continuation> Continuation); 119 | 120 | @POST("api/item/v8/count/") 121 | Object m2733a(@Body @NotNull ListItemRequest listItemRequest, @NotNull Continuation> Continuation); 122 | 123 | @POST("api/item/v8/") 124 | Object m2706n0(@Body @NotNull ListItemRequest listItemRequest, @InterfaceC11751i("X-TimezoneOffset") String str, @InterfaceC11751i("X-24HourFormat") String str2, @NotNull Continuation> Continuation); 125 | 126 | @POST("api/item/v8/{itemId}/getPriceSpecifications") 127 | Object m2684y0(@Path(encoded = true, value = "itemId") String str, @Body @NotNull PriceSpecificationsRequest priceSpecificationsRequest, @NotNull Continuation> Continuation); 128 | 129 | 130 | /* location */ 131 | @POST("api/location/v1/lookup") 132 | Object m2771E(@Body @NotNull GeoLocation geoLocation, @NotNull Continuation> Continuation); 133 | 134 | @POST("api/location/v1/search") 135 | Object m2752N0(@Body @NotNull LocationRequest locationRequest, @NotNull Continuation> Continuation); 136 | 137 | 138 | /* manufactureritem */ 139 | @POST("api/manufactureritem/v1/") 140 | Object m2727d(@Body @NotNull ManufacturerItemsRequest manufacturerItemsRequest, @NotNull Continuation> Continuation); 141 | 142 | @POST("api/manufactureritem/v2/updateUserTooltipSeenTime") 143 | Object m2711l(@NotNull Continuation> Continuation); 144 | 145 | @POST("api/manufactureritem/v2/") 146 | Object m2698r0(@Body @NotNull ManufacturerItemsV2Request manufacturerItemsV2Request, @NotNull Continuation> Continuation); 147 | 148 | 149 | /* map */ 150 | @POST("api/map/v1/listAllBusinessLocationPicker") 151 | Object m2766G0(@NotNull Continuation> Continuation); 152 | 153 | 154 | /* order */ 155 | @POST("api/order/v7/{orderId}/charityPickupDocumentUrl") 156 | Object m2775C(@Path(encoded = true, value = "orderId") @NotNull String str, @NotNull Continuation> Continuation); 157 | 158 | @POST("api/order/v7/{orderId}/markNotCollected") 159 | Object m2765H(@Path(encoded = true, value = "orderId") @NotNull String str, @NotNull Continuation> Continuation); 160 | 161 | @POST("api/order/v7/") 162 | Object m2760J0(@Body @NotNull ListOrdersRequest listOrdersRequest, @NotNull Continuation> Continuation); 163 | 164 | @POST("api/order/v7/{orderId}/abort") 165 | Object m2754M0(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull CancelOrderRequest cancelOrderRequest, @NotNull Continuation> Continuation); 166 | 167 | @POST("api/order/v7/{orderId}/rate") 168 | Object m2753N(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull OrderRatingItem orderRatingItem, @NotNull Continuation> Continuation); 169 | 170 | @POST("api/order/v7/{orderId}/cancel") 171 | Object m2748P0(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull CancelOrderRequest cancelOrderRequest, @NotNull Continuation> Continuation); 172 | 173 | @POST("api/order/v7/{orderId}/pay") 174 | Object m2743S(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull CreatePaymentRequest createPaymentRequest, @NotNull Continuation> Continuation); 175 | 176 | @POST("api/order/v7/active") 177 | Object m2736X(@Body @NotNull ListActiveOrdersRequest listActiveOrdersRequest, @NotNull Continuation> Continuation); 178 | 179 | @POST("api/order/v7/{orderId}/validateAndSetAddress") 180 | Object m2730b0(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull UserAddress userAddress, @NotNull Continuation> Continuation); 181 | 182 | @POST("api/order/v7/{orderId}/status") 183 | Object m2717i(@Path(encoded = true, value = "orderId") @NotNull String str, @NotNull Continuation> Continuation); 184 | 185 | @POST("api/order/v7/{orderId}") 186 | Object m2704o0(@Path(encoded = true, value = "orderId") @NotNull String str, @NotNull Continuation> Continuation); 187 | 188 | @POST("api/order/v7/{orderId}/wouldBuyAgain") 189 | Object m2702p0(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull WouldBuyAgainRequest wouldBuyAgainRequest, @NotNull Continuation> Continuation); 190 | 191 | @POST("api/order/v7/{orderId}/redeem") 192 | Object m2696s0(@Path(encoded = true, value = "orderId") @NotNull String str, @Body @NotNull RedeemOrderRequest redeemOrderRequest, @NotNull Continuation> Continuation); 193 | 194 | @POST("api/order/v7/{receiptId}/sendOrderConfirmedEmail") 195 | Object m2692u0(@Path(encoded = true, value = "receiptId") String str, @Body @NotNull OrderConfirmedEmailRequest orderConfirmedEmailRequest, @NotNull Continuation> Continuation); 196 | 197 | @POST("api/order/v7/create/{itemId}") 198 | Object m2715j(@Path(encoded = true, value = "itemId") @NotNull String str, @Body @NotNull CreateOrderRequest createOrderRequest, @NotNull Continuation> Continuation); 199 | 200 | 201 | /* payment */ 202 | @POST("api/payment/v3/{paymentId}/additionalAuthorization") 203 | Object m2688w0(@Path(encoded = true, value = "paymentId") @NotNull String str, @Body @NotNull AdditionalAuthRequest additionalAuthRequest, @NotNull Continuation> Continuation); 204 | 205 | @POST("api/payment/v3/{paymentId}") 206 | Object m2687x(@Path(encoded = true, value = "paymentId") @NotNull String str, @NotNull Continuation> Continuation); 207 | 208 | @POST("api/payment/v3/{paymentId}/biometrics") 209 | Object m2740T0(@Path(encoded = true, value = "paymentId") @NotNull String str, @NotNull Continuation> Continuation); 210 | 211 | 212 | /* paymentMethod */ 213 | @POST("api/paymentMethod/v1/item/{itemId}") 214 | Object m2768F0(@Path(encoded = true, value = "itemId") String str, @Body @NotNull PaymentMethodsRequest paymentMethodsRequest, @NotNull Continuation> Continuation); 215 | 216 | @POST("api/paymentMethod/v1/savedpaymentmethod/delete") 217 | Object m2689w(@Body @NotNull DeleteCardRequest deleteCardRequest, @NotNull Continuation> Continuation); 218 | 219 | @POST("api/paymentMethod/v1/") 220 | Object m2718h0(@Body @NotNull PaymentMethodsRequest paymentMethodsRequest, @NotNull Continuation> Continuation); 221 | 222 | 223 | /* selfonboarding */ 224 | @POST("api/selfonboarding/v1/selfonboard") 225 | Object m2745R(@Body @NotNull SelfOnboardRequest selfOnboardRequest, @NotNull Continuation> Continuation); 226 | 227 | 228 | /* store */ 229 | @POST("api/store/v4/{storeId}") 230 | Object m2724e0(@Path(encoded = true, value = "storeId") String str, @Body @NotNull StoreRequest storeRequest, @NotNull Continuation> Continuation); 231 | 232 | 233 | /* support */ 234 | @POST("api/support/v2/consumer/") 235 | Object m2778A0(@Body @NotNull ConsumerSupportRequest consumerSupportRequest, @NotNull Continuation> Continuation); 236 | 237 | @POST("api/support/v2/consumer/refund/choice") 238 | Object m2746Q0(@Body @NotNull ConsumerRefundChoiceRequest consumerRefundChoiceRequest, @NotNull Continuation> Continuation); 239 | 240 | @POST("api/support/v2/consumer/{supportRequestId}/confirm") 241 | Object m2732a0(@Path(encoded = true, value = "supportRequestId") String str, @NotNull Continuation> Continuation); 242 | 243 | @Multipart 244 | @POST("api/support/v2/uploading/files") 245 | Object m2703p(@Part List list, @NotNull Continuation> Continuation); 246 | 247 | @POST("api/support/v1/business/") 248 | Object m2686x0(@Body @NotNull BusinessSupportRequest businessSupportRequest, @NotNull Continuation> Continuation); 249 | 250 | 251 | /* tracking */ 252 | @InterfaceC11753k({"withoutAuthorization: true"}) 253 | @POST("api/tracking/v1/anonymousEvents") 254 | Object m2699r(@Body @NotNull ConsentScreenEventRequest consentScreenEventRequest, @NotNull Continuation> Continuation); 255 | 256 | @POST("api/tracking/v1/events") 257 | Object m2694t0(@Body @NotNull TrackingEventsRequest trackingEventsRequest, @NotNull Continuation> Continuation); 258 | 259 | 260 | /* user */ 261 | @POST("api/user/v2/") 262 | Object m2773D(@NotNull Continuation> Continuation); 263 | 264 | @POST("api/user/v2/profileDetails") 265 | Object m2772D0(@NotNull Continuation> Continuation); 266 | 267 | @POST("api/user/v2/updatePushNotificationSettings") 268 | Object m2769F(@Body @NotNull PushNotificationSettingsRequestResponse pushNotificationSettingsRequestResponse, @NotNull Continuation> Continuation); 269 | 270 | @POST("api/user/demographics/update") 271 | Object m2761J(@Body @NotNull UserDemographicsUpdate userDemographicsUpdate, @NotNull Continuation> Continuation); 272 | 273 | @POST("api/user/v2/emailChangeRequest") 274 | Object m2757L(@Body @NotNull EmailChangeRequest emailChangeRequest, @NotNull Continuation> Continuation); 275 | 276 | @POST("api/user/v2/getEmailStatus") 277 | Object m2683z(@NotNull Continuation> Continuation); 278 | 279 | @POST("api/user/v2/getPushNotificationSettings") 280 | Object m2682z0(@NotNull Continuation> Continuation); 281 | 282 | @POST("api/user/v2/updateUserReferralAcceptanceState") 283 | Object m2709m(@Body @NotNull UserReferralUpdateAcceptanceStateRequest userReferralUpdateAcceptanceStateRequest, @NotNull Continuation> Continuation); 284 | 285 | @POST("api/user/v2/confirmEmail/{token}") 286 | Object m2707n(@Path(encoded = true, value = "token") @NotNull String str, @NotNull Continuation> Continuation); 287 | 288 | @POST("api/user/v2/mePage") 289 | Object m2700q0(@NotNull Continuation> Continuation); 290 | 291 | @POST("api/user/badge/getBadge") 292 | Object m2747Q(@Body @NotNull UserBadgeDetailsRequest userBadgeDetailsRequest, @NotNull Continuation> Continuation); 293 | 294 | @POST("api/user/v2/resendWelcomeEmail") 295 | Object m2742S0(@Body @NotNull ResendWelcomeEmailRequest resendWelcomeEmailRequest, @NotNull Continuation> Continuation); 296 | 297 | @POST("api/user/v2/update") 298 | Object m2737W(@Body @NotNull UserData userData, @NotNull Continuation> Continuation); 299 | 300 | @POST("api/user/badge") 301 | Object m2725e(@NotNull Continuation> Continuation); 302 | 303 | @POST("api/user/favorite/v1/{itemId}/update") 304 | Object m2720g0(@Path(encoded = true, value = "itemId") String str, @Body @NotNull SetFavoriteRequest setFavoriteRequest, @NotNull Continuation> Continuation); 305 | 306 | 307 | /* voucher */ 308 | @POST("api/voucher/v4/used") 309 | Object m2763I(@NotNull Continuation> Continuation); 310 | 311 | @POST("api/voucher/v3/") 312 | Object m2750O0(@Body @NotNull VoucherListRequest voucherListRequest, @NotNull Continuation> Continuation); 313 | 314 | @POST("api/voucher/v3/add") 315 | Object m2744R0(@Body @NotNull AddVoucherRequest addVoucherRequest, @NotNull Continuation> Continuation); 316 | 317 | @POST("api/voucher/v4/active") 318 | Object m2741T(@NotNull Continuation> Continuation); 319 | 320 | @POST("api/voucher/v3/{voucherId}/storeFilterList") 321 | Object m2726d0(@Path(encoded = true, value = "voucherId") String str, @Body @NotNull VoucherFilterRequest voucherFilterRequest, @NotNull Continuation> Continuation); 322 | 323 | @POST("api/voucher/v3/{voucherId}") 324 | Object m2722f0(@Path(encoded = true, value = "voucherId") String str, @Body @NotNull VoucherDetailRequest voucherDetailRequest, @NotNull Continuation> Continuation); 325 | 326 | @POST("api/voucher/v4/{voucherId}") 327 | Object m2719h(@Path(encoded = true, value = "voucherId") String str, @NotNull Continuation> Continuation); 328 | 329 | @POST("api/voucher/v4/add") 330 | Object m2701q(@Body @NotNull AddVoucherRequest addVoucherRequest, @NotNull Continuation> Continuation); 331 | 332 | @POST("api/voucher/v4/{voucherId}/storeFilterList") 333 | Object m2685y(@Path(encoded = true, value = "voucherId") String str, @NotNull Continuation> Continuation); 334 | 335 | 336 | /* widget */ 337 | @POST("api/widget/v1/getfavorites") 338 | Object m2735Y(@Body @NotNull FavouriteWidgetRequest favouriteWidgetRequest, @NotNull Continuation> Continuation); 339 | 340 | 341 | /* external */ 342 | @GET("https://meta.apptoogoodtogo.com/env/v1/list.json") 343 | Object m2729c(@NotNull Continuation> Continuation); 344 | 345 | } -------------------------------------------------------------------------------- /openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.3 2 | info: 3 | title: TooGoodToGo API 4 | description: Attempt to reverse-engineer the TooGoodToGo API 5 | version: 0.0.1 6 | 7 | servers: 8 | - url: https://apptoogoodtogo.com/api 9 | description: Production (Nearest) 10 | - url: https://euw1.apptoogoodtogo.com/api 11 | description: Production (EU) 12 | - url: https://use1.apptoogoodtogo.com/api 13 | description: Production (US) 14 | 15 | - url: https://backend-staging.apptoogoodtogo.com/api 16 | description: Staging (Nearest) 17 | - url: https://backend-staging-euw1.apptoogoodtogo.com/api 18 | description: Staging (EU) 19 | - url: https://backend-staging-use1.apptoogoodtogo.com/api 20 | description: Staging (US) 21 | 22 | - url: https://gold-backend-internal.dev-euw1.tgtg.ninja/api 23 | description: Gold (EU) (Requires VPN) 24 | - url: https://gold-backend-internal.dev-use1.tgtg.ninja/api 25 | description: Gold (US) (Requires VPN) 26 | 27 | - url: https://backend-test1.apptoogoodtogo.com/api 28 | description: Test1 (EU) 29 | - url: https://backend-test1-use1.apptoogoodtogo.com/api 30 | description: Test1 (US) 31 | 32 | - url: https://backend-test2.apptoogoodtogo.com/api 33 | description: Test2 (EU) 34 | - url: https://backend-test2-use1.apptoogoodtogo.com/api 35 | description: Test2 (US) 36 | 37 | - url: https://backend-test3.apptoogoodtogo.com/api 38 | description: Test3 (EU) 39 | - url: https://backend-test3-use1.apptoogoodtogo.com/api 40 | description: Test3 (US) 41 | 42 | - url: https://backend-test4.apptoogoodtogo.com/api 43 | description: Test4 (EU) 44 | - url: https://backend-test4-use1.apptoogoodtogo.com/api 45 | description: Test4 (US) 46 | 47 | - url: https://backend-test5.apptoogoodtogo.com/api 48 | description: Test5 (EU) 49 | - url: https://backend-test5-use1.apptoogoodtogo.com/api 50 | description: Test5 (US) 51 | 52 | - url: https://backend-test6.apptoogoodtogo.com/api 53 | description: Test6 (EU) 54 | - url: https://backend-test6-use1.apptoogoodtogo.com/api 55 | description: Test6 (US) 56 | 57 | - url: https://backend-test7.apptoogoodtogo.com/api 58 | description: Test7 (EU) 59 | - url: https://backend-test7-use1.apptoogoodtogo.com/api 60 | description: Test7 (US) 61 | 62 | - url: https://backend-test8.apptoogoodtogo.com/api 63 | description: Test8 (EU) 64 | - url: https://backend-test8-use1.apptoogoodtogo.com/api 65 | description: Test8 (US) 66 | 67 | - url: https://backend-test9.apptoogoodtogo.com/api 68 | description: Test9 (EU) 69 | - url: https://backend-test9-use1.apptoogoodtogo.com/api 70 | description: Test9 (US) 71 | 72 | tags: 73 | - name: "app" 74 | description: "" 75 | - name: "auth" 76 | description: "" 77 | - name: "basket" 78 | description: "" 79 | - name: "gdpr" 80 | description: "" 81 | - name: "hiddenstore" 82 | description: "" 83 | - name: "item" 84 | description: "" 85 | - name: "location" 86 | description: "" 87 | - name: "map" 88 | description: "" 89 | - name: "order" 90 | description: "" 91 | - name: "payment" 92 | description: "" 93 | - name: "selfonboarding" 94 | description: "" 95 | - name: "store" 96 | description: "" 97 | - name: "support" 98 | description: "" 99 | - name: "tracking" 100 | description: "" 101 | - name: "user" 102 | description: "" 103 | - name: "voucher" 104 | description: "" 105 | 106 | paths: 107 | /app/v1/app_settings: 108 | post: 109 | tags: 110 | - app 111 | summary: Get App settings 112 | 113 | parameters: 114 | - in: header 115 | name: Accept-Language 116 | schema: 117 | type: string 118 | required: true 119 | 120 | responses: 121 | '200': 122 | description: OK 123 | content: 124 | application/json: 125 | schema: 126 | $ref: '#/components/schemas/AppSettings' 127 | '400': 128 | description: Bad request. The Accept-Language header is required. 129 | 130 | /app/v1/user_settings: 131 | post: 132 | tags: 133 | - app 134 | summary: Get User settings 135 | security: 136 | - bearerAuth: [] 137 | 138 | responses: 139 | '200': 140 | description: OK 141 | content: 142 | application/json: 143 | schema: 144 | $ref: '#/components/schemas/UserSettings' 145 | '400': 146 | description: Bad request. The Accept-Language header is required. 147 | 148 | /auth/v2/loginByEmail: 149 | post: 150 | tags: 151 | - auth 152 | summary: Logs in a user by email. 153 | 154 | requestBody: 155 | $ref: '#/components/requestBodies/LoginByEmailRequest' 156 | 157 | responses: 158 | '200': 159 | description: OK 160 | content: 161 | application/json: 162 | schema: 163 | $ref: '#/components/schemas/LoginResponse' 164 | '400': 165 | description: VALIDATION_ERROR 166 | content: 167 | application/json: 168 | schema: 169 | $ref: '#/components/schemas/Errors' 170 | '403': 171 | description: FAILED_LOGIN 172 | content: 173 | application/json: 174 | schema: 175 | $ref: '#/components/schemas/Errors' 176 | 177 | /auth/v2/logout: 178 | post: 179 | tags: 180 | - auth 181 | summary: Logs out (destroys the tokens) 182 | security: 183 | - bearerAuth: [] 184 | 185 | responses: 186 | '200': 187 | description: OK 188 | '401': 189 | description: UNAUTHORIZED 190 | content: 191 | application/json: 192 | schema: 193 | oneOf: 194 | - $ref: '#/components/schemas/Errors' 195 | - $ref: '#/components/schemas/Error' 196 | 197 | /hiddenstore/v2/unlock: 198 | post: 199 | tags: 200 | - hiddenstore 201 | summary: Unlock a hidden store 202 | security: 203 | - bearerAuth: [] 204 | 205 | requestBody: 206 | $ref: '#/components/requestBodies/UnlockHiddenStoreRequest' 207 | 208 | responses: 209 | '200': 210 | description: OK 211 | content: 212 | application/json: 213 | schema: 214 | $ref: '#/components/schemas/UnlockHiddenStoreResponse' 215 | '400': 216 | description: VALIDATION_ERROR 217 | content: 218 | application/json: 219 | schema: 220 | $ref: '#/components/schemas/Errors' 221 | '401': 222 | description: UNAUTHORIZED 223 | content: 224 | application/json: 225 | schema: 226 | oneOf: 227 | - $ref: '#/components/schemas/Errors' 228 | - $ref: '#/components/schemas/Error' 229 | '403': 230 | description: FORBIDDEN 231 | content: 232 | application/json: 233 | schema: 234 | $ref: '#/components/schemas/Errors' 235 | # happens if the given user_id doesn't match with the given bearer token 236 | # UNAUTHORIZED 237 | # Access is denied 238 | 239 | /auth/v2/token/refresh: 240 | post: 241 | tags: 242 | - auth 243 | summary: Refresh the access token 244 | 245 | requestBody: 246 | required: true 247 | content: 248 | application/json: 249 | schema: 250 | type: object 251 | properties: 252 | refresh_token: 253 | type: string 254 | description: "Refresh token" 255 | required: 256 | - refresh_token 257 | 258 | responses: 259 | '200': 260 | description: OK 261 | content: 262 | application/json: 263 | schema: 264 | $ref: '#/components/schemas/RefreshTokenResult' 265 | '400': 266 | description: VALIDATION_ERROR - refresh_token must not be blank 267 | content: 268 | application/json: 269 | schema: 270 | $ref: '#/components/schemas/Errors' 271 | '401': 272 | description: UNAUTHORIZED - Invalid token 273 | content: 274 | application/json: 275 | schema: 276 | $ref: '#/components/schemas/Errors' 277 | 278 | /map/v1/listAllBusinessLocationPicker: 279 | post: 280 | tags: 281 | - map 282 | summary: List all business location picker 283 | 284 | responses: 285 | '200': 286 | description: OK 287 | content: 288 | text/html: 289 | schema: 290 | $ref: '#/components/schemas/StoreLocationListResult' 291 | 292 | /user/v1/: 293 | post: 294 | tags: 295 | - user 296 | summary: Get current user data 297 | security: 298 | - bearerAuth: [] 299 | 300 | responses: 301 | '200': 302 | description: OK 303 | content: 304 | application/json: 305 | schema: 306 | $ref: '#/components/schemas/UserData' 307 | '401': 308 | description: UNAUTHORIZED 309 | content: 310 | application/json: 311 | schema: 312 | oneOf: 313 | - $ref: '#/components/schemas/Errors' 314 | - $ref: '#/components/schemas/Error' 315 | 316 | /user/v1/update: 317 | post: 318 | tags: 319 | - user 320 | summary: Update current user data 321 | security: 322 | - bearerAuth: [] 323 | 324 | requestBody: 325 | required: true 326 | content: 327 | application/json: 328 | schema: 329 | $ref: '#/components/schemas/UserData' # user_id is required but not checked 330 | 331 | responses: 332 | '200': 333 | description: OK 334 | content: 335 | application/json: 336 | schema: 337 | $ref: '#/components/schemas/UserData' 338 | '400': 339 | description: VALIDATION_ERROR 340 | content: 341 | application/json: 342 | schema: 343 | $ref: '#/components/schemas/Errors' 344 | '401': 345 | description: UNAUTHORIZED 346 | content: 347 | application/json: 348 | schema: 349 | oneOf: 350 | - $ref: '#/components/schemas/Errors' 351 | - $ref: '#/components/schemas/Error' 352 | 353 | /user/v1/changePassword: 354 | post: 355 | tags: 356 | - user 357 | summary: Change password 358 | security: 359 | - bearerAuth: [] 360 | 361 | requestBody: 362 | $ref: '#/components/requestBodies/ChangePasswordRequest' 363 | 364 | responses: 365 | '200': 366 | description: OK 367 | '400': 368 | description: VALIDATION_ERROR 369 | content: 370 | application/json: 371 | schema: 372 | $ref: '#/components/schemas/Errors' 373 | '401': 374 | description: UNAUTHORIZED 375 | content: 376 | application/json: 377 | schema: 378 | oneOf: 379 | - $ref: '#/components/schemas/Errors' 380 | - $ref: '#/components/schemas/Error' 381 | '403': 382 | description: PASSWORD_INCORRECT 383 | content: 384 | application/json: 385 | schema: 386 | $ref: '#/components/schemas/Errors' 387 | # PASSWORD_INCORRECT 388 | # WrongPasswordException 389 | 390 | /user/v1/resetPassword: 391 | post: 392 | tags: 393 | - user 394 | summary: Reset password 395 | 396 | requestBody: 397 | $ref: '#/components/requestBodies/ResetPasswordRequest' 398 | 399 | responses: 400 | '200': 401 | description: 'OK' 402 | '400': 403 | description: VALIDATION_ERROR 404 | content: 405 | application/json: 406 | schema: 407 | $ref: '#/components/schemas/Errors' 408 | 409 | /user/v1/resendWelcomeEmail: 410 | post: 411 | tags: 412 | - user 413 | summary: Resend the Welcome email 414 | security: 415 | - bearerAuth: [] 416 | 417 | requestBody: 418 | $ref: '#/components/requestBodies/ResendWelcomeEmailRequest' 419 | 420 | responses: 421 | '200': 422 | description: 'OK' 423 | '400': 424 | description: VALIDATION_ERROR 425 | content: 426 | application/json: 427 | schema: 428 | $ref: '#/components/schemas/Errors' 429 | '401': 430 | description: UNAUTHORIZED 431 | content: 432 | application/json: 433 | schema: 434 | oneOf: 435 | - $ref: '#/components/schemas/Errors' 436 | - $ref: '#/components/schemas/Error' 437 | '403': 438 | description: FORBIDDEN 439 | content: 440 | application/json: 441 | schema: 442 | $ref: '#/components/schemas/Errors' 443 | # happens if the given user_id doesn't match with the given bearer token 444 | # UNAUTHORIZED 445 | # Access is denied 446 | 447 | components: 448 | # Authentication 449 | securitySchemes: 450 | bearerAuth: 451 | type: http 452 | scheme: bearer 453 | 454 | # Describing Requests 455 | requestBodies: 456 | LoginByEmailRequest: 457 | required: true 458 | content: 459 | application/json: 460 | schema: 461 | type: object 462 | properties: 463 | device_type: 464 | type: string 465 | description: "Device type" 466 | enum: [UNKNOWN, IOS, ANDROID] 467 | email: 468 | type: string 469 | description: "User's email" 470 | password: 471 | type: string 472 | format: password 473 | description: "User's password" 474 | example: 475 | device_type: "ANDROID" 476 | email: "john.doe@dev.local" 477 | password: "p@ssw0rd" 478 | required: 479 | - device_type 480 | - email 481 | - password 482 | 483 | ChangePasswordRequest: 484 | required: true 485 | content: 486 | application/json: 487 | schema: 488 | type: object 489 | properties: 490 | old_password: 491 | type: string 492 | description: "Old password" 493 | new_password: 494 | type: string 495 | description: "New password" 496 | refresh_token: 497 | type: string 498 | description: "Refresh token" 499 | required: 500 | - old_password 501 | - new_password 502 | - refresh_token 503 | 504 | ResetPasswordRequest: 505 | required: true 506 | content: 507 | application/json: 508 | schema: 509 | type: object 510 | properties: 511 | email: 512 | type: string 513 | format: email 514 | example: john.doe@dev.local 515 | required: 516 | - email 517 | 518 | ResendWelcomeEmailRequest: 519 | required: true 520 | content: 521 | application/json: 522 | schema: 523 | type: object 524 | properties: 525 | user_id: 526 | type: string 527 | example: "123456" 528 | required: 529 | - user_id 530 | 531 | UnlockHiddenStoreRequest: 532 | required: true 533 | content: 534 | application/json: 535 | schema: 536 | type: object 537 | properties: 538 | unlock_code: 539 | type: string 540 | user_id: 541 | type: string 542 | example: "123456" 543 | required: 544 | - unlock_code 545 | - user_id 546 | 547 | # Describing Responses 548 | schemas: 549 | Errors: 550 | type: object 551 | properties: 552 | errors: 553 | type: array 554 | items: 555 | type: object 556 | properties: 557 | code: 558 | type: string 559 | description: Error type 560 | message: 561 | type: string 562 | description: Error message 563 | required: 564 | - code 565 | required: 566 | - errors 567 | 568 | Error: 569 | type: object 570 | properties: 571 | timestamp: 572 | type: integer 573 | example: 1622583457179 574 | status: 575 | type: integer 576 | example: 401 577 | error: 578 | type: string 579 | example: "Unauthorized" 580 | message: 581 | type: string 582 | path: 583 | type: string 584 | example: "/api/auth/v2/logout" 585 | required: 586 | - timestamp 587 | - status 588 | - error 589 | - message 590 | - path 591 | 592 | StoreLocationListResult: 593 | type: object 594 | properties: 595 | info: 596 | type: array 597 | items: 598 | type: object 599 | properties: 600 | latitude: 601 | type: string 602 | example: "23.45678912" 603 | longitude: 604 | type: string 605 | example: "5.67890123" 606 | msg: 607 | type: string 608 | example: "OK" 609 | status_code: 610 | type: string 611 | example: "1" 612 | required: 613 | - info 614 | - msg 615 | - status_code 616 | 617 | RefreshTokenResult: 618 | type: object 619 | properties: 620 | access_token: 621 | type: string 622 | refresh_token: 623 | type: string 624 | required: 625 | - access_token 626 | - refresh_token 627 | 628 | AppSettings: 629 | type: object 630 | properties: 631 | on_app_open_message: 632 | type: string 633 | enum: [BLOCKING] 634 | open_message_type: 635 | type: string 636 | enum: [BLOCKING] 637 | open_message_url: 638 | type: string 639 | format: uri 640 | example: 'https://space.toogoodtogo.com/app-update/android' 641 | countries: 642 | type: array 643 | items: 644 | type: object 645 | properties: 646 | country_iso_code: 647 | type: string 648 | minLength: 2 649 | maxLength: 2 650 | example: 'FR' 651 | terms_url: 652 | type: string 653 | format: uri 654 | example: 'https://toogoodtogo.fr/fr/terms-and-conditions' 655 | privacy_url: 656 | type: string 657 | format: uri 658 | example: 'https://toogoodtogo.fr/fr/privacy-policy' 659 | required: 660 | - country_iso_code 661 | - terms_url 662 | - privacy_url 663 | minItems: 1 664 | purchase_rating_start: 665 | type: string 666 | pattern: '^\d{2}:\d{2}:\d{2}$' 667 | example: '06:00:00' 668 | purchase_rating_end: 669 | type: string 670 | pattern: '^\d{2}:\d{2}:\d{2}$' 671 | example: '23:00:00' 672 | purchase_rating_delay: 673 | type: number 674 | format: double 675 | example: "5400.000000000" 676 | required: 677 | - countries 678 | - purchase_rating_start 679 | - purchase_rating_end 680 | - purchase_rating_delay 681 | 682 | UserSettings: 683 | type: object 684 | properties: 685 | country_iso_code: 686 | type: string 687 | minLength: 2 688 | maxLength: 2 689 | example: 'FR' 690 | phone_country_code_suggestion: 691 | type: string 692 | example: '33' 693 | is_user_email_verified: 694 | type: boolean 695 | terms_url: 696 | type: string 697 | format: uri 698 | example: 'https://toogoodtogo.fr/fr/terms-and-conditions' 699 | privacy_url: 700 | type: string 701 | format: uri 702 | example: 'https://toogoodtogo.fr/fr/privacy-policy' 703 | contact_form_url: 704 | type: string 705 | format: uri 706 | example: 'https://toogoodtogo.fr/fr/support/consumer' 707 | blog_url: 708 | type: string 709 | format: uri 710 | example: 'https://toogoodtogo.fr/fr/blog' 711 | careers_url: 712 | type: string 713 | format: uri 714 | example: 'https://toogoodtogo.org/en/careers' 715 | education_url: 716 | type: string 717 | format: uri 718 | example: 'https://toogoodtogo.fr/fr/movement/education' 719 | instagram_url: 720 | type: string 721 | format: uri 722 | example: 'https://www.instagram.com/toogoodtogo.fr' 723 | store_signup_url: 724 | type: string 725 | format: uri 726 | example: 'https://toogoodtogo.fr/fr/business?webview=1&utm_medium=App&utm_source=App&utm_campaign=' 727 | store_contact_url: 728 | type: string 729 | format: uri 730 | example: 'https://toogoodtogo.fr/fr/support/store' 731 | bound_sw: 732 | type: object 733 | properties: 734 | longitude: 735 | type: number 736 | format: float 737 | example: -1.2345678 738 | latitude: 739 | type: number 740 | format: float 741 | example: 23.45678912 742 | bound_ne: 743 | type: object 744 | properties: 745 | longitude: 746 | type: number 747 | format: float 748 | example: 5.67890123 749 | latitude: 750 | type: number 751 | format: float 752 | example: 45.678901 753 | meals_saved: 754 | type: object 755 | properties: 756 | country_iso_code: 757 | type: string 758 | minLength: 2 759 | maxLength: 2 760 | example: 'FR' 761 | share_url: 762 | type: string 763 | format: uri 764 | example: 'https://share.toogoodtogo.com/mealssaved/b4f64a9e4482f4e7ef449c66e51adc98?locale=fr_FR' 765 | image_url: 766 | type: string 767 | format: uri 768 | example: 'https://store.toogoodtogo.com/web/resource/v2/sharing/mealsSaved/mobile/4/fr_FR/b4f64a9e4482f4e7ef449c66e51adc98' 769 | meals_saved_last_month: 770 | type: integer 771 | example: 915314 772 | month: 773 | type: integer 774 | example: 4 775 | year: 776 | type: integer 777 | example: 2021 778 | bank_transaction_fee: 779 | type: string 780 | my_store_url: 781 | type: string 782 | order_id: 783 | type: string 784 | unrated_order_id: 785 | type: string 786 | panic_message: 787 | type: string 788 | 789 | has_any_vouchers: 790 | type: boolean 791 | can_show_best_before_explainer: 792 | type: boolean 793 | 794 | UserData: 795 | type: object 796 | properties: 797 | user_id: 798 | type: string 799 | example: "123456" 800 | name: 801 | type: string 802 | example: "John Doe" 803 | country_id: 804 | type: string 805 | minLength: 2 806 | maxLength: 2 807 | example: 'FR' 808 | email: 809 | type: string 810 | format: email 811 | example: 'john.doe@dev.local' 812 | phone_country_code: 813 | type: string 814 | example: '33' 815 | phone_number: 816 | type: string 817 | example: '612345678' 818 | role: # Not used in the mobile app 819 | type: string 820 | enum: [CONSUMER] 821 | is_partner: 822 | type: boolean 823 | newsletter_opt_in: 824 | type: boolean 825 | push_notifications_opt_in: 826 | type: boolean 827 | required: 828 | - user_id 829 | - name 830 | - phone_country_code 831 | - phone_number 832 | - newsletter_opt_in 833 | - push_notifications_opt_in 834 | 835 | Order: 836 | type: object 837 | properties: 838 | cancel_until: 839 | type: string 840 | confirmation_email_sent_to: 841 | type: string 842 | food_handling_instructions: 843 | type: string 844 | buffet_instructions: 845 | type: string 846 | can_user_supply_packaging: 847 | type: boolean 848 | packaging_option: 849 | type: string 850 | is_rated: 851 | type: boolean 852 | item_collection_info: 853 | type: string 854 | item_cover_image: 855 | type: string 856 | item_id: 857 | type: integer 858 | item_logo: 859 | type: string 860 | item_name: 861 | type: string 862 | pickup_interval: 863 | type: object 864 | properties: 865 | start: 866 | type: string 867 | end: 868 | type: string 869 | pickup_location: 870 | type: string 871 | price: 872 | type: string 873 | price_excluding_taxes: 874 | type: string 875 | price_including_taxes: 876 | type: string 877 | sales_taxes: 878 | type: string 879 | total_applied_taxes: 880 | type: string 881 | quantity: 882 | type: integer 883 | overall_rating: 884 | type: string 885 | order_id: 886 | type: integer 887 | redeem_interval: 888 | type: string 889 | order_state: 890 | type: string 891 | enum: [ACTIVE, REDEEMED, REFUNDED_OR_CANCELLED, UNREDEEMED, NOT_COLLECTED] 892 | store_branch: 893 | type: string 894 | store_id: 895 | type: integer 896 | store_logo: 897 | type: string 898 | store_name: 899 | type: string 900 | time_of_purchase: 901 | type: string 902 | format: date-time 903 | would_buy_again: 904 | type: boolean 905 | is_buffet: 906 | type: boolean 907 | can_show_best_before_explainer: 908 | type: boolean 909 | needsSync: 910 | type: boolean 911 | hasCollectionTimeChanged: 912 | type: boolean 913 | hasCollectionStateChanged: 914 | type: boolean 915 | 916 | ListOrders: 917 | type: object 918 | properties: 919 | current_time: 920 | type: string 921 | format: date-time 922 | example: "2021-06-01T00:24:58.768422Z" 923 | has_more: 924 | type: boolean 925 | orders: 926 | type: array 927 | items: 928 | $ref: '#/components/schemas/Order' 929 | required: 930 | - current_time 931 | - has_more 932 | - orders 933 | 934 | Voucher: 935 | type: object 936 | properties: 937 | id: 938 | type: string 939 | example: '1234' 940 | name: 941 | type: string 942 | state: 943 | type: string 944 | enum: [PENDING, ACTIVE, USED, EXPIRED] 945 | required: 946 | - id 947 | - name 948 | - state 949 | 950 | ListUserVoucher: 951 | type: object 952 | properties: 953 | vouchers: 954 | type: array 955 | items: 956 | $ref: '#/components/schemas/Voucher' 957 | 958 | StartupResponse: 959 | type: object 960 | properties: 961 | user: 962 | $ref: '#/components/schemas/UserData' 963 | app_settings: 964 | $ref: '#/components/schemas/AppSettings' 965 | user_settings: 966 | $ref: '#/components/schemas/UserSettings' 967 | orders: 968 | $ref: '#/components/schemas/ListOrders' 969 | vouchers: 970 | $ref: '#/components/schemas/ListUserVoucher' 971 | 972 | LoginResponse: 973 | type: object 974 | properties: 975 | access_token: 976 | type: string 977 | refresh_token: 978 | type: string 979 | startup_data: 980 | $ref: '#/components/schemas/StartupResponse' 981 | user_count: 982 | type: string 983 | required: 984 | - access_token 985 | - refresh_token 986 | - startup_data 987 | 988 | UnlockHiddenStoreResponse: 989 | type: object 990 | properties: 991 | state: 992 | type: string 993 | enum: [OK, CODE_INVALID, ALREADY_UNLOCKED] 994 | required: 995 | - state 996 | --------------------------------------------------------------------------------