Developer documentation

AtlasForge Financial API

A complete reference for building on the AtlasForge platform — connectivity, payments, identity, and AI-powered insights.

Introduction

The AtlasForge Financial API is organized around REST. Our API has predictable resource-oriented URLs, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

The base URL for all API requests is:

https://atlasforgefinancial.com/v1

Account linking is powered by Plaid: your frontend exchanges a Link token for a public token, then your backend calls /accounts/link on AtlasForge to exchange it and start syncing.

Authentication

Authenticate by including the API key we email you in theAuthorizationheader of every request. Use your test key (prefixafg_test_) against the Plaid sandbox; the live key (afg_live_) unlocks production once we've completed your onboarding.

Authorization: Bearer afg_test_…

All API requests must be made over HTTPS. Requests without a key return 401; live keys against an account that isn't production-enabled return402. You can probe configuration without auth at GET /api/v1/health.

Errors

AtlasForge Financial uses conventional HTTP response codes to indicate the success or failure of an API request:

  • 200 — OK. Everything worked as expected.
  • 400 — Bad Request. The request was unacceptable, often due to a missing parameter.
  • 401 — Unauthorized. No valid API key provided.
  • 404 — Not Found. The requested resource doesn't exist.
  • 429 — Too Many Requests. Rate limit exceeded.
  • 5xx — Server errors on our end (rare).

Link accounts

POST/v1/accounts/link

Exchange the Plaid public_token for a long-lived access token that AtlasForge stores against(partner_id, user_id, item_id). Returns the initial set of accounts with balances.

Body parameters

FieldTypeDescription
public_tokenstringToken returned by Plaid Link's onSuccess callback.
user_idstringSame end-user id you used for /link/token/create.
institutionobject?Optional { institution_id, name } from Plaid metadata for nicer reporting.
Request
curl -X POST https://atlasforgefinancial.com/v1/accounts/link \
  -H "Authorization: Bearer $ATLAS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "public_token": "public-sandbox-9e2a...",
    "user_id": "usr_8M2nQ",
    "institution": { "institution_id": "ins_109508", "name": "Sandbox Bank" }
  }'

Response · 200 OK

{
  "item_id": "item_a1B2c3D4",
  "institution": { "institution_id": "ins_109508", "name": "Sandbox Bank" },
  "accounts": [
    {
      "account_id": "acc_42",
      "name": "Plaid Checking",
      "mask": "0000",
      "type": "depository",
      "subtype": "checking",
      "current_balance": 110.0,
      "available_balance": 100.0,
      "iso_currency_code": "USD"
    }
  ]
}

Every successful link also writes an account_link event into your partner-portal usage, so dashboards reflect activity automatically.

List accounts

GET/v1/accounts

Returns current balances for every account linked to a given end-user across all of their Plaid items.

Query parameters

FieldTypeDescription
user_idstringRequired. Your end-user id.
Request
curl "https://atlasforgefinancial.com/v1/accounts?user_id=usr_8M2nQ" \
  -H "Authorization: Bearer $ATLAS_KEY"

Response · 200 OK

{
  "accounts": [
    {
      "account_id": "acc_42",
      "name": "Plaid Checking",
      "type": "depository",
      "subtype": "checking",
      "current_balance": 110.0,
      "available_balance": 100.0,
      "iso_currency_code": "USD"
    }
  ]
}

Transactions

GET/v1/transactions

Returns enriched transactions for an end-user using Plaid's /transactions/sync under the hood. We persist the cursor for you — call without one to resume from your last sync.

Query parameters

FieldTypeDescription
user_idstringRequired. Your end-user id.
sinceYYYY-MM-DDOptional. Only return transactions on or after this date.
limitintegerPage size — defaults to 100, max 500.
cursorstringOptional. Plaid sync cursor from a previous response. We store the latest one for you if omitted.
Request
curl "https://atlasforgefinancial.com/v1/transactions?user_id=usr_8M2nQ&limit=2" \
  -H "Authorization: Bearer $ATLAS_KEY"

Response · 200 OK

{
  "transactions": [
    {
      "transaction_id": "txn_7gK1",
      "account_id": "acc_42",
      "merchant_name": "Trader Joe's",
      "amount": 42.18,
      "iso_currency_code": "USD",
      "date": "2026-06-13",
      "pending": false,
      "personal_finance_category_primary": "FOOD_AND_DRINK"
    }
  ],
  "next_cursor": "eyJsYXN0...",
  "has_more": true
}

Each transaction surfaced is also recorded as a transaction event in your partner portal — no separate ingest call needed.

Transfers

POST/v1/transfers

Initiates a money movement between two linked accounts, or to a saved recipient.

Request
curl -X POST https://atlasforgefinancial.com/v1/transfers \
  -H "Authorization: Bearer $ATLAS_KEY" \
  -H "Idempotency-Key: $UUID" \
  -d '{
    "from_account_id": "acc_a1B2c3D4",
    "to_account_id": "acc_recipient_42",
    "amount": 25.00,
    "currency": "USD",
    "memo": "Coffee"
  }'

Response · 200 OK

{
  "id": "tfr_M0p9X",
  "status": "submitted",
  "rail": "rtp",
  "estimated_settlement": "2026-06-14T19:23:11Z"
}

Safe to Spend

POST/v1/calculate/safe-to-spend

Computes a user's daily safe-to-spend allowance from their cash balance, upcoming bills, savings commitments and debt commitments. This is the headline calculation behind the AtlasForge platform.

Request
curl -X POST https://atlasforgefinancial.com/api/v1/calculate/safe-to-spend \
  -H "X-API-Key: $ATLAS_KEY" \
  -d '{
    "end_user_id": "usr_8M2nQ",
    "cash_balance": 4218.50,
    "upcoming_bills": [{ "amount": 1450, "due_in_days": 9 }],
    "savings_commitments": 200,
    "debt_commitments": 0,
    "cash_buffer": 250
  }'

Response · 200 OK

{
  "safe_to_spend_today": 78.45,
  "daily_allowance": 78.45,
  "monthly_safe_to_spend": 2353.50,
  "breakdown": {
    "cash_after_buffer": 3968.50,
    "upcoming_bills_total": 1450,
    "savings_commitments": 200,
    "debt_commitments": 0,
    "discretionary_pool": 2353.50,
    "days_in_period": 30
  },
  "calculation_id": "calc_8M2nQ_2026-06-14",
  "calculated_at": "2026-06-14T18:00:00Z",
  "is_sandbox": false
}

Use /api/v1/ingest instead if you want AtlasForge to cache the result and fire a calculation.updated webhook to your backend. The cached value powers your end-user dashboards and the partner portal.

AI Insights

GET/v1/insights/cashflow

Returns a 30-day cash flow forecast for the authenticated user, including projected balances and identified shortfalls.

Request
curl https://atlasforgefinancial.com/v1/insights/cashflow \
  -H "Authorization: Bearer $ATLAS_KEY"

Response · 200 OK

{
  "horizon_days": 30,
  "projected_min_balance": 412.18,
  "projected_min_date": "2026-06-21",
  "confidence": 0.92,
  "alerts": [
    { "type": "low_balance", "date": "2026-06-21" }
  ]
}

Ingest API (Server-to-server)

The Ingest API lets your own backend stream partner usage events (signups, account links, transactions) into AtlasForge so they appear on the partner portal and admin dashboards in real time.

Endpoints are secret-protected — not partner-accessible. Pass X-Atlas-Ingest-Secret (or Authorization: Bearer …) on every request.

Endpoints

  • POST /api/ingest/event — single event
  • POST /api/ingest/events/batch — up to 500 events
  • GET /api/ingest/ping — connectivity check

Event payload

FieldTypeDescription
partner_idstringRequired. AtlasForge partner id (visible in the admin dashboard URL / partners list).
event_typeenumRequired. One of: user_signup, account_link, transaction.
user_idstringYour end-user id. Used for active-user de-dup.
amount_centsintegerOnly for transactions. USD cents (no decimals).
categorystringOnly for transactions. e.g. groceries, rent, dining, subscription.
institutionstringOnly for account_link. e.g. chase, vanguard.
occurred_atISO 8601Optional. Event timestamp. Defaults to now.

Example — curl

Request
# Single event
curl -X POST https://atlasforgefinancial.com/api/ingest/event \
  -H "X-Atlas-Ingest-Secret: $ATLAS_INGEST_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_id": "bb8eca7c-f0c3-4ee3-9a0a-c97bc66b0f2b",
    "event_type": "transaction",
    "user_id":    "usr_42",
    "amount_cents": 4218,
    "category":   "groceries"
  }'

Response · 200 OK

{
  "accepted": 1,
  "partners": ["bb8eca7c-f0c3-4ee3-9a0a-c97bc66b0f2b"]
}

Example — batch (curl)

curl -X POST https://atlasforgefinancial.com/api/ingest/events/batch \
  -H "X-Atlas-Ingest-Secret: $ATLAS_INGEST_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "partner_id": "p_1", "event_type": "user_signup", "user_id": "usr_1" },
      { "partner_id": "p_1", "event_type": "account_link", "user_id": "usr_1",
        "institution": "chase" },
      { "partner_id": "p_1", "event_type": "transaction", "user_id": "usr_1",
        "amount_cents": 4218, "category": "groceries" }
    ]
  }'

Example — Node.js

import fetch from "node-fetch";

const ATLAS = "https://atlasforgefinancial.com";
const SECRET = process.env.ATLAS_INGEST_SECRET;

export async function atlasIngest(event) {
  const res = await fetch(`${ATLAS}/api/ingest/event`, {
    method:  "POST",
    headers: {
      "X-Atlas-Ingest-Secret": SECRET,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(event),
  });
  if (!res.ok) {
    const err = await res.text();
    throw new Error(`Atlas ingest failed (${res.status}): ${err}`);
  }
  return res.json();
}

// Fire-and-forget after a real transaction in your app:
await atlasIngest({
  partner_id:   "bb8eca7c-...",
  event_type:   "transaction",
  user_id:      "usr_42",
  amount_cents: 4218,
  category:     "groceries",
});

Example — Python

import os
import requests

ATLAS  = "https://atlasforgefinancial.com"
SECRET = os.environ["ATLAS_INGEST_SECRET"]

def atlas_ingest(event: dict) -> dict:
    r = requests.post(
        f"{ATLAS}/api/ingest/event",
        headers={"X-Atlas-Ingest-Secret": SECRET},
        json=event,
        timeout=5,
    )
    r.raise_for_status()
    return r.json()

# Batch up to 500 events in one call:
def atlas_ingest_batch(events: list[dict]) -> dict:
    r = requests.post(
        f"{ATLAS}/api/ingest/events/batch",
        headers={"X-Atlas-Ingest-Secret": SECRET},
        json={"events": events},
        timeout=10,
    )
    r.raise_for_status()
    return r.json()

Responses

  • 200 — Events accepted; returns count and resolved partner ids.
  • 400 — One or more partner_ids don't exist. Response includes a missing array.
  • 401 — Missing or wrong X-Atlas-Ingest-Secret.
  • 503 — Ingest secret not configured on the server.

Tip: deliver events fire-and-forget from your other app so a slow AtlasForge response never blocks your hot path. Batching is significantly faster for high-volume events.

Webhooks

AtlasForge sends webhook events when relevant changes occur. Every delivery is signed with an HMAC-SHA256 signature in theAtlas-Signature header.

POST https://example.com/webhooks
Atlas-Signature: t=1718...,v1=8a3...

{
  "id": "evt_5Aq",
  "type": "transfer.settled",
  "data": { "transfer_id": "tfr_M0p9X" }
}

Rate limits

The default rate limit is 60 requests per second per API key. Enterprise plans receive higher limits and burst capacity. The current usage is returned in the X-RateLimit-* response headers.