Skip to content

External API Consumption Reference

This document catalogs every external HTTP call made by the sap-devs CLI, grouped by service. Each entry lists the endpoint, HTTP method, response format, parsing approach, timeout, authentication, and fragility assessment.

All calls use Go's net/http standard library directly (no third-party HTTP client wrappers).


Fragility Legend

RatingMeaning
LowStable JSON API with versioned contract; breakage is unlikely and detectable
MediumXML feed or undocumented API; format changes are plausible and may break parsing
HighHTML scraping, complex protocol, or undocumented internal API; silent breakage likely on upstream changes

1. GitHub API — Tutorial Repositories

Package: internal/tutorials/client.goClient timeout: 30 seconds Authentication: Optional token header via GITHUB_TOOLS_SAP_TOKEN / GH_TOKEN / GITHUB_TOKEN env vars or sap-devs config token

1a. Fetch Repository List

FieldValue
URLhttps://raw.githubusercontent.com/sap-tutorials/Tutorials/master/config/repository-groups.json
MethodGET
Response formatJSON
Parsingjson.Unmarshal into []repoGroupEntry
HeadersUser-Agent, Authorization: token <token> (optional)
Error handlingReturns ErrRepoUnavailable on HTTP 403/404
FragilityLow — static JSON file in a known repo location

1b. Fetch Default Branch

FieldValue
URLhttps://api.github.com/repos/sap-tutorials/{repo}
MethodGET
Response formatJSON
Parsingjson.Unmarshal extracting default_branch field
Error handlingReturns ErrRepoUnavailable on HTTP 403/404
FragilityLow — standard GitHub REST API v3

1c. Fetch Repository Tree

FieldValue
URLhttps://api.github.com/repos/sap-tutorials/{repo}/git/trees/{branch}?recursive=1
MethodGET
Response formatJSON
Parsingjson.Unmarshal into tree struct; filters paths starting with tutorials/ to extract slugs
Error handlingReturns ErrRepoUnavailable on HTTP 403/404
FragilityLow — standard GitHub REST API v3

1d. Fetch Raw Tutorial Markdown

FieldValue
URLhttps://raw.githubusercontent.com/sap-tutorials/{repo}/{branch}/tutorials/{slug}/{slug}.md
MethodGET
Response formatRaw markdown text
ParsingRead as string — no structured parsing
Error handlingReturns ErrRepoUnavailable on HTTP 403/404
FragilityMedium — depends on a tutorials/{slug}/{slug}.md path convention in the sap-tutorials repos

2. GitHub API — Archive Download (Sync)

Package: internal/sync/fetcher.goClient timeout: Default (http.DefaultClient, no explicit timeout) Authentication: Optional token header

FieldValue
URLConfigured per source (official repo archive URL, company repo URL)
MethodGET
Response formatZIP archive
Parsingarchive/zip extraction with top-level directory prefix stripping
HeadersAuthorization: token <token> (optional)
Error handlingDetects auth redirect to /login path; zip-slip guard prevents path traversal
FragilityMedium — relies on GitHub/GitLab archive format convention (single top-level directory)

3. GitHub API — Release Check (Update)

Package: internal/update/checker.goClient timeout: 5 seconds

FieldValue
URLhttps://{host}/api/v3/repos/{owner}/{repo}/releases/latest (GitHub Enterprise)
MethodGET
Response formatJSON
Parsingjson.NewDecoder().Decode() extracting tag_name field
HeadersAccept: application/vnd.github+json, Authorization: Bearer <token> (optional)
Error handlingReturns nil on HTTP 404 (no releases); error on other non-200 codes
FragilityLow — standard GitHub REST API v3

4. GitHub API — Release Asset Download (Update)

Package: internal/update/installer.goClient timeout: 300 seconds (5 minutes) Max body: 100 MB

4a. Checksums Download

FieldValue
URL{repoURL}/releases/download/{tagName}/checksums.txt
MethodGET
Response formatPlain text (<sha256hex> <filename> per line)
ParsingLine-by-line strings.Fields matching asset name
HeadersAuthorization: Bearer <token> (optional)
FragilityLow — GoReleaser-generated format

4b. Archive Download

FieldValue
URL{repoURL}/releases/download/{tagName}/sap-devs_{version}_{os}_{arch}{ext}
MethodGET
Response formatBinary (.tar.gz on Linux/macOS, .zip on Windows)
Parsingarchive/tar + compress/gzip or archive/zip extraction; SHA-256 checksum verification
FragilityLow — GoReleaser-generated naming convention

5. YouTube RSS Feed (Atom)

Package: internal/youtube/youtube.goClient timeout: 10 seconds Max body: 1 MiB Authentication: None

FieldValue
URLhttps://www.youtube.com/feeds/videos.xml?playlist_id={playlistId}
MethodGET
Response formatXML (Atom feed)
Parsingxml.Unmarshal into custom atomFeed/atomEntry structs
Key playlistPL6RpkC85SLQAVBSQXN9522_1jNvPavBgg (SAP Developer News)
FragilityMedium — YouTube's Atom feed is undocumented; format changes would silently break parsing

Consumed by:

  • cmd/news.gonews latest, news list
  • internal/mcpserver/tools_news.go — MCP get_recent_news tool

6. YouTube Data API v3

Package: internal/youtube/apiv3.goClient timeout: 15 seconds Max body: 5 MiB Authentication: API key in URL query parameter (key=)

6a. Playlist Items

FieldValue
URLhttps://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={id}&key={apiKey}
MethodGET
Response formatJSON
Parsingjson.Unmarshal into playlistItemsResponse; paginates via nextPageToken
FragilityLow — versioned Google API

6b. Video Details (Batch Enrichment)

FieldValue
URLhttps://www.googleapis.com/youtube/v3/videos?part=contentDetails,snippet&id={csv-ids}&key={apiKey}
MethodGET
Response formatJSON
Parsingjson.Unmarshal into videosResponse; batched in groups of 50
Error handlingNon-fatal — enrichment failures are skipped; episodes returned without duration/tags
FragilityLow — versioned Google API

7. SAP Learning Platform

Package: internal/learning/Authentication: None

7a. Catalog Download

File: internal/learning/catalog.go

FieldValue
URLhttps://learning.sap.com/service/catalog-download/json
MethodGET
Response formatJSON (large array; ~5.4 MB, ~5,100 items)
Parsingjson.Unmarshal into []catalogItem; filtered to Learning_type == "Learning Journey" (~351 items)
Client timeout30 seconds
Caching7-day TTL at ~/.cache/sap-devs/learning/index.json
FragilityMedium — undocumented API; field names or response structure could change

7b. Search API

File: internal/learning/api.go

FieldValue
URLhttps://learning.sap.com/service/learning/search/getCards(types=...,filters=...,sort='',limit=N,page=1)
MethodGET
Response formatJSON
Parsingjson.Unmarshal into searchResponse struct
Client timeout15 seconds
Query paramstypes (JSON array), filters (JSON object with locale + query), limit, page
Caching1-hour TTL for search results
FragilityMedium — undocumented internal API; function-import-style URL pattern

8. SAP Discovery Center (OData V2)

Package: internal/discovery/client.goBase URL: https://discovery-center.cloud.sapClient timeout: 15 seconds Authentication: CSRF token (fetched per session)

This is the most complex external integration. Two distinct OData services are consumed:

8a. CSRF Token Fetch

FieldValue
URLhttps://discovery-center.cloud.sap/platformx/
MethodHEAD
Headers sentx-csrf-token: Fetch, x-requested-with: XMLHttpRequest
ResponseCSRF token extracted from x-csrf-token response header
FragilityHigh — undocumented; CSRF mechanism could change without notice

8b. Batch Requests (/platformx/$batch)

All /platformx/ function imports are called via OData $batch:

FieldValue
URLhttps://discovery-center.cloud.sap/platformx/$batch
MethodPOST
Content-Typemultipart/mixed;boundary=batch_{UnixNano}
Headersx-csrf-token, DataServiceVersion: 2.0, MaxDataServiceVersion: 2.0, x-requested-with: XMLHttpRequest
Response formatMultipart MIME wrapping JSON
ParsingCustom extractBatchJSON() — finds first {...} via brace-depth counting, unwraps {"d":{"FunctionName":"<double-encoded-json>"&#125;&#125; envelope

Function imports called via batch:

FunctionParametersReturns
GetMissionCatalogContentV2username=''[]MissionCatalogGroup
GetViewFuzzySearchesCustomV3searchString, filterCategory, filterType, filterProduct, filterLoB, filterIndustry, filterFocusTags, filterPartners, top[]Mission
GetProductsCategoriesversion='1'Categories
GetApplicationFocusTagsIndustryLobversion='1'Facets
GetGuidanceFrameworkTree(none)[]GuidanceNode
GetGuidanceFrameworkContentByIdid='<guid>'string (HTML content)

Fragility: High — complex multipart protocol with double-JSON-encoding quirk, custom brace-counting parser, and undocumented function imports. Any protocol or response format change breaks silently.

8c. Service Catalog (Direct GET)

FieldValue
URLhttps://discovery-center.cloud.sap/servicecatalog/ServiceDetailss?$format=json&$select=Id,Name,ShortName,Category,ShortDescription,LicenseModelType,IsDeprecatedService
MethodGET
HeadersAccept: application/json, DataServiceVersion: 2.0, MaxDataServiceVersion: 2.0
Response formatJSON (OData V2 {"d":{"results":[...]&#125;&#125; envelope)
Parsingjson.Unmarshal into standard OData wrapper
FragilityMedium — standard OData but undocumented; field set could change

Package: internal/tutorials/enrichment.goClient timeout: 10 seconds Authentication: None

FieldValue
URLhttps://developers.sap.com/bin/sapdx/v3/solr/search?json={payload}
MethodGET
Query payload{"rows":"2000","start":0,"searchField":"","pagePath":"/content/developers/website/languages/en/tutorial-navigator","language":"en_us","addDefaultLanguage":true,"filters":[]}
Response formatJSON
Parsingjson.Unmarshal extracting result[].publicUrl and result[].featured
HeadersUser-Agent, Accept: application/json
Error handlingFully non-fatal — returns original index unchanged on any error (HTTP, parse, network)
FragilityHigh — undocumented internal SAP CMS endpoint; URL path, query format, and response schema could all change without notice. Failures are silent (returns original data unchanged).

10. Khoros Community API (SAP Community Events)

Package: internal/events/khoros.goClient timeout: Configurable (passed as parameter) Max body: 1 MiB Authentication: None

FieldValue
URLhttps://groups.community.sap.com/api/2.0/search?q={liql-query}
MethodGET
Query formatLiQL (Lithium Query Language): SELECT id,subject,view_href,occasion_data.* FROM messages WHERE board.id='{boardID}'
Response formatJSON
Parsingjson.Unmarshal into khorosResponse; checks status == "success"; filters out non-occasion items, /ec-p/ links, and past events
HeadersUser-Agent: Mozilla/5.0 (compatible; sap-devs/1.0)
FragilityMedium — Khoros v2 API is documented but SAP could change board IDs, occasion data fields, or migrate platforms

11. RSS Feed Fetching (Generic Events)

Package: internal/events/rss.goClient timeout: Configurable (passed as parameter) Max body: 1 MiB Authentication: None

FieldValue
URLConfigured per event type in pack YAML
MethodGET
Response formatXML (RSS 2.0)
Parsingxml.Unmarshal into rssFeed; extracts title, link, pubDate; generates ID via SHA-256 of link
HeadersUser-Agent: Mozilla/5.0 (compatible; sap-devs/1.0)
FragilityMedium — depends on upstream RSS feed availability and standard RSS 2.0 format

12. SAP Community Blog Posts

Package: internal/community/community.goClient timeout: 10 seconds Authentication: None

12a. Blog RSS Feed

FieldValue
URLhttps://community.sap.com/khhcw49343/rss/board?board.id=developer-news
MethodGET
Response formatXML (RSS 2.0)
Parsingxml.Unmarshal into rssFeed struct
Max body1 MiB
HeadersUser-Agent: Mozilla/5.0 (compatible; sap-devs/1.0)
FragilityMedium — Khoros API path; the previous vanity URL (/t5/.../rss) broke when SAP Community changed frontend routing

12b. Blog Post Content Fetch (HTML Scraping)

FieldValue
URLIndividual blog post URLs from the RSS feed
MethodGET
Response formatHTML
ParsingFull HTML page fetched and converted to Markdown via github.com/JohannesKaufmann/html-to-markdown/v2
Max body4 MiB
HeadersUser-Agent: Mozilla/5.0 (compatible; sap-devs/1.0)
FragilityHighHTML scraping. No DOM scoping or CSS selector is applied; the entire page body is converted. Any change to the SAP Community page template (layout, wrapper divs, navigation HTML) will pollute the markdown output with non-content elements. There is no validation of output quality.

13. Dynamic Content Fetch (Sync Markers)

Package: internal/sync/marker.go, internal/sync/convert.goClient timeout: 10 seconds (default) Max body: 1 MiB Authentication: None

Content authors embed <!-- sync:fetch ... --> HTML comment markers in context.md files. During sap-devs sync, each marker triggers an HTTP fetch of the specified URL.

FieldValue
URLAuthor-defined (any URL specified in marker attributes)
MethodGET
Response formatHTML, plain text, or raw (configurable via format attribute)
ParsingThree-stage pipeline: (1) html.Parse via golang.org/x/net/html, (2) optional CSS selector scoping via github.com/andybalholm/cascadia, (3) conversion via html-to-markdown or text extraction

Marker Syntax

html
<!-- sync:fetch url="https://..." format="markdown" selector=".content" max_lines="50" max_tokens="100" ttl_hours="24" label="Release notes" -->
AttributeRequiredDescription
urlYesURL to fetch
formatNoraw, text, or markdown (default: markdown)
selectorNoCSS selector to scope HTML extraction
max_linesNoTruncate output to N lines
max_tokensNoTruncate output to ~N tokens (4 chars/token approximation)
ttl_hoursNoCache TTL override
labelNoHuman-readable label for progress UI

Fragility Assessment: High (when format is markdown or text with a selector)

This is the most fragile pattern in the codebase because it chains multiple failure-prone steps:

  1. CSS selector depends on remote page structure — if the target site changes its DOM, the selector silently matches nothing and falls back to the full page body (logged as a warning but sync continues)
  2. HTML-to-Markdown conversion depends on the html-to-markdown library handling arbitrary HTML correctly
  3. Silent degradation — a broken selector produces garbage content that gets injected into AI tool context without validation

When format is raw, fragility is Low (just a plain HTTP GET).


14. IP Geolocation

Package: cmd/config_location.goClient timeout: 3 seconds Authentication: None

FieldValue
URLhttp://ip-api.com/json (note: plain HTTP, not HTTPS)
MethodGET
Response formatJSON
Parsingjson.NewDecoder().Decode() extracting city and country fields
Error handlingFully non-fatal; prints error message and returns empty string
PrivacyUser confirmation prompt required before the call is made
FragilityLow — simple, well-documented public API; but uses plain HTTP (no TLS)

Summary

By Fragility

RatingEndpoints
HighDiscovery Center batch protocol, SAP Developers Solr search, Community blog HTML scraping, Sync marker HTML+selector pipeline, Discovery Center CSRF
MediumTutorial raw markdown path convention, Sync archive format, Learning catalog/search APIs, Khoros Community API, YouTube RSS feed, Community blog RSS URL, Service catalog OData, Generic RSS feeds
LowGitHub REST API (repos, trees, branches, releases), YouTube Data API v3, IP geolocation, GoReleaser asset downloads

By Response Format

FormatEndpoints
JSONGitHub API, YouTube API v3, SAP Learning, Discovery Center (wrapped), Khoros, Solr search, IP geolocation, Release check
XMLYouTube RSS (Atom), Community blog RSS, Generic event RSS
HTMLCommunity blog posts, Sync marker fetches (with format=markdown/text)
BinarySync archive (ZIP), Update asset (TAR.GZ/ZIP)
Plain textTutorial markdown, Checksums, Sync marker fetches (with format=raw)

By Authentication

MethodEndpoints
NoneYouTube RSS, SAP Learning, Khoros, Solr, Community, IP geolocation, Sync markers
Bearer/token header (optional)GitHub API, Sync archive, Release check/download
API key in URLYouTube Data API v3
CSRF token (session)Discovery Center batch

Timeout Summary

TimeoutEndpoints
3sIP geolocation
5sRelease check
10sYouTube RSS, Community blog, Solr search, Sync markers
15sYouTube API v3, Learning search, Discovery Center
30sTutorial GitHub client, Learning catalog
300sRelease asset download
DefaultSync archive (http.DefaultClient)