R/axprism.R

Defines functions axprism_bulk_financials axprism_webhooks_events axprism_webhooks_delete axprism_webhooks_create axprism_webhooks_list axprism_idx_financials axprism_idx_symbols axprism_bursa_shariah axprism_bursa_symbols axprism_tadawul_financials axprism_tadawul_symbols .axprism_exchange_get axprism_text_search axprism_disclosures_recent axprism_disclosures_search axprism_fx_rates axprism_calendar axprism_holders_13f axprism_insiders axprism_news axprism_estimates axprism_prices axprism_portfolio axprism_purification axprism_compliance_point_in_time axprism_compliance_trend axprism_compliance_multi axprism_compliance axprism_screener axprism_segments axprism_concept_history axprism_facts axprism_compare axprism_batch_metric axprism_ttm axprism_financials axprism_exchanges axprism_symbols axprism_market_cap axprism_profile axprism_health axprism_rulesets axprism_pricing axprism_usage axprism_me .axprism_delete .axprism_post .axprism_get axprism_request axprism_client .axprism_compact `%||%`

Documented in axprism_batch_metric axprism_bulk_financials axprism_bursa_shariah axprism_bursa_symbols axprism_calendar axprism_client axprism_compare axprism_compliance axprism_compliance_multi axprism_compliance_point_in_time axprism_compliance_trend axprism_concept_history axprism_disclosures_recent axprism_disclosures_search axprism_estimates axprism_exchanges axprism_facts axprism_financials axprism_fx_rates axprism_health axprism_holders_13f axprism_idx_financials axprism_idx_symbols axprism_insiders axprism_market_cap axprism_me axprism_news axprism_portfolio axprism_prices axprism_pricing axprism_profile axprism_purification axprism_request axprism_rulesets axprism_screener axprism_segments axprism_symbols axprism_tadawul_financials axprism_tadawul_symbols axprism_text_search axprism_ttm axprism_usage axprism_webhooks_create axprism_webhooks_delete axprism_webhooks_events axprism_webhooks_list

#' AxPrism API client for R
#'
#' Official R client for the AxPrism Institutional XBRL Platform
#' (\url{https://axprism.com}). Authenticates with the \code{X-API-Key} header,
#' retries with exponential backoff on rate limits (429) and transient 5xx
#' errors, and exposes typed convenience functions plus a generic
#' \code{\link{axprism_request}} escape hatch covering every endpoint.
#'
#' A public, read-only demo key is available for testing:
#' \code{axmd_demo_try_axprism_2024}.
#'
#' @keywords internal
"_PACKAGE"

`%||%` <- function(a, b) if (is.null(a) || length(a) == 0 || (is.character(a) && !nzchar(a))) b else a

# Drop NULL entries from a (query) list. Pure helper, used for URL query
# building; kept separate so it can be unit-tested without network access.
.axprism_compact <- function(x) Filter(Negate(is.null), x)

#' Create an AxPrism API client
#'
#' @param api_key Your AxPrism API key (\code{axmd_live_...}). Defaults to the
#'   \code{AXPRISM_API_KEY} environment variable.
#' @param base_url API base URL. Defaults to \code{https://axprism.com}.
#' @param timeout_s Request timeout in seconds (default 30).
#' @param max_retries Max retries on 429 / 5xx (default 3).
#' @param backoff_s Base seconds for exponential backoff (default 0.5).
#' @return An object of class \code{axprism_client}.
#' @examples
#' # Constructing a client is offline and requires no network access.
#' client <- axprism_client(api_key = "demo-key")
#' inherits(client, "axprism_client")
#' client$base_url
#'
#' # Trailing slashes in the base URL are normalized away.
#' axprism_client(api_key = "k", base_url = "https://axprism.com/")$base_url
#'
#' \dontrun{
#' # A live call additionally needs a real API key and network access.
#' client <- axprism_client(api_key = "axmd_demo_try_axprism_2024")
#' axprism_compliance(client, "AAPL")
#' }
#' @export
axprism_client <- function(api_key = NULL,
                           base_url = "https://axprism.com",
                           timeout_s = 30,
                           max_retries = 3,
                           backoff_s = 0.5) {
  key <- api_key %||% Sys.getenv("AXPRISM_API_KEY")
  if (!nzchar(key)) {
    stop("api_key is required. Get one at https://axprism.com/keys, or set AXPRISM_API_KEY.")
  }
  structure(
    list(
      api_key = key,
      base_url = sub("/+$", "", base_url),
      timeout_s = timeout_s,
      max_retries = max_retries,
      backoff_s = backoff_s
    ),
    class = "axprism_client"
  )
}

#' Make a raw request against the AxPrism API
#'
#' Generic escape hatch for any of the API's 165+ endpoints. Returns parsed
#' JSON (a list). Honors retries/backoff and raises informative errors.
#'
#' @param client An \code{axprism_client}.
#' @param method HTTP method: "GET", "POST", or "DELETE".
#' @param path Endpoint path beginning with \code{/api/v1/...}.
#' @param query Named list of query parameters (NULLs dropped).
#' @param body Named list sent as a JSON request body (for POST).
#' @return Parsed response (named list).
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' # Requires network access and a valid API key.
#' axprism_request(client, "GET", "/api/v1/health")
#' }
#' @export
axprism_request <- function(client, method, path, query = list(), body = NULL) {
  stopifnot(inherits(client, "axprism_client"))
  if (!requireNamespace("httr", quietly = TRUE)) stop("install.packages('httr')")
  if (!requireNamespace("jsonlite", quietly = TRUE)) stop("install.packages('jsonlite')")

  url <- paste0(client$base_url, path)
  query <- .axprism_compact(query)
  headers <- httr::add_headers(
    `X-API-Key` = client$api_key,
    Accept = "application/json",
    `User-Agent` = "axprism-r/0.2.0"
  )

  attempt <- 0
  repeat {
    resp <- switch(
      method,
      GET = httr::GET(url, query = query, headers, httr::timeout(client$timeout_s)),
      POST = httr::POST(url, query = query, body = body, encode = "json", headers, httr::timeout(client$timeout_s)),
      DELETE = httr::DELETE(url, query = query, headers, httr::timeout(client$timeout_s)),
      stop(sprintf("unsupported method: %s", method))
    )
    status <- httr::status_code(resp)

    if ((status == 429 || status >= 500) && attempt < client$max_retries) {
      retry_after <- suppressWarnings(as.numeric(httr::headers(resp)[["retry-after"]]))
      wait <- if (!is.na(retry_after) && retry_after > 0) {
        min(retry_after, 60)
      } else {
        client$backoff_s * (2^attempt)
      }
      Sys.sleep(wait)
      attempt <- attempt + 1
      next
    }

    raw <- httr::content(resp, as = "text", encoding = "UTF-8")
    parsed <- tryCatch(
      jsonlite::fromJSON(raw, simplifyVector = TRUE),
      error = function(e) list(raw = raw)
    )

    if (status >= 400) {
      msg <- if (is.list(parsed)) (parsed$message %||% parsed$error %||% parsed$detail %||% raw) else raw
      stop(sprintf("AxPrism API error %d: %s", status, msg), call. = FALSE)
    }
    return(parsed)
  }
}

.axprism_get <- function(client, path, query = list()) axprism_request(client, "GET", path, query = query)
.axprism_post <- function(client, path, body = NULL, query = list()) axprism_request(client, "POST", path, query = query, body = body)
.axprism_delete <- function(client, path) axprism_request(client, "DELETE", path)

# ---- Account ---------------------------------------------------------------

#' Account info for the current API key
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_me(client)
#' }
#' @export
axprism_me <- function(client) .axprism_get(client, "/api/v1/me")

#' Request usage analytics
#' @param client An \code{axprism_client}.
#' @param days Look-back window in days (default 30).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_usage(client, days = 30)
#' }
#' @export
axprism_usage <- function(client, days = 30) .axprism_get(client, "/api/v1/me/usage", list(days = days))

#' Subscription pricing and entitlements
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_pricing(client)
#' }
#' @export
axprism_pricing <- function(client) .axprism_get(client, "/api/v1/pricing")

#' List supported Shariah compliance rulesets
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_rulesets(client)
#' }
#' @export
axprism_rulesets <- function(client) .axprism_get(client, "/api/v1/rulesets")

#' Public health check
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_health(client)
#' }
#' @export
axprism_health <- function(client) .axprism_get(client, "/api/v1/health")

# ---- Company / symbols -----------------------------------------------------

#' Company profile, CIK, SIC, exchange, and Shariah activity screen
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol, e.g. "AAPL".
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_profile(client, "AAPL")
#' }
#' @export
axprism_profile <- function(client, ticker) .axprism_get(client, paste0("/api/v1/profile/", toupper(ticker)))

#' Rolling-average market capitalization (USD)
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param months Averaging window in months (default 36).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_market_cap(client, "AAPL")
#' }
#' @export
axprism_market_cap <- function(client, ticker, months = 36) {
  .axprism_get(client, paste0("/api/v1/market-cap/", toupper(ticker)), list(months = months))
}

#' Symbol search / suggestions
#' @param client An \code{axprism_client}.
#' @param query Search string.
#' @param limit Max results (default 20).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_symbols(client, "apple")
#' }
#' @export
axprism_symbols <- function(client, query = "", limit = 20) {
  .axprism_get(client, "/api/v1/symbols", list(q = query, limit = limit))
}

#' List supported exchanges
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_exchanges(client)
#' }
#' @export
axprism_exchanges <- function(client) .axprism_get(client, "/api/v1/exchanges")

# ---- Financials ------------------------------------------------------------

#' Normalized financial statements (IS / BS / CF / ALL)
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param statement "IS", "BS", "CF", or "ALL".
#' @param period "annual", "quarterly", or "ttm".
#' @param currency "NATIVE", "USD", or any ISO 4217 code.
#' @param history "latest" or "all".
#' @param as_reported Return raw un-normalized XBRL when TRUE.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_financials(client, "AAPL", statement = "IS")
#' }
#' @export
axprism_financials <- function(client, ticker, statement = "IS", period = "annual",
                               currency = "NATIVE", history = "latest", as_reported = FALSE) {
  .axprism_get(client, paste0("/api/v1/financials/", toupper(ticker)),
               list(statement = statement, period = period, currency = currency,
                    history = history, as_reported = if (as_reported) "1" else "0"))
}

#' Trailing twelve months income statement
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param currency Reporting currency (default "NATIVE").
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_ttm(client, "AAPL")
#' }
#' @export
axprism_ttm <- function(client, ticker, currency = "NATIVE") {
  .axprism_get(client, paste0("/api/v1/financials/", toupper(ticker), "/ttm"), list(currency = currency))
}

#' One metric across multiple tickers (max 20)
#' @param client An \code{axprism_client}.
#' @param tickers Character vector of tickers.
#' @param metric Metric key, e.g. "ax:Revenue".
#' @param period "annual" or "quarterly".
#' @param currency Reporting currency (default "USD").
#' @param years Number of years (default 5).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_batch_metric(client, c("AAPL", "MSFT"), "ax:Revenue")
#' }
#' @export
axprism_batch_metric <- function(client, tickers, metric, period = "annual", currency = "USD", years = 5) {
  .axprism_get(client, "/api/v1/financials/batch",
               list(tickers = paste(toupper(tickers), collapse = ","), metric = metric,
                    period = period, currency = currency, years = years))
}

#' Compare a metric across companies over time
#' @param client An \code{axprism_client}.
#' @param tickers Character vector of tickers.
#' @param metric Metric key (default "ax:Revenue").
#' @param period "annual" or "quarterly".
#' @param limit_periods Number of periods (default 8).
#' @param currency Reporting currency (default "USD").
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_compare(client, c("AAPL", "MSFT"))
#' }
#' @export
axprism_compare <- function(client, tickers, metric = "ax:Revenue", period = "annual",
                            limit_periods = 8, currency = "USD") {
  .axprism_get(client, "/api/v1/compare",
               list(tickers = paste(toupper(tickers), collapse = ","), metric = metric,
                    period = period, limit_periods = limit_periods, currency = currency))
}

#' Raw XBRL facts for a company
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param concept Optional XBRL concept filter.
#' @param limit Max facts (default 500).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_facts(client, "AAPL")
#' }
#' @export
axprism_facts <- function(client, ticker, concept = NULL, limit = 500) {
  .axprism_get(client, paste0("/api/v1/facts/", toupper(ticker)), list(concept = concept, limit = limit))
}

#' Historical values for a single XBRL concept
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param concept XBRL concept tag.
#' @param limit Max periods (default 20).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_concept_history(client, "AAPL", "Revenues")
#' }
#' @export
axprism_concept_history <- function(client, ticker, concept, limit = 20) {
  .axprism_get(client, sprintf("/api/v1/concepts/%s/%s/history", toupper(ticker), concept), list(limit = limit))
}

#' Reported business / geographic segments
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param limit Max filings (default 1).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_segments(client, "AAPL")
#' }
#' @export
axprism_segments <- function(client, ticker, limit = 1) {
  .axprism_get(client, paste0("/api/v1/segments/", toupper(ticker)), list(limit = limit))
}

#' Screen tickers by compliance and fundamentals (max 50)
#' @param client An \code{axprism_client}.
#' @param tickers Character vector of tickers.
#' @param verdict Optional verdict filter ("halal"/"haram"/"inconclusive").
#' @param ruleset Compliance ruleset (default "aaoifi").
#' @param period "annual" or "quarterly".
#' @param debt_ratio_max Optional max debt ratio.
#' @param income_ratio_max Optional max non-permissible income ratio.
#' @param market_cap_min Optional minimum market cap (USD).
#' @param market_cap_max Optional maximum market cap (USD).
#' @param limit Max results (default 50).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_screener(client, c("AAPL", "MSFT"))
#' }
#' @export
axprism_screener <- function(client, tickers, verdict = NULL, ruleset = "aaoifi", period = "annual",
                             debt_ratio_max = NULL, income_ratio_max = NULL,
                             market_cap_min = NULL, market_cap_max = NULL, limit = 50) {
  .axprism_get(client, "/api/v1/screener",
               list(tickers = paste(toupper(tickers), collapse = ","), verdict = verdict,
                    ruleset = ruleset, period = period, debt_ratio_max = debt_ratio_max,
                    income_ratio_max = income_ratio_max, market_cap_min = market_cap_min,
                    market_cap_max = market_cap_max, limit = limit))
}

# ---- Compliance ------------------------------------------------------------

#' Shariah compliance verdict for one ticker
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param standard "aaoifi", "msci", "dji", "ftse", or "saudi".
#' @param period "annual" or "quarterly".
#' @param as_of Optional ISO date for point-in-time context.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_compliance(client, "AAPL")
#' }
#' @export
axprism_compliance <- function(client, ticker, standard = "aaoifi", period = "annual", as_of = NULL) {
  .axprism_get(client, paste0("/api/v1/compliance/", toupper(ticker)),
               list(standard = standard, period = period, as_of = as_of))
}

#' Run all supported Shariah standards at once
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param period "annual" or "quarterly".
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_compliance_multi(client, "AAPL")
#' }
#' @export
axprism_compliance_multi <- function(client, ticker, period = "annual") {
  .axprism_get(client, paste0("/api/v1/compliance/", toupper(ticker), "/multi"), list(period = period))
}

#' Compliance ratio trend over N periods
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param periods Number of periods (default 8).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_compliance_trend(client, "AAPL")
#' }
#' @export
axprism_compliance_trend <- function(client, ticker, periods = 8) {
  .axprism_get(client, paste0("/api/v1/compliance/", toupper(ticker), "/trend"), list(periods = periods))
}

#' Historical point-in-time compliance verdict
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param as_of ISO date ("YYYY-MM-DD").
#' @param standard Compliance standard (default "aaoifi").
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_compliance_point_in_time(client, "AAPL", as_of = "2023-12-31")
#' }
#' @export
axprism_compliance_point_in_time <- function(client, ticker, as_of, standard = "aaoifi") {
  .axprism_get(client, paste0("/api/v1/compliance/", toupper(ticker), "/point-in-time"),
               list(as_of = as_of, standard = standard))
}

#' Purification amount for a single holding (USD)
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param shares_held Number of shares held.
#' @param dividend_per_share Optional dividend per share (USD).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_purification(client, "AAPL", shares_held = 100)
#' }
#' @export
axprism_purification <- function(client, ticker, shares_held, dividend_per_share = NULL) {
  .axprism_get(client, paste0("/api/v1/compliance/", toupper(ticker), "/purification"),
               list(shares_held = shares_held, dividend_per_share = dividend_per_share))
}

#' Screen a full portfolio for Shariah compliance and purification
#' @param client An \code{axprism_client}.
#' @param items List of holdings (each a list with \code{ticker}, optional
#'   \code{weight}, \code{shares}, \code{dividend_per_share}).
#' @param ruleset Compliance ruleset (default "aaoifi").
#' @param period "annual" or "quarterly".
#' @param include_purification Compute purification when TRUE.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_portfolio(client, list(list(ticker = "AAPL", shares = 100)))
#' }
#' @export
axprism_portfolio <- function(client, items, ruleset = "aaoifi", period = "annual", include_purification = TRUE) {
  .axprism_post(client, "/api/v1/compliance/portfolio",
                body = list(items = items, ruleset = ruleset, period = period,
                            include_purification = include_purification))
}

# ---- Market data -----------------------------------------------------------

#' OHLCV price history
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param start Optional start date (ISO).
#' @param end Optional end date (ISO).
#' @param limit Max bars (default 252).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_prices(client, "AAPL")
#' }
#' @export
axprism_prices <- function(client, ticker, start = NULL, end = NULL, limit = 252) {
  .axprism_get(client, paste0("/api/v1/prices/", toupper(ticker)), list(start = start, end = end, limit = limit))
}

#' Analyst consensus, price targets, earnings, and dividends
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_estimates(client, "AAPL")
#' }
#' @export
axprism_estimates <- function(client, ticker) .axprism_get(client, paste0("/api/v1/estimates/", toupper(ticker)))

#' Recent news for a ticker
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param limit Max items (default 25).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_news(client, "AAPL")
#' }
#' @export
axprism_news <- function(client, ticker, limit = 25) {
  .axprism_get(client, "/api/v1/news", list(ticker = toupper(ticker), limit = limit))
}

#' Insider (Form 3/4/5) transactions
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param limit Max records (default 25).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_insiders(client, "AAPL")
#' }
#' @export
axprism_insiders <- function(client, ticker, limit = 25) {
  .axprism_get(client, paste0("/api/v1/insiders/", toupper(ticker)), list(limit = limit))
}

#' Institutional 13-F holders by CIK
#' @param client An \code{axprism_client}.
#' @param cik Central Index Key.
#' @param limit Max records (default 1).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_holders_13f(client, "0000320193")
#' }
#' @export
axprism_holders_13f <- function(client, cik, limit = 1) {
  .axprism_get(client, paste0("/api/v1/holders/", cik), list(limit = limit))
}

#' Earnings / events calendar for a ticker
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_calendar(client, "AAPL")
#' }
#' @export
axprism_calendar <- function(client, ticker) .axprism_get(client, "/api/v1/calendar", list(ticker = toupper(ticker)))

#' FX rates relative to a base currency
#' @param client An \code{axprism_client}.
#' @param base Base currency (default "USD").
#' @param symbols Optional character vector of target currencies.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_fx_rates(client, "USD", c("EUR", "GBP"))
#' }
#' @export
axprism_fx_rates <- function(client, base = "USD", symbols = NULL) {
  q <- list(base = base)
  if (!is.null(symbols)) q$symbols <- paste(symbols, collapse = ",")
  .axprism_get(client, "/api/v1/fx-rates", q)
}

# ---- Disclosures / text ----------------------------------------------------

#' Full-text search across disclosures (SEC EDGAR, ESEF, etc.)
#' @param client An \code{axprism_client}.
#' @param q Query string.
#' @param ticker Optional ticker filter.
#' @param forms Optional character vector of form types.
#' @param limit Max hits (default 20).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_disclosures_search(client, "revenue recognition")
#' }
#' @export
axprism_disclosures_search <- function(client, q, ticker = NULL, forms = NULL, limit = 20) {
  .axprism_get(client, "/api/v1/disclosures/search",
               list(q = q, ticker = ticker,
                    forms = if (!is.null(forms)) paste(forms, collapse = ",") else NULL, limit = limit))
}

#' Recent filings for a ticker
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param limit Max filings (default 20).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_disclosures_recent(client, "AAPL")
#' }
#' @export
axprism_disclosures_recent <- function(client, ticker, limit = 20) {
  .axprism_get(client, paste0("/api/v1/disclosures/", toupper(ticker), "/recent"), list(limit = limit))
}

#' Search indexed filing text blocks
#' @param client An \code{axprism_client}.
#' @param q Query string.
#' @param ticker Optional ticker filter.
#' @param form Optional form-type filter.
#' @param limit Max hits (default 20).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_text_search(client, "climate risk")
#' }
#' @export
axprism_text_search <- function(client, q, ticker = NULL, form = NULL, limit = 20) {
  .axprism_get(client, "/api/v1/text/search", list(q = q, ticker = ticker, form = form, limit = limit))
}

# ---- International exchanges ------------------------------------------------

.axprism_exchange_get <- function(client, exchange, suffix, query = list()) {
  .axprism_get(client, paste0("/api/v1/", exchange, suffix), query)
}

#' Tadawul (Saudi) symbols
#' @param client An \code{axprism_client}.
#' @param sector Optional sector filter.
#' @param limit Max symbols (default 200).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_tadawul_symbols(client)
#' }
#' @export
axprism_tadawul_symbols <- function(client, sector = NULL, limit = 200) {
  .axprism_exchange_get(client, "tadawul", "/symbols", list(sector = sector, limit = limit))
}

#' Tadawul company financials
#' @param client An \code{axprism_client}.
#' @param symbol Tadawul symbol (e.g. "2222").
#' @param period "annual" or "quarterly".
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_tadawul_financials(client, "2222")
#' }
#' @export
axprism_tadawul_financials <- function(client, symbol, period = "annual") {
  .axprism_exchange_get(client, "tadawul", paste0("/financials/", symbol), list(period = period))
}

#' Bursa Malaysia symbols
#' @param client An \code{axprism_client}.
#' @param limit Max symbols (default 200).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_bursa_symbols(client)
#' }
#' @export
axprism_bursa_symbols <- function(client, limit = 200) {
  .axprism_exchange_get(client, "bursa", "/symbols", list(limit = limit))
}

#' Bursa Malaysia Shariah-compliant list
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_bursa_shariah(client)
#' }
#' @export
axprism_bursa_shariah <- function(client) .axprism_exchange_get(client, "bursa", "/shariah")

#' Indonesia Stock Exchange (IDX) symbols
#' @param client An \code{axprism_client}.
#' @param limit Max symbols (default 200).
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_idx_symbols(client)
#' }
#' @export
axprism_idx_symbols <- function(client, limit = 200) {
  .axprism_exchange_get(client, "idx", "/symbols", list(limit = limit))
}

#' IDX company financials
#' @param client An \code{axprism_client}.
#' @param symbol IDX symbol.
#' @param period "annual" or "quarterly".
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_idx_financials(client, "BBCA")
#' }
#' @export
axprism_idx_financials <- function(client, symbol, period = "annual") {
  .axprism_exchange_get(client, "idx", paste0("/financials/", symbol), list(period = period))
}

# ---- Webhooks --------------------------------------------------------------

#' List webhook subscriptions
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_webhooks_list(client)
#' }
#' @export
axprism_webhooks_list <- function(client) .axprism_get(client, "/api/v1/webhooks")

#' Create a webhook subscription
#' @param client An \code{axprism_client}.
#' @param url Callback URL.
#' @param event Event type (see \code{axprism_webhooks_events}).
#' @param ticker_filter Optional ticker filter.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_webhooks_create(client, "https://example.com/hook", "filing.created")
#' }
#' @export
axprism_webhooks_create <- function(client, url, event, ticker_filter = NULL) {
  body <- list(url = url, event = event)
  if (!is.null(ticker_filter)) body$ticker_filter <- ticker_filter
  .axprism_post(client, "/api/v1/webhooks", body = body)
}

#' Delete a webhook subscription
#' @param client An \code{axprism_client}.
#' @param sub_id Subscription id.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_webhooks_delete(client, "sub_123")
#' }
#' @export
axprism_webhooks_delete <- function(client, sub_id) {
  .axprism_delete(client, paste0("/api/v1/webhooks/", sub_id))
}

#' List available webhook event types
#' @param client An \code{axprism_client}.
#' @return Parsed API response as a named list.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_webhooks_events(client)
#' }
#' @export
axprism_webhooks_events <- function(client) .axprism_get(client, "/api/v1/webhooks/events")

# ---- Bulk ------------------------------------------------------------------

#' Bulk financials as a CSV string
#' @param client An \code{axprism_client}.
#' @param ticker Ticker symbol.
#' @param statement "IS", "BS", or "CF".
#' @param period "annual" or "quarterly".
#' @return A character scalar containing CSV text.
#' @examples
#' client <- axprism_client(api_key = "demo-key")
#' \dontrun{
#' axprism_bulk_financials(client, "AAPL")
#' }
#' @export
axprism_bulk_financials <- function(client, ticker, statement = "IS", period = "annual") {
  if (!requireNamespace("httr", quietly = TRUE)) stop("install.packages('httr')")
  resp <- httr::GET(
    paste0(client$base_url, "/api/v1/bulk/financials.csv"),
    query = list(ticker = toupper(ticker), statement = statement, period = period),
    httr::add_headers(`X-API-Key` = client$api_key, `User-Agent` = "axprism-r/0.2.0"),
    httr::timeout(client$timeout_s)
  )
  if (httr::status_code(resp) >= 400) {
    stop(sprintf("AxPrism API error %d", httr::status_code(resp)), call. = FALSE)
  }
  httr::content(resp, as = "text", encoding = "UTF-8")
}

Try the axprism package in your browser

Any scripts or data that you put into this service are public.

axprism documentation built on July 8, 2026, 9:07 a.m.